Moodle 2.0.3 release
[moodle.git] / filter / tex / filter.php
blobddff02c2f107f95fb4516591585a207d75a35735
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.
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/>.
17 /**
18 * Moodle - Filter for converting TeX expressions to cached gif images
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.
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
35 defined('MOODLE_INTERNAL') || die;
37 /**
38 * Create TeX image link.
40 * @param string $imagefile name of file
41 * @param string $tex TeX notation (html entities already decoded)
42 * @param int $height O means automatic
43 * @param int $width O means automatic
44 * @param string $align
45 * @param string $alt
46 * @return string HTML markup
48 function filter_text_image($imagefile, $tex, $height, $width, $align, $alt) {
49 global $CFG, $OUTPUT;
51 if (!$imagefile) {
52 throw new coding_exception('image file argument empty in filter_text_image()');
55 // Work out any necessary inline style.
56 $rules = array();
57 if ($align !== 'middle') {
58 $rules[] = 'vertical-align:' . $align . ';';
60 if ($height) {
61 $rules[] = 'height:' . $height . 'px;';
63 if ($width) {
64 $rules[] = 'width:' . $width . 'px;';
66 if (!empty($rules)) {
67 $style = ' style="' . implode('', $rules) . '" ';
68 } else {
69 $style = '';
72 // Prepare the title attribute.
73 // Note that we retain the title tag as TeX format rather than using
74 // the alt text, even if supplied. The alt text is intended for blind
75 // users (to provide a text equivalent to the equation) while the title
76 // is there as a convenience for sighted users who want to see the TeX
77 // code.
78 $title = 'title="'.s($tex).'"';
80 if ($alt === '') {
81 $alt = s($tex);
82 } else {
83 $alt = s(html_entity_decode($tex, ENT_QUOTES, 'UTF-8'));
86 // Build the output.
87 $anchorcontents = "<img class=\"texrender\" $title alt=\"$alt\" src=\"";
88 if ($CFG->slasharguments) { // Use this method if possible for better caching
89 $anchorcontents .= "$CFG->wwwroot/filter/tex/pix.php/$imagefile";
90 } else {
91 $anchorcontents .= "$CFG->wwwroot/filter/tex/pix.php?file=$imagefile";
93 $anchorcontents .= "\" $style/>";
95 if (!file_exists("$CFG->dataroot/filter/tex/$imagefile") && has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
96 $link = '/filter/tex/texdebug.php';
97 $action = null;
98 } else {
99 $link = new moodle_url('/filter/tex/displaytex.php', array('texexp'=>$tex));
100 $action = new popup_action('click', $link, 'popup', array('width'=>320,'height'=>240));
102 $output = $OUTPUT->action_link($link, $anchorcontents, $action, array('title'=>'TeX')); //TODO: the popups do not work when text caching is enabled!!
104 return $output;
109 * TeX filtering class.
111 class filter_tex extends moodle_text_filter {
112 function filter($text, array $options = array()) {
114 global $CFG, $DB;
116 /// Do a quick check using stripos to avoid unnecessary work
117 if (!preg_match('/<tex/i',$text) and !strstr($text,'$$') and !strstr($text,'\\[') and !preg_match('/\[tex/i',$text)) { //added one more tag (dlnsk)
118 return $text;
121 # //restrict filtering to forum 130 (Maths Tools on moodle.org)
122 # $scriptname = $_SERVER['SCRIPT_NAME'];
123 # if (!strstr($scriptname,'/forum/')) {
124 # return $text;
126 # if (strstr($scriptname,'post.php')) {
127 # $parent = forum_get_post_full($_GET['reply']);
128 # $discussion = $DB->get_record("forum_discussions", array("id"=>$parent->discussion));
129 # } else if (strstr($scriptname,'discuss.php')) {
130 # $discussion = $DB->get_record("forum_discussions", array("id"=>$_GET['d']));
131 # } else {
132 # return $text;
134 # if ($discussion->forum != 130) {
135 # return $text;
137 $text .= ' ';
138 preg_match_all('/\$(\$\$+?)([^\$])/s',$text,$matches);
139 for ($i=0; $i<count($matches[0]); $i++) {
140 $replacement = str_replace('$','&#x00024;', $matches[1][$i]).$matches[2][$i];
141 $text = str_replace($matches[0][$i], $replacement, $text);
144 // <tex> TeX expression </tex>
145 // or <tex alt="My alternative text to be used instead of the TeX form"> TeX expression </tex>
146 // or $$ TeX expression $$
147 // or \[ TeX expression \] // original tag of MathType and TeXaide (dlnsk)
148 // or [tex] TeX expression [/tex] // somtime it's more comfortable than <tex> (dlnsk)
149 preg_match_all('/<tex(?:\s+alt=["\'](.*?)["\'])?>(.+?)<\/tex>|\$\$(.+?)\$\$|\\\\\[(.+?)\\\\\]|\\[tex\\](.+?)\\[\/tex\\]/is', $text, $matches);
150 for ($i=0; $i<count($matches[0]); $i++) {
151 $texexp = $matches[2][$i] . $matches[3][$i] . $matches[4][$i] . $matches[5][$i];
152 $alt = $matches[1][$i];
153 $texexp = str_replace('<nolink>','',$texexp);
154 $texexp = str_replace('</nolink>','',$texexp);
155 $texexp = str_replace('<span class="nolink">','',$texexp);
156 $texexp = str_replace('</span>','',$texexp);
157 $texexp = preg_replace("/<br[[:space:]]*\/?>/i", '', $texexp); //dlnsk
158 $align = "middle";
159 if (preg_match('/^align=bottom /',$texexp)) {
160 $align = "text-bottom";
161 $texexp = preg_replace('/^align=bottom /','',$texexp);
162 } else if (preg_match('/^align=top /',$texexp)) {
163 $align = "text-top";
164 $texexp = preg_replace('/^align=top /','',$texexp);
167 // decode entities encoded by editor, luckily there is very little chance of double decoding
168 $texexp = html_entity_decode($texexp, ENT_QUOTES, 'UTF-8');
170 if ($texexp === '') {
171 contninue;
174 $md5 = md5($texexp);
175 if (!$DB->record_exists("cache_filters", array("filter"=>"tex", "md5key"=>$md5))) {
176 $texcache = new stdClass();
177 $texcache->filter = 'tex';
178 $texcache->version = 1;
179 $texcache->md5key = $md5;
180 $texcache->rawtext = $texexp;
181 $texcache->timemodified = time();
182 $DB->insert_record("cache_filters", $texcache, false);
184 $filename = $md5 . ".{$CFG->filter_tex_convertformat}";
185 $text = str_replace( $matches[0][$i], filter_text_image($filename, $texexp, 0, 0, $align, $alt), $text);
187 return $text;