Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/ //
2
// Moodle is free software: you can redistribute it and/or modify
3
// it under the terms of the GNU General Public License as published by
4
// the Free Software Foundation, either version 3 of the License, or
5
// (at your option) any later version.
6
//
7
// Moodle is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
// GNU General Public License for more details.
11
//
12
// You should have received a copy of the GNU General Public License
13
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
14
 
15
/**
16
 * Mathjax JS Loader.
17
 *
18
 * @module filter_mathjaxloader/loader
19
 * @copyright 2014 Damyon Wiese  <damyon@moodle.com>
20
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21
 */
22
import {
23
    eventTypes,
24
    notifyFilterContentRenderingComplete,
25
} from 'core_filters/events';
26
 
27
/**
28
 * The users current language - this can't be set until MathJax is loaded - so we need to store it.
29
 * @property {string} lang
30
 * @default ''
31
 * @private
32
 */
33
let lang = '';
34
 
35
/**
36
 * Used to prevent configuring MathJax twice.
37
 * @property {boolean} configured
38
 * @default false
39
 * @private
40
 */
41
let configured = false;
42
 
43
/**
44
 * Called by the filter when it is active on any page.
45
 * This does not load MathJAX yet - it addes the configuration to the head incase it gets loaded later.
46
 * It also subscribes to the filter-content-updated event so MathJax can respond to content loaded by Ajax.
47
 *
48
 * @param {Object} params List of configuration params containing mathjaxconfig (text) and lang
49
 */
50
export const configure = (params) => {
51
    // Add a js configuration object to the head.
52
    // See "https://docs.mathjax.org/en/v2.7-latest/advanced/dynamic.html"
53
    const script = document.createElement("script");
54
    script.type = "text/x-mathjax-config";
55
    script[(window.opera ? "innerHTML" : "text")] = params.mathjaxconfig;
56
    document.getElementsByTagName("head")[0].appendChild(script);
57
 
58
    // Save the lang config until MathJax is actually loaded.
59
    lang = params.lang;
60
 
61
    // Listen for events triggered when new text is added to a page that needs
62
    // processing by a filter.
63
    document.addEventListener(eventTypes.filterContentUpdated, contentUpdated);
64
};
65
 
66
/**
67
 * Set the correct language for the MathJax menus. Only do this once.
68
 *
69
 * @private
70
 */
71
const setLocale = () => {
72
    if (!configured) {
73
        if (typeof window.MathJax !== "undefined") {
74
            window.MathJax.Hub.Queue(function() {
75
                window.MathJax.Localization.setLocale(lang);
76
            });
77
            window.MathJax.Hub.Configured();
78
            configured = true;
79
        }
80
    }
81
};
82
 
83
/**
84
 * Add the node to the typeset queue.
85
 *
86
 * @param {HTMLElement} node The Node to be processed by MathJax
87
 * @private
88
 */
89
const typesetNode = (node) => {
90
    if (!(node instanceof HTMLElement)) {
91
        // We may have been passed a #text node.
92
        // These cannot be formatted.
93
        return;
94
    }
95
 
96
    // MathJax 2.X does not notify when complete. The best we can do, according to their docs, is to queue a callback.
97
    // See https://docs.mathjax.org/en/v2.7-latest/advanced/typeset.html
98
    // Note that the MathJax.Hub.Queue() method will return immediately, regardless of whether the typesetting has taken place
99
    // or not, so you can not assume that the mathematics is visible after you make this call.
100
    // That means that things like the size of the container for the mathematics may not yet reflect the size of the
101
    // typeset mathematics. If you need to perform actions that depend on the mathematics being typeset, you should push those
102
    // actions onto the MathJax.Hub.queue as well.
103
    window.MathJax.Hub.Queue(["Typeset", window.MathJax.Hub, node]);
104
    window.MathJax.Hub.Queue([(node) => {
105
        // The notifyFilterContentRenderingComplete event takes an Array of NodeElements or a NodeList.
106
        // We cannot create a NodeList so we use an HTMLElement[].
107
        notifyFilterContentRenderingComplete([node]);
108
    }, node]);
109
};
110
 
111
/**
112
 * Called by the filter when an equation is found while rendering the page.
113
 */
114
export const typeset = () => {
115
    if (!configured) {
116
        setLocale();
117
        const elements = document.getElementsByClassName('filter_mathjaxloader_equation');
118
        for (const element of elements) {
119
            if (typeof window.MathJax !== "undefined") {
120
                typesetNode(element);
121
            }
122
        }
123
    }
124
};
125
 
126
/**
127
 * Handle content updated events - typeset the new content.
128
 *
129
 * @param {CustomEvent} event - Custom event with "nodes" indicating the root of the updated nodes.
130
 */
131
export const contentUpdated = (event) => {
132
    if (typeof window.MathJax === "undefined") {
133
        return;
134
    }
135
 
136
    let listOfElementContainMathJax = [];
137
    let hasMathJax = false;
138
    // The list of HTMLElements in an Array.
139
    event.detail.nodes.forEach((node) => {
140
        if (!(node instanceof HTMLElement)) {
141
            // We may have been passed a #text node.
142
            return;
143
        }
144
        const mathjaxElements = node.querySelectorAll('.filter_mathjaxloader_equation');
145
        if (mathjaxElements.length > 0) {
146
            hasMathJax = true;
147
        }
148
        listOfElementContainMathJax.push(mathjaxElements);
149
    });
150
    if (!hasMathJax) {
151
        return;
152
    }
153
    const processDelay = window.MathJax.Hub.processSectionDelay;
154
    // Set the process section delay to 0 when updating the formula.
155
    window.MathJax.Hub.processSectionDelay = 0;
156
    // When content is updated never position to hash, it may cause unexpected document scrolling.
157
    window.MathJax.Hub.Config({positionToHash: false});
158
    setLocale();
159
    listOfElementContainMathJax.forEach((mathjaxElements) => {
160
        mathjaxElements.forEach((node) => typesetNode(node));
161
    });
162
    window.MathJax.Hub.processSectionDelay = processDelay;
163
};