Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
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/>.
16
 
17
/**
18
 * Moodle - Filter for converting TeX expressions to cached gif images
19
 *
20
 * This Moodle text filter converts TeX expressions delimited
21
 * by either $$...$$ or by <tex...>...</tex> tags to gif images using
22
 * mimetex.cgi obtained from http: *www.forkosh.com/mimetex.html authored by
23
 * John Forkosh john@forkosh.com.  Several binaries of this areincluded with
24
 * this distribution.
25
 * Note that there may be patent restrictions on the production of gif images
26
 * in Canada and some parts of Western Europe and Japan until July 2004.
27
 *
28
 * @package    filter
29
 * @subpackage tex
30
 * @copyright  2004 Zbigniew Fiedorowicz fiedorow@math.ohio-state.edu
31
 *             Originally based on code provided by Bruno Vernier bruno@vsbeducation.ca
32
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 */
34
 
35
defined('MOODLE_INTERNAL') || die;
36
 
37
require_once($CFG->libdir . '/classes/useragent.php');
38
 
39
/**
40
 * Create TeX image link.
41
 *
42
 * @param string $imagefile name of file
43
 * @param string $tex TeX notation (html entities already decoded)
44
 * @param int $height O means automatic
45
 * @param int $width O means automatic
46
 * @param string $align
47
 * @param string $alt
48
 * @return string HTML markup
49
 */
50
function filter_text_image($imagefile, $tex, $height, $width, $align, $alt) {
51
    global $CFG, $OUTPUT;
52
 
53
    if (!$imagefile) {
54
        throw new coding_exception('image file argument empty in filter_text_image()');
55
    }
56
 
57
    // Work out any necessary inline style.
58
    $rules = array();
59
    if ($align !== 'middle') {
60
        $rules[] = 'vertical-align:' . $align . ';';
61
    }
62
    if ($height) {
63
        $rules[] = 'height:' . $height . 'px;';
64
    }
65
    if ($width) {
66
        $rules[] = 'width:' . $width . 'px;';
67
    }
68
    if (!empty($rules)) {
69
        $style = ' style="' . implode('', $rules) . '" ';
70
    } else {
71
        $style = '';
72
    }
73
 
74
    // Prepare the title attribute.
75
    // Note that we retain the title tag as TeX format rather than using
76
    // the alt text, even if supplied. The alt text is intended for blind
77
    // users (to provide a text equivalent to the equation) while the title
78
    // is there as a convenience for sighted users who want to see the TeX
79
    // code.
80
    $title = 'title="'.s($tex).'"';
81
 
82
    if ($alt === '') {
83
        $alt = s($tex);
84
    } else {
85
        $alt = s(html_entity_decode($tex, ENT_QUOTES, 'UTF-8'));
86
    }
87
 
88
    // Build the output.
89
    $anchorcontents = "<img class=\"texrender\" $title alt=\"$alt\" src=\"";
90
    if ($CFG->slasharguments) {        // Use this method if possible for better caching
91
        $anchorcontents .= "$CFG->wwwroot/filter/tex/pix.php/$imagefile";
92
    } else {
93
        $anchorcontents .= "$CFG->wwwroot/filter/tex/pix.php?file=$imagefile";
94
    }
95
    $anchorcontents .= "\" $style/>";
96
 
97
    if (!file_exists("$CFG->dataroot/filter/tex/$imagefile") && has_capability('moodle/site:config', context_system::instance())) {
98
        $link = '/filter/tex/texdebug.php';
99
        $action = null;
100
    } else {
101
        $link = new moodle_url('/filter/tex/displaytex.php', array('texexp'=>$tex));
102
        $action = new popup_action('click', $link, 'popup', array('width'=>320,'height'=>240));
103
    }
104
    $output = $OUTPUT->action_link($link, $anchorcontents, $action, array('title'=>'TeX')); //TODO: the popups do not work when text caching is enabled!!
105
    $output = "<span class=\"MathJax_Preview\">$output</span><script type=\"math/tex\">$tex</script>";
106
 
107
    return $output;
108
}
109
 
110
 
111
/**
112
 * TeX filtering class.
113
 */
114
class filter_tex extends moodle_text_filter {
115
    function filter($text, array $options = array()) {
116
 
117
        global $CFG, $DB;
118
 
119
        /// Do a quick check using stripos to avoid unnecessary work
120
        if ((!preg_match('/<tex/i', $text)) &&
121
                (strpos($text,'$$') === false) &&
122
                (strpos($text,'\\[') === false) &&
123
                (strpos($text, '\\(') === false) &&
124
                (!preg_match('/\[tex/i',$text))) {
125
            return $text;
126
        }
127
 
128
#    //restrict filtering to forum 130 (Maths Tools on moodle.org)
129
#    $scriptname = $_SERVER['SCRIPT_NAME'];
130
#    if (!strstr($scriptname,'/forum/')) {
131
#        return $text;
132
#    }
133
#    if (strstr($scriptname,'post.php')) {
134
#        $parent = forum_get_post_full($_GET['reply']);
135
#        $discussion = $DB->get_record("forum_discussions", array("id"=>$parent->discussion));
136
#    } else if (strstr($scriptname,'discuss.php')) {
137
#        $discussion = $DB->get_record("forum_discussions", array("id"=>$_GET['d']));
138
#    } else {
139
#        return $text;
140
#    }
141
#    if ($discussion->forum != 130) {
142
#        return $text;
143
#    }
144
        $text .= ' ';
145
        preg_match_all('/\$(\$\$+?)([^\$])/s',$text,$matches);
146
        for ($i=0; $i<count($matches[0]); $i++) {
147
            $replacement = str_replace('$','&#x00024;', $matches[1][$i]).$matches[2][$i];
148
            $text = str_replace($matches[0][$i], $replacement, $text);
149
        }
150
 
151
        // <tex> TeX expression </tex>
152
        // or <tex alt="My alternative text to be used instead of the TeX form"> TeX expression </tex>
153
        // or $$ TeX expression $$
154
        // or \[ TeX expression \]          // original tag of MathType and TeXaide (dlnsk)
155
        // or [tex] TeX expression [/tex]   // somtime it's more comfortable than <tex> (dlnsk)
156
        $rules = array(
157
            '<tex(?:\s+alt=["\'](.*?)["\'])?>(.+?)<\/tex>',
158
            '\$\$(.+?)\$\$',
159
            '\\\\\[(.+?)\\\\\]',
160
            '\\\\\((.+?)\\\\\)',
161
            '\\[tex\\](.+?)\\[\/tex\\]'
162
        );
163
        $megarule = '/' . implode('|', $rules) . '/is';
164
        preg_match_all($megarule, $text, $matches);
165
        for ($i=0; $i<count($matches[0]); $i++) {
166
            $texexp = '';
167
            for ($j = 0; $j < count($rules); $j++) {
168
                $texexp .= $matches[$j + 2][$i];
169
            }
170
            $alt = $matches[1][$i];
171
            $texexp = str_replace('<nolink>','',$texexp);
172
            $texexp = str_replace('</nolink>','',$texexp);
173
            $texexp = str_replace('<span class="nolink">','',$texexp);
174
            $texexp = str_replace('</span>','',$texexp);
175
            $texexp = preg_replace("/<br[[:space:]]*\/?>/i", '', $texexp);  //dlnsk
176
            $align = "middle";
177
            if (preg_match('/^align=bottom /',$texexp)) {
178
              $align = "text-bottom";
179
              $texexp = preg_replace('/^align=bottom /','',$texexp);
180
            } else if (preg_match('/^align=top /',$texexp)) {
181
              $align = "text-top";
182
              $texexp = preg_replace('/^align=top /','',$texexp);
183
            }
184
 
185
            // decode entities encoded by editor, luckily there is very little chance of double decoding
186
            $texexp = html_entity_decode($texexp, ENT_QUOTES, 'UTF-8');
187
 
188
            if ($texexp === '') {
189
                continue;
190
            }
191
 
192
            // Sanitize the decoded string, because filter_text_image() injects the final string between script tags.
193
            $texexp = clean_param($texexp, PARAM_TEXT);
194
 
195
            $md5 = md5($texexp);
196
            if (!$DB->record_exists("cache_filters", array("filter"=>"tex", "md5key"=>$md5))) {
197
                $texcache = new stdClass();
198
                $texcache->filter = 'tex';
199
                $texcache->version = 1;
200
                $texcache->md5key = $md5;
201
                $texcache->rawtext = $texexp;
202
                $texcache->timemodified = time();
203
                $DB->insert_record("cache_filters", $texcache, false);
204
            }
205
            $convertformat = get_config('filter_tex', 'convertformat');
206
            if ($convertformat == 'svg' && !core_useragent::supports_svg()) {
207
                $convertformat = 'png';
208
            }
209
            $filename = $md5.".{$convertformat}";
210
            $text = str_replace( $matches[0][$i], filter_text_image($filename, $texexp, 0, 0, $align, $alt), $text);
211
        }
212
        return $text;
213
    }
214
}
215
 
216