Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 13... Línea 13...
13
//
13
//
14
// You should have received a copy of the GNU General Public License
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
Línea 16... Línea 16...
16
 
16
 
17
/**
17
/**
18
 * This filter provides automatic support for MathJax
18
 * File only retained to prevent fatal errors in code that tries to require/include this.
-
 
19
 *
-
 
20
 * @todo MDL-82708 delete this file as part of Moodle 6.0 development.
19
 *
21
 * @deprecated This file is no longer required in Moodle 4.5+.
20
 * @package    filter_mathjaxloader
22
 * @package filter_mathjaxloader
21
 * @copyright  2013 Damyon Wiese (damyon@moodle.com)
23
 * @copyright Damyon Wiese <damyon@moodle.com>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
-
 
24
 
25
 */
Línea 25... Línea -...
25
defined('MOODLE_INTERNAL') || die();
-
 
26
 
-
 
27
/**
-
 
28
 * Mathjax filtering
-
 
29
 */
-
 
30
class filter_mathjaxloader extends moodle_text_filter {
-
 
31
 
-
 
32
    /*
-
 
33
     * Perform a mapping of the moodle language code to the equivalent for MathJax.
-
 
34
     *
-
 
35
     * @param string $moodlelangcode - The moodle language code - e.g. en_pirate
-
 
36
     * @return string The MathJax language code.
-
 
37
     */
-
 
38
    public function map_language_code($moodlelangcode) {
-
 
39
 
-
 
40
        // List of language codes found in the MathJax/localization/ directory.
-
 
41
        $mathjaxlangcodes = [
-
 
42
            'ar', 'ast', 'bcc', 'bg', 'br', 'ca', 'cdo', 'ce', 'cs', 'cy', 'da', 'de', 'diq', 'en', 'eo', 'es', 'fa',
-
 
43
            'fi', 'fr', 'gl', 'he', 'ia', 'it', 'ja', 'kn', 'ko', 'lb', 'lki', 'lt', 'mk', 'nl', 'oc', 'pl', 'pt',
-
 
44
            'pt-br', 'qqq', 'ru', 'scn', 'sco', 'sk', 'sl', 'sv', 'th', 'tr', 'uk', 'vi', 'zh-hans', 'zh-hant'
-
 
45
        ];
-
 
46
 
-
 
47
        // List of explicit mappings and known exceptions (moodle => mathjax).
-
 
48
        $explicit = [
-
 
49
            'cz' => 'cs',
-
 
50
            'pt_br' => 'pt-br',
-
 
51
            'zh_tw' => 'zh-hant',
-
 
52
            'zh_cn' => 'zh-hans',
-
 
53
        ];
-
 
54
 
-
 
55
        // If defined, explicit mapping takes the highest precedence.
-
 
56
        if (isset($explicit[$moodlelangcode])) {
-
 
57
            return $explicit[$moodlelangcode];
-
 
58
        }
-
 
59
 
-
 
60
        // If there is exact match, it will be probably right.
-
 
61
        if (in_array($moodlelangcode, $mathjaxlangcodes)) {
-
 
62
            return $moodlelangcode;
-
 
63
        }
-
 
64
 
-
 
65
        // Finally try to find the best matching mathjax pack.
-
 
66
        $parts = explode('_', $moodlelangcode, 2);
-
 
67
        if (in_array($parts[0], $mathjaxlangcodes)) {
-
 
68
            return $parts[0];
-
 
69
        }
-
 
70
 
-
 
71
        // No more guessing, use English.
-
 
72
        return 'en';
-
 
73
    }
-
 
74
 
-
 
75
    /*
-
 
76
     * Add the javascript to enable mathjax processing on this page.
-
 
77
     *
-
 
78
     * @param moodle_page $page The current page.
-
 
79
     * @param context $context The current context.
-
 
80
     */
-
 
81
    public function setup($page, $context) {
-
 
82
 
-
 
83
        if ($page->requires->should_create_one_time_item_now('filter_mathjaxloader-scripts')) {
-
 
84
            $url = get_config('filter_mathjaxloader', 'httpsurl');
-
 
85
            $lang = $this->map_language_code(current_language());
-
 
86
            $url = new moodle_url($url, array('delayStartupUntil' => 'configured'));
-
 
87
 
-
 
88
            $page->requires->js($url);
-
 
89
 
-
 
90
            $config = get_config('filter_mathjaxloader', 'mathjaxconfig');
-
 
91
            $wwwroot = new moodle_url('/');
-
 
92
 
-
 
93
            $config = str_replace('{wwwroot}', $wwwroot->out(true), $config);
-
 
94
 
-
 
95
            $params = array('mathjaxconfig' => $config, 'lang' => $lang);
-
 
96
 
-
 
97
            $page->requires->js_call_amd('filter_mathjaxloader/loader', 'configure', [$params]);
-
 
98
        }
-
 
99
    }
-
 
100
 
-
 
101
    /*
-
 
102
     * This function wraps the filtered text in a span, that mathjaxloader is configured to process.
-
 
103
     *
-
 
104
     * @param string $text The text to filter.
-
 
105
     * @param array $options The filter options.
-
 
106
     */
-
 
107
    public function filter($text, array $options = array()) {
-
 
108
        global $PAGE;
-
 
109
 
-
 
110
        $legacy = get_config('filter_mathjaxloader', 'texfiltercompatibility');
-
 
111
        $extradelimiters = explode(',', get_config('filter_mathjaxloader', 'additionaldelimiters'));
26
defined('MOODLE_INTERNAL') || die();
112
        if ($legacy) {
-
 
113
            // This replaces any of the tex filter maths delimiters with the default for inline maths in MathJAX "\( blah \)".
-
 
114
            // E.g. "<tex.*> blah </tex>".
-
 
115
            $text = preg_replace('|<(/?) *tex( [^>]*)?>|u', '[\1tex]', $text);
-
 
116
            // E.g. "[tex.*] blah [/tex]".
-
 
117
            $text = str_replace('[tex]', '\\(', $text);
-
 
118
            $text = str_replace('[/tex]', '\\)', $text);
-
 
119
            // E.g. "$$ blah $$".
-
 
120
            $text = preg_replace('|\$\$([\S\s]*?)\$\$|u', '\\(\1\\)', $text);
-
 
121
            // E.g. "\[ blah \]".
-
 
122
            $text = str_replace('\\[', '\\(', $text);
-
 
123
            $text = str_replace('\\]', '\\)', $text);
-
 
124
        }
-
 
125
 
-
 
126
        $hasextra = false;
-
 
127
        foreach ($extradelimiters as $extra) {
-
 
128
            if ($extra && strpos($text, $extra) !== false) {
-
 
129
                $hasextra = true;
-
 
130
                break;
-
 
131
            }
-
 
132
        }
-
 
133
 
-
 
134
        $hasdisplayorinline = false;
-
 
135
        if ($hasextra) {
-
 
136
            // Convert the HTML tag wrapper inside the equation to entities.
-
 
137
            $text = $this->escape_html_tag_wrapper($text);
-
 
138
            // If custom dilimeters are used, wrap whole text to prevent autolinking.
-
 
139
            $text = '<span class="nolink">' . $text . '</span>';
-
 
140
        } else if (preg_match('/\\\\[[(]/', $text) || preg_match('/\$\$/', $text)) {
-
 
141
            // Convert the HTML tag wrapper inside the equation to entities.
-
 
142
            $text = $this->escape_html_tag_wrapper($text);
-
 
143
            // Only parse the text if there are mathjax symbols in it. The recognized
-
 
144
            // math environments are \[ \] and $$ $$ for display mathematics and \( \)
-
 
145
            // for inline mathematics.
-
 
146
            // Note: 2 separate regexes seems to perform better here than using a single
-
 
147
            // regex with groupings.
-
 
148
 
-
 
149
            // Wrap display and inline math environments in nolink spans.
-
 
150
            // Do not wrap nested environments, i.e., if inline math is nested
-
 
151
            // inside display math, only the outer display math is wrapped in
-
 
152
            // a span. The span HTML inside a LaTex math environment would break
-
 
153
            // MathJax. See MDL-61981.
-
 
154
            list($text, $hasdisplayorinline) = $this->wrap_math_in_nolink($text);
-
 
155
        }
-
 
156
 
-
 
157
        if ($hasdisplayorinline || $hasextra) {
-
 
158
            $PAGE->requires->js_call_amd('filter_mathjaxloader/loader', 'typeset');
-
 
159
            return '<span class="filter_mathjaxloader_equation">' . $text . '</span>';
-
 
160
        }
-
 
161
        return $text;
-
 
162
    }
-
 
163
 
-
 
164
    /**
-
 
165
     * Find math environments in the $text and wrap them in no link spans
-
 
166
     * (<span class="nolink"></span>). If math environments are nested, only
-
 
167
     * the outer environment is wrapped in the span.
-
 
168
     *
-
 
169
     * The recognized math environments are \[ \] and $$ $$ for display
-
 
170
     * mathematics and \( \) for inline mathematics.
-
 
171
     *
-
 
172
     * @param string $text The text to filter.
-
 
173
     * @return array An array containing the potentially modified text and
-
 
174
     * a boolean that is true if any changes were made to the text.
-
 
175
     */
-
 
176
    protected function wrap_math_in_nolink($text) {
-
 
177
        $i = 1;
-
 
178
        $len = strlen($text);
-
 
179
        $displaystart = -1;
-
 
180
        $displaybracket = false;
-
 
181
        $displaydollar = false;
-
 
182
        $inlinestart = -1;
-
 
183
        $changesdone = false;
-
 
184
        // Loop over the $text once.
-
 
185
        while ($i < $len) {
-
 
186
            if ($displaystart === -1) {
-
 
187
                // No display math has started yet.
-
 
188
                if ($text[$i - 1] === '\\' && $text[$i] === '[') {
-
 
189
                    // Display mode \[ begins.
-
 
190
                    $displaystart = $i - 1;
-
 
191
                    $displaybracket = true;
-
 
192
                } else if ($text[$i - 1] === '$' && $text[$i] === '$') {
-
 
193
                    // Display mode $$ begins.
-
 
194
                    $displaystart = $i - 1;
-
 
195
                    $displaydollar = true;
-
 
196
                } else if ($text[$i - 1] === '\\' && $text[$i] === '(') {
-
 
197
                    // Inline math \( begins, not nested inside display math.
-
 
198
                    $inlinestart = $i - 1;
-
 
199
                } else if ($text[$i - 1] === '\\' && $text[$i] === ')' && $inlinestart > -1) {
-
 
200
                    // Inline math ends, not nested inside display math.
-
 
201
                    // Wrap the span around it.
-
 
202
                    $text = $this->insert_span($text, $inlinestart, $i);
-
 
203
 
-
 
204
                    $inlinestart = -1; // Reset.
-
 
205
                    $i += 28; // The $text length changed due to the <span>.
-
 
206
                    $len += 28;
-
 
207
                    $changesdone = true;
-
 
208
                }
-
 
209
            } else {
-
 
210
                // Display math open.
-
 
211
                if (($text[$i - 1] === '\\' && $text[$i] === ']' && $displaybracket) ||
-
 
212
                        ($text[$i - 1] === '$' && $text[$i] === '$' && $displaydollar)) {
-
 
213
                    // Display math ends, wrap the span around it.
-
 
214
                    $text = $this->insert_span($text, $displaystart, $i);
-
 
215
 
-
 
216
                    $displaystart = -1; // Reset.
-
 
217
                    $displaybracket = false;
-
 
218
                    $displaydollar = false;
-
 
219
                    $i += 28; // The $text length changed due to the <span>.
-
 
220
                    $len += 28;
-
 
221
                    $changesdone = true;
-
 
222
                }
-
 
223
            }
-
 
224
 
-
 
225
            ++$i;
-
 
226
        }
-
 
227
        return array($text, $changesdone);
-
 
228
    }
-
 
229
 
-
 
230
    /**
-
 
231
     * Wrap a portion of the $text inside a no link span
-
 
232
     * (<span class="nolink"></span>). The whole text is then returned.
-
 
233
     *
-
 
234
     * @param string $text The text to modify.
-
 
235
     * @param int $start The start index of the substring in $text that should
-
 
236
     * be wrapped in the span.
-
 
237
     * @param int $end The end index of the substring in $text that should be
-
 
238
     * wrapped in the span.
-
 
239
     * @return string The whole $text with the span inserted around
-
 
240
     * the defined substring.
-
 
241
     */
-
 
242
    protected function insert_span($text, $start, $end) {
-
 
243
        return substr_replace($text,
-
 
244
                '<span class="nolink">'. substr($text, $start, $end - $start + 1) .'</span>',
-
 
245
                $start,
-
 
246
                $end - $start + 1);
-
 
247
    }
-
 
248
 
-
 
249
    /**
-
 
250
     * Escapes HTML tags within a string.
-
 
251
     *
-
 
252
     * This function replaces HTML tags enclosed in curly brackets with their respective HTML entities.
-
 
253
     *
-
 
254
     * @param string $text The input string containing HTML tags.
-
 
255
     * @return string Returns the input string with HTML tags escaped.
-
 
256
     */
-
 
257
    private function escape_html_tag_wrapper(string $text): string {
-
 
258
        return preg_replace_callback('/\{([^}]+)\}/', function(array $matches): string {
-
 
259
            $search = ['<', '>'];
-
 
260
            $replace = ['&lt;', '&gt;'];
-
 
261
            return str_replace($search, $replace, $matches[0]);
-
 
262
        }, $text);
-