www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

mml2jax.js (10376B)


      1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 
      4 /*************************************************************
      5  *
      6  *  MathJax/extensions/mml2jax.js
      7  *  
      8  *  Implements the MathML to Jax preprocessor that locates <math> nodes
      9  *  within the text of a document and replaces them with SCRIPT tags
     10  *  for processing by MathJax.
     11  *
     12  *  ---------------------------------------------------------------------
     13  *  
     14  *  Copyright (c) 2010-2015 The MathJax Consortium
     15  * 
     16  *  Licensed under the Apache License, Version 2.0 (the "License");
     17  *  you may not use this file except in compliance with the License.
     18  *  You may obtain a copy of the License at
     19  * 
     20  *      http://www.apache.org/licenses/LICENSE-2.0
     21  * 
     22  *  Unless required by applicable law or agreed to in writing, software
     23  *  distributed under the License is distributed on an "AS IS" BASIS,
     24  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     25  *  See the License for the specific language governing permissions and
     26  *  limitations under the License.
     27  */
     28 
     29 MathJax.Extension.mml2jax = {
     30   version: "2.6.0",
     31   config: {
     32     preview: "mathml"       // Use the <math> element as the
     33                             //   preview.  Set to "none" for no preview,
     34                             //   set to "alttext" to use the alttext attribute
     35                             //   of the <math> element, set to "altimg" to use
     36                             //   an image described by the altimg* attributes
     37                             //   or set to an array specifying an HTML snippet
     38                             //   to use a fixed preview for all math
     39 
     40   },
     41   MMLnamespace: "http://www.w3.org/1998/Math/MathML",
     42   
     43   PreProcess: function (element) {
     44     if (!this.configured) {
     45       this.config = MathJax.Hub.CombineConfig("mml2jax",this.config);
     46       if (this.config.Augment) {MathJax.Hub.Insert(this,this.config.Augment)}
     47       this.InitBrowser();
     48       this.configured = true;
     49     }
     50     if (typeof(element) === "string") {element = document.getElementById(element)}
     51     if (!element) {element = document.body}
     52     var mathArray = [];
     53     //
     54     //  Handle all math tags with no namespaces
     55     //
     56     this.PushMathElements(mathArray,element,"math");
     57     //
     58     //  Handle math with namespaces in XHTML
     59     //
     60     this.PushMathElements(mathArray,element,"math",this.MMLnamespace);
     61     //
     62     //  Handle math with namespaces in HTML
     63     //
     64     var i, m;
     65     if (typeof(document.namespaces) !== "undefined") {
     66       //
     67       // IE namespaces are listed in document.namespaces
     68       //
     69       try {
     70         for (i = 0, m = document.namespaces.length; i < m; i++) {
     71           var ns = document.namespaces[i];
     72           if (ns.urn === this.MMLnamespace)
     73             {this.PushMathElements(mathArray,element,ns.name+":math")}
     74         }
     75       } catch (err) {}
     76     } else {
     77       //
     78       //  Everybody else
     79       //  
     80       var html = document.getElementsByTagName("html")[0];
     81       if (html) {
     82         for (i = 0, m = html.attributes.length; i < m; i++) {
     83           var attr = html.attributes[i];
     84           if (attr.nodeName.substr(0,6) === "xmlns:" && attr.nodeValue === this.MMLnamespace)
     85             {this.PushMathElements(mathArray,element,attr.nodeName.substr(6)+":math")}
     86         }
     87       }
     88     }
     89     this.ProcessMathArray(mathArray);
     90   },
     91   
     92   PushMathElements: function (array,element,name,namespace) {
     93     var math, preview = MathJax.Hub.config.preRemoveClass;
     94     if (namespace) {
     95       if (!element.getElementsByTagNameNS) return;
     96       math = element.getElementsByTagNameNS(namespace,name);
     97     } else {
     98       math = element.getElementsByTagName(name);
     99     }
    100     for (var i = 0, m = math.length; i < m; i++) {
    101       var parent = math[i].parentNode;
    102       if (parent && parent.className !== preview &&
    103          !parent.isMathJax && !math[i].prefix === !namespace) array.push(math[i]);
    104     }
    105   },
    106   
    107   ProcessMathArray: function (math) {
    108     var i, m = math.length;
    109     if (m) {
    110       if (this.MathTagBug) {
    111         for (i = 0; i < m; i++) {
    112           if (math[i].nodeName === "MATH") {this.ProcessMathFlattened(math[i])}
    113                                       else {this.ProcessMath(math[i])}
    114         }
    115       } else {
    116         for (i = 0; i < m; i++) {this.ProcessMath(math[i])}
    117       }
    118     }
    119   },
    120   
    121   ProcessMath: function (math) {
    122     var parent = math.parentNode;
    123     if (!parent || parent.className === MathJax.Hub.config.preRemoveClass) return;
    124     var script = document.createElement("script");
    125     script.type = "math/mml";
    126     parent.insertBefore(script,math);
    127     if (this.AttributeBug) {
    128       var html = this.OuterHTML(math);
    129       if (this.CleanupHTML) {
    130         html = html.replace(/<\?import .*?>/i,"").replace(/<\?xml:namespace .*?\/>/i,"");
    131         html = html.replace(/&nbsp;/g,"&#xA0;");
    132       }
    133       MathJax.HTML.setScript(script,html); parent.removeChild(math);
    134     } else {
    135       var span = MathJax.HTML.Element("span"); span.appendChild(math);
    136       MathJax.HTML.setScript(script,span.innerHTML);
    137     }
    138     if (this.config.preview !== "none") {this.createPreview(math,script)}
    139   },
    140   
    141   ProcessMathFlattened: function (math) {
    142     var parent = math.parentNode;
    143     if (!parent || parent.className === MathJax.Hub.config.preRemoveClass) return;
    144     var script = document.createElement("script");
    145     script.type = "math/mml";
    146     parent.insertBefore(script,math);
    147     var mml = "", node, MATH = math;
    148     while (math && math.nodeName !== "/MATH") {
    149       node = math; math = math.nextSibling;
    150       mml += this.NodeHTML(node);
    151       node.parentNode.removeChild(node);
    152     }
    153     if (math && math.nodeName === "/MATH") {math.parentNode.removeChild(math)}
    154     script.text = mml + "</math>";
    155     if (this.config.preview !== "none") {this.createPreview(MATH,script)}
    156   },
    157   
    158   NodeHTML: function (node) {
    159     var html, i, m;
    160     if (node.nodeName === "#text") {
    161       html = this.quoteHTML(node.nodeValue);
    162     } else if (node.nodeName === "#comment") {
    163       html = "<!--" + node.nodeValue + "-->"
    164     } else {
    165       // In IE, outerHTML doesn't properly quote attributes, so quote them by hand
    166       // In Opera, HTML special characters aren't quoted in attributes, so quote them
    167       html = "<"+node.nodeName.toLowerCase();
    168       for (i = 0, m = node.attributes.length; i < m; i++) {
    169         var attribute = node.attributes[i];
    170         if (attribute.specified && attribute.nodeName.substr(0,10) !== "_moz-math-") {
    171           // Opera 11.5 beta turns xmlns into xmlns:xmlns, so put it back (*** check after 11.5 is out ***)
    172           html += " "+attribute.nodeName.toLowerCase().replace(/xmlns:xmlns/,"xmlns")+"=";
    173           var value = attribute.nodeValue; // IE < 8 doesn't properly set style by setAttributes
    174           if (value == null && attribute.nodeName === "style" && node.style) {value = node.style.cssText}
    175           html += '"'+this.quoteHTML(value)+'"';
    176         }
    177       }
    178       html += ">";
    179       // Handle internal HTML (possibly due to <semantics> annotation or missing </math>)
    180       if (node.outerHTML != null && node.outerHTML.match(/(.<\/[A-Z]+>|\/>)$/)) {
    181         for (i = 0, m = node.childNodes.length; i < m; i++)
    182           {html += this.OuterHTML(node.childNodes[i])}
    183         html += "</"+node.nodeName.toLowerCase()+">";
    184       }
    185     }
    186     return html;
    187   },
    188   OuterHTML: function (node) {
    189     if (node.nodeName.charAt(0) === "#") {return this.NodeHTML(node)}
    190     if (!this.AttributeBug) {return node.outerHTML}
    191     var html = this.NodeHTML(node);
    192     for (var i = 0, m = node.childNodes.length; i < m; i++)
    193       {html += this.OuterHTML(node.childNodes[i]);}
    194     html += "</"+node.nodeName.toLowerCase()+">";
    195     return html;
    196   },
    197   quoteHTML: function (string) {
    198     if (string == null) {string = ""}
    199     return string.replace(/&/g,"&#x26;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;");
    200   },
    201   
    202   createPreview: function (math,script) {
    203     var preview = this.config.preview;
    204     if (preview === "none") return;
    205     var isNodePreview = false;
    206     if (preview === "mathml") {
    207       isNodePreview = true;
    208       // mathml preview does not work with IE < 9, so fallback to alttext.
    209       if (this.MathTagBug) {preview = "alttext"} else {preview = math.cloneNode(true)}
    210     }
    211     if (preview === "alttext" || preview === "altimg") {
    212       isNodePreview = true;
    213       var alttext = this.filterPreview(math.getAttribute("alttext"));
    214       if (preview === "alttext") {
    215         if (alttext != null) {preview = MathJax.HTML.TextNode(alttext)} else {preview = null}
    216       } else {
    217         var src = math.getAttribute("altimg");
    218         if (src != null) {
    219           // FIXME: use altimg-valign when display="inline"?
    220           var style = {width: math.getAttribute("altimg-width"), height: math.getAttribute("altimg-height")};
    221           preview = MathJax.HTML.Element("img",{src:src,alt:alttext,style:style});
    222         } else {preview = null}
    223       }
    224     }
    225     if (preview) {
    226       var span;
    227       if (isNodePreview) {
    228         span = MathJax.HTML.Element("span",{className:MathJax.Hub.config.preRemoveClass});
    229         span.appendChild(preview);
    230       } else {
    231         span = MathJax.HTML.Element("span",{className:MathJax.Hub.config.preRemoveClass},preview);
    232       }
    233       script.parentNode.insertBefore(span,script);
    234     }
    235   },
    236   
    237   filterPreview: function (text) {return text},
    238   
    239   InitBrowser: function () {
    240     var test = MathJax.HTML.Element("span",{id:"<", className: "mathjax", innerHTML: "<math><mi>x</mi><mspace /></math>"});
    241     var html = test.outerHTML || "";
    242     this.AttributeBug = html !== "" && !(
    243       html.match(/id="&lt;"/) &&           // "<" should convert to "&lt;"
    244       html.match(/class="mathjax"/) &&     // IE leaves out quotes
    245       html.match(/<\/math>/)               // Opera 9 drops tags after self-closing tags
    246     );
    247     this.MathTagBug = test.childNodes.length > 1;    // IE < 9 flattens unknown tags
    248     this.CleanupHTML = MathJax.Hub.Browser.isMSIE;   // remove namespace and other added tags
    249   }
    250 
    251 };
    252 
    253 //
    254 // We register the preprocessors with the following priorities:
    255 // - mml2jax.js: 5
    256 // - jsMath2jax.js: 8
    257 // - asciimath2jax.js, tex2jax.js: 10 (default)
    258 // See issues 18 and 484 and the other *2jax.js files.
    259 // 
    260 MathJax.Hub.Register.PreProcessor(["PreProcess",MathJax.Extension.mml2jax],5);
    261 MathJax.Ajax.loadComplete("[MathJax]/extensions/mml2jax.js");