Extension:MathJax

What is this?
Extension:MathJax enables MathJax (http://www.mathjax.org/), a Javascript library, for typesetting TeX and LaTeX formulae in MediaWiki inside math environments. The following math environments are defined for inline style math: And the following math environments are defined for display style math: MathJax produces nice and scalable mathematics, see their website (http://www.mathjax.org/) for a demonstration. This extension also enables the usage of \label{} and  \eqref{}  tags with automatic formula numbering. If needed you can still hand label by using \tag{}.
 *  $...$ ,
 * \(...\) and
 * &lt;math&gt;...&lt;/math&gt;.
 *  $$...$$ ,
 * \[...\] and
 * :&lt;math&gt;...&lt;/math&gt;</tt>.

An alternative for the default texvc</tt> math handling
If you but still want to render math, than this extension could be a solution for you.
 * don't want to use texvc</tt> because you
 * want scalable nicer mathematics,
 * transparent backgrounds, or
 * find having LaTeX on your server too inconvenient; or
 * can't use texvc</tt>
 * as you have trouble configuring and compiling, or
 * can't easily write png files (because of safe_mode</tt>) or
 * for some other reason,

Install MathJax on your webserver
MathJax is just a Javascript library, so there is no compilation involved, just putting the MathJax files (Javascript files and fonts) on your webserver.

Install the MathJax Javascript library by following their installation instructions at http://www.mathjax.org/resources/docs/?installation.html. An easy installation would use their zip package as follows:
 * 1) Download the latest zip distribution from http://sourceforge.net/projects/mathjax/files/.
 * 2) Unzip the package (you get a directory mathjax</tt>) and place it in your root directory of your webserver (e.g., /home/username/public_html/</tt>).
 * 3) Test if it works by surfing to, e.g.,  http://www.yourwebserver.dom/~username/mathjax/test/ </tt> and  http://www.yourwebserver.dom/~username/mathjax/test/sample.html </tt>. You should see nicely rendered math. Try right-clicking on the math to get the MathJax contextual menu (e.g., scale all maths on a page or enabling zooming on mouse hovering).

Install Extension:MathJax on your webserver
To install Extension:MathJax you need to put the MathJax.php</tt> code on your server as well as a MathJax Javascript configuration file: mwMathJaxConfig.js</tt>. To enable the extension you then need to modify your LocalSettings.php</tt> MediaWiki configuration file.


 * 1) Installing MathJax.php: cut and paste the code found below and place it in  .  Note: $IP stands for the root directory of your MediaWiki installation, the same directory that holds LocalSettings.php.
 * 2) Install the MathJax Javascript configuration hub file: cut and paste the code found below and place it in $IP/extensions/MathJax/mwMathJaxConfig.js</tt>. (If you like having a shared installation for multiple wiki's then place the config file inside the mathjax</tt> directory such that it is easy to share.)

Configuration
To install this extension, add the following to LocalSettings.php:

The  array has keys of URLs to Javascript files and keys of local file paths to configuration hub Javascript files. Thus: This will be included in the rendered page (except when the page is in namespace Special</tt>) as

It doesn't matter if you have  set to   or  ; Extension:MathJax will take over rendering of the standard &lt;math&gt;</tt> math tags.

Code
* The keys are URL's, while the values are file paths. So for the example above * the MathJax Javascript files are accessible on the webserver as * http://WEBSERVER/mathjax/ and the configuration hub file is accessible as a  * file from within php using the path "../mathjax/myMathJaxConfig.js". * The URL for MathJax.js should best be a relative URL, see the installation * manual of MathJax "Notes about shared installations", to avoid problems with * counter measures for cross side scripting attacks (aka XSS attacks). * * @note We don't include the Javascript on Special pages, so there is no math * rendering there. E.g., in Special:AllMessages there are occurances of * $1$2 which we don't want to typeset, and which don't pass through the * parser. * * @param out  The OutputPage object being rendered (in nearly finished form). * * @returns    true on success; false on failure (never triggered). * * @hook       BeforePageDisplay * @globals    $wgMathJaxJS (associative array), $wgTitle, $wgJsMimeType */ $wgHooks['BeforePageDisplay'][] = 'MathJax_Javascript_addJS'; $wgMathJaxJS = array; function MathJax_Javascript_addJS($out) { global $wgTitle, $wgJsMimeType, $wgMathJaxJS; if($wgTitle->getNamespace == NS_SPECIAL) { $out->addScript("<script type='$wgJsMimeType'>/* No MathJax: Special page */ \n"); return true; } // In principle we can include any Javascript file from LocalSettings.php by   // abusing this script for other purposes. That is safe, as we have to assume // LocalSettings.php is controlled by the sysadmin. foreach($wgMathJaxJS as $src => $inline) { $out->addScript("<script type='$wgJsMimeType' src='$src'>" . file_get_contents($inline) . " \n"); } return true; }

/** * MathJax_change_edit_toolbar(&$toolbar) * * Remove the standard math button from the toolbar and add two new ones for * inline style and for display style mathematics. * * Through the globals $wgMathJaxInlineButton, $wgMathJaxDisplayButton one can * sepcify a file path to an image file to use for the button. If empty, then * the standard math button is used for both buttons. * * @note This code wil breas whenever the toolbar code changes its output * format. We can't help that, that's because there is no nice interface to do * this. * @note On Wikipedia there is already a different toolbar in use, but without * math button, so in that case, it doesn't matter much. * * @param $toolbar   This is the "HTML" rendered version of the edit toolbar, *                   using Javascript calls "addButton" to add buttons. * * @returns    true on success; false on failure (never triggered). * * @hook       EditPageBeforeEditToolbar * @globals    $wgMathJaxInlineButton, $wgMathJaxDisplayButton, $wgStylePath */ $wgHooks['EditPageBeforeEditToolbar'][] = 'MathJax_change_edit_toolbar'; function MathJax_change_edit_toolbar(&$toolbar) { global $wgMathJaxInlineButton, $wgMathJaxDisplayButton, $wgStylePath; $i = strpos($toolbar, 'mw-editbutton-math'); if($i === false) return true; // don't do anything, we can't find the math button... $e = strpos ($toolbar, ';', $i); $b = strrpos(substr($toolbar, 0, $e), 'addButton'); $l = $e - $b + 2; if(empty($wgMathJaxInlineButton)) $wgMathJaxInlineButton = "$wgStylePath/common/images/button_math.png"; if(empty($wgMathJaxDisplayButton)) $wgMathJaxDisplayButton = "$wgStylePath/common/images/button_math.png"; $inline_math = 'addButton("' . $wgMathJaxInlineButton . '"'   . ',"Inline mathematical formula (LaTeX)","$","$","Insert formula here","mw-editbutton-math");'. "\n"; $display_math = 'addButton("'. $wgMathJaxDisplayButton . '"'   . ',"Display-style mathematical formula (LaTeX)","$$","$$",'    . '"Insert formula here, optionally \\\\tag{manual-number}","mw-editbutton-math2");'. "\n"; $toolbar = substr_replace($toolbar, $inline_math . $display_math, $b, $l); return true; }

/** * MathJax_parser_stage1(&$parser, &$text, &$strip_state) * * Preprocess the raw wiki text (we have hooked this early on in the processing * chain) for mathematics. This means we have to: * *  1. Prevent math environments inside " ... ", *     " ... " and " " from being typeset on the final *     page. The pre and code tags are special: we can not just block them in *      the MathJax configuration hub as WM may add them as markup to other *     elements. *     These tags (nowiki, pre and code) will not be handled correctly for *     template expansions, as their is no ParserBeforeStrip stage for *     templates. *     For template arguments using these tags there is no problem at all. *  2. Change the standard "..." tag into MathJax delimiters for *     inline style math. *  3. Change the ":..." combination (as used on Wikipedia for *      display style math)  into MathJax delimiters for display style math. *  4. Protect our math environments from further processing by putting in  *      place holders; we use the $strip_state->nowiki ReplacementArray for *     this. These place holders will be automatically unstripped by *      unstripNoWiki in Parser::Parse just before the ParserBeforeTidy hook. * * There is a stage 2 parser which will replace the actual math by place holders * and does the \label{} and \eqref{} handling. This stage 2 parser will also * see the expanded templates; and therefore, there as well, we will replace * "..." and ":..." by MathJax delimiters. * * @note Partly based on code from Extension:JsMath by Tommy Ekola. Maybe the * WikiMedia developers should document their code base a little bit more... * Luckily examples (like Extension:JsMath) and source code reading helps. * * @param &$parser       The Parser object doing the job. * @param &$text         The raw wiki text which is thrown in. * @param &$strip_state  A StripState object which holds two *                       ReplacementArray's which are key value lists of place *                       holders (substituted into the $text) and their value. * * @returns              true on success; false on failure (never triggered). * * @hook       ParserBeforeStrip * @globals * @seealso    MathJax_parser_stage2 */ $wgHooks['ParserBeforeStrip'][] = 'MathJax_parser_stage1'; function MathJax_parser_stage1(&$parser, &$text, &$strip_state) { $uniq_prefix = $parser->mUniqPrefix; $tempstrip = new ReplacementArray; $elements = array('nowiki', 'pre', 'code'); // pre and code are handled differntly in wiki than in html $matches = array; $nowiki_markers_replace = array; $precode_markers_replace = array; $text = Parser::extractTagsAndParams($elements, $text, $matches, $uniq_prefix); foreach($matches as $marker => $data) { list($element, $content, $params, $tag) = $data; $tagName = strtolower($element); switch($tagName) { case '!--': // Comment gets always extracted $output = $tag; $tempstrip->setPair($marker, $output); break; case 'nowiki': // ...      $output = $tag; // we add the spans after this loop $nowiki_markers_replace[$marker] = '<span class="tex2jax_ignore">'. $marker. ' ';     $strip_state->nowiki->setPair($marker, $output); // this will be "unstripped" in the normal code break; case 'pre': case 'code': // ... and $output = $tag; // we add the spans after this loop $precode_markers_replace[$marker] = '<span class="tex2jax_ignore">'. $marker. ' ';     $tempstrip->setPair($marker, $output); // this will be "unstripped" in the normal code break; } }  MathJax_subst_math_tag($text); // ... // now add the spans for the nowiki parts by replacing the markers by spanned markers $text = strtr($text, $nowiki_markers_replace); // now add the spans for the pre and code parts by replacing the markers by spanned markers $text = strtr($text, $precode_markers_replace); // now it should be safe for our mathematics handling // but we delay that for the InternalParseBeforeLinks hook // (MathJax_parser_stage2) as then templates have been expanded as well; note // that the handling of nowiki, pre and code will be messed up for templates! #MathJax_parser_stage2($parser, $text, $strip_state); // Insert the comments back in: Unstrip comments, pre and code $text = $tempstrip->replace($text); return true; }

/** * MathJax_parser_stage2(&$parser, &$text, &$strip_state) * * The stage 2 math parser will "strip" (replace by place holders) all math * environments, adding them to the $strip_state->nowiki ReplacementArray. * Additionally we register the \label{}, if present, of the math enviroment and * replace it by an auto numbered \tag{} and then replace all occurances of * \eqref{} by the correct formula number. Existing \tag{} commands are also * registered such that they can be referenced using \eqref{}. * * The stage 2 parser will see the expanded templates; and therefore, here as * well, we will replace "..." and ":..." by MathJax * delimiters. We can not handle nowiki, pre and code tags in the expanded * templates. * * @param &$parser       The Parser object doing the job. * @param &$text         The text which is thrown in. * @param &$strip_state  A StripState object which holds two *                       ReplacementArray's which are key value lists of place *                       holders (substituted into the $text) and their value. * * @returns              true on success; false on failure (never triggered). * * @hook       InternalParseBeforeLinks * @globals    $MathJax_strip_state, $MathJax_unique_prefix, $MathJax_mark_n, $MathJax_marker_suffix *             $MathJax_eqnumber, $MathJax_eqnumbers * @seealso    MathJax_parser_stage1 */ $MathJax_strip_state = null; $MathJax_unique_prefix = null; $MathJax_mark_n = 1; $MathJax_eqnumber = 1; $MathJax_eqnumbers = array; $wgHooks['InternalParseBeforeLinks'][] = 'MathJax_parser_stage2'; function MathJax_parser_stage2(&$parser, &$text, &$strip_state) { global $MathJax_strip_state, $MathJax_unique_prefix, $MathJax_marker_suffix;

// we need to add the formulas in a regex callback to the strip state // simple and dirty solution: use globals $MathJax_strip_state = $strip_state; // this is $parser->mStripState $MathJax_unique_prefix = $parser->uniqPrefix; $MathJax_marker_suffix = $parser::MARKER_SUFFIX;

MathJax_subst_math_tag($text); // ...

// now handle all MathJax math environments by registering equations // (numbering) and stripping them (replacing by place holder); // they get added to the nowiki strip list and will be unstripped in  // Parser::Parse just before the ParserBeforeTidy hook $text = preg_replace_callback('/(\\\\begin{(.*?)})(.*?)(\\\\end{\\2})/s', 'MathJax_register_and_strip_math', $text); // watch out for \$ in TeX using negative look behind: $text = preg_replace_callback('/((\${1,2}))(.*?)((?<!\\\\)\\2)/s', 'MathJax_register_and_strip_math', $text); $text = preg_replace_callback('/((\\\\\\[))(.*?)(\\\\\\])/s', 'MathJax_register_and_strip_math', $text); $text = preg_replace_callback('/((\\\\\\)(.*?)(\\\\\\))/s', 'MathJax_register_and_strip_math', $text);

// replace all occurances of \eqref{} (and also \ref{}) by the correct formula // reference (as plain text, e.g., \eqref{sum} becomes (2)) $text = preg_replace_callback('(\\\\(eq)?ref\\{(.*?)\\})', 'MathJax_replace_eqrefs', $text);

return true; }

/** * MathJax_subst_math_tag(&$text) * * Change "..." into "\(...\)" (inline math style) *   and ": ...$$" into "\[...\]" (display math style) in place. */ function MathJax_subst_math_tag(&$text) { // Change $$...$$ and :$$...$$ into \(...\) and \[...\] $text = preg_replace('|:$$(.*?)$$|s', '\\\\[$1\\\\]', $text); $text = preg_replace('|$$(.*?)$$|s', '\\\\($1\\\\)', $text); }

/** * MathJax_register_and_strip_math($matches) * * This is a regex callback used from MathJax_parser_stage2 to replace MathJax * math environments and register an equation number (if \label{} or \tag{} is * present). * * @param matches  Match array where *                   $matches[1] is the opening math delimiter *                   $matches[3] is the TeX content *                   $matches[4] is the closing math delimiter *                 Note: $matches[2] has no function; it was used as a backref * * @return The marker which was used to replace the math environment. * * @globals  $MathJax_strip_state, $MathJax_unique_prefix, $MathJax_mark_n, $MathJax_marker_suffix *           $MathJax_eqnumber, $MathJax_eqnumbers */ function MathJax_register_and_strip_math($matches) { global $MathJax_strip_state, $MathJax_unique_prefix, $MathJax_mark_n, $MathJax_marker_suffix; $eq = $matches[3]; // formula numbering $eq = preg_replace_callback('(\\\\(label|tag)\{(.*?)\})', 'MathJax_register_eq', $eq); $marker = $MathJax_unique_prefix. "-MathJax-". sprintf('%08X', $MathJax_mark_n++). $MathJax_marker_suffix; $stripped = $matches[1]. $eq. $matches[4]; $MathJax_strip_state->nowiki->setPair($marker, $stripped); return $marker; }

/** * MathJax_register_eq($matches) * * This is a regex callback used from MathJax_register_and_strip_math to * register a formula number (or given tag) for later referencing by \eqref. * * @param matches  Match array where *                   $matches[1]   is either 'label' or 'tag' *                   $matches[2]   is the argument from \label{} or \tag{} * * @return An autonumbered tag. * * @globals  $MathJax_eqnumber, $MathJax_eqnumbers */ function MathJax_register_eq($matches) { global $MathJax_eqnumber, $MathJax_eqnumbers; $label = $matches[2]; if(array_key_exists($label, $MathJax_eqnumbers)) return '\\tag{'. $label. ':label exists!}'; $MathJax_eqnumbers[$label] = $matches[1] == 'label' ? $MathJax_eqnumber++ : $label; return '\\tag{'. $MathJax_eqnumbers[$label]. '}'; }

/** * MathJax_replace_eqrefs($matches) * * This is a regex callback used from MathJax_parser_stage2 to replace all * \eqref{} references with the correct formula reference. * * @param matches  Match array where *                   $matches[2]   is the argument of \eqref{} * * @return A textual reference. (No link yet...) * * @globals  $MathJax_eqnumbers */ function MathJax_replace_eqrefs($matches) { global $MathJax_eqnumbers; $label = $matches[2]; # the possible "eq" for "eqref" is in $matches[1]... if(array_key_exists($label, $MathJax_eqnumbers)) return "(" . $MathJax_eqnumbers[$label] . ")"; return " ". $matches[0]. " "; }