www

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

toMathML.js (9950B)


      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/toMathML.js
      7  *  
      8  *  Implements a toMathML() method for the mml Element Jax that returns
      9  *  a MathML string from a given math expression.
     10  *
     11  *  ---------------------------------------------------------------------
     12  *  
     13  *  Copyright (c) 2010-2015 The MathJax Consortium
     14  * 
     15  *  Licensed under the Apache License, Version 2.0 (the "License");
     16  *  you may not use this file except in compliance with the License.
     17  *  You may obtain a copy of the License at
     18  * 
     19  *      http://www.apache.org/licenses/LICENSE-2.0
     20  * 
     21  *  Unless required by applicable law or agreed to in writing, software
     22  *  distributed under the License is distributed on an "AS IS" BASIS,
     23  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     24  *  See the License for the specific language governing permissions and
     25  *  limitations under the License.
     26  */
     27 
     28 MathJax.Hub.Register.LoadHook("[MathJax]/jax/element/mml/jax.js",function () {
     29   var VERSION = "2.6.1";
     30   
     31   var MML = MathJax.ElementJax.mml,
     32       SETTINGS = MathJax.Hub.config.menuSettings;
     33   
     34   MML.mbase.Augment({
     35 
     36     toMathML: function (space) {
     37       var inferred = (this.inferred && this.parent.inferRow);
     38       if (space == null) {space = ""}
     39       var tag = this.type, attr = this.toMathMLattributes();
     40       if (tag === "mspace") {return space + "<"+tag+attr+" />"}
     41       var data = [], SPACE = (this.isToken ? "" : space+(inferred ? "" : "  "));
     42       for (var i = 0, m = this.data.length; i < m; i++) {
     43         if (this.data[i]) {data.push(this.data[i].toMathML(SPACE))}
     44           else if (!this.isToken && !this.isChars) {data.push(SPACE+"<mrow />")}
     45       }
     46       if (this.isToken || this.isChars) {return space + "<"+tag+attr+">"+data.join("")+"</"+tag+">"}
     47       if (inferred) {return data.join("\n")}
     48       if (data.length === 0 || (data.length === 1 && data[0] === ""))
     49         {return space + "<"+tag+attr+" />"}
     50       return space + "<"+tag+attr+">\n"+data.join("\n")+"\n"+ space +"</"+tag+">";
     51     },
     52 
     53     toMathMLattributes: function () {
     54       var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults);
     55       var names = (this.attrNames||MML.copyAttributeNames),
     56           skip = MML.skipAttributes, copy = MML.copyAttributes;
     57       var attr = [];
     58 
     59       if (this.type === "math" && (!this.attr || !this.attr.xmlns))
     60         {attr.push('xmlns="http://www.w3.org/1998/Math/MathML"')}
     61       if (!this.attrNames) {
     62         for (var id in defaults) {if (!skip[id] && !copy[id] && defaults.hasOwnProperty(id)) {
     63           if (this[id] != null && this[id] !== defaults[id]) {
     64             if (this.Get(id,null,1) !== this[id])
     65               attr.push(id+'="'+this.toMathMLattribute(this[id])+'"');
     66           }
     67         }}
     68       }
     69       for (var i = 0, m = names.length; i < m; i++) {
     70         if (copy[names[i]] === 1 && !defaults.hasOwnProperty(names[i])) continue;
     71         value = (this.attr||{})[names[i]]; if (value == null) {value = this[names[i]]}
     72         if (value != null) {attr.push(names[i]+'="'+this.toMathMLquote(value)+'"')}
     73       }
     74       this.toMathMLclass(attr);
     75       if (attr.length) {return " "+attr.join(" ")} else {return ""}
     76     },
     77     toMathMLclass: function (attr) {
     78       var CLASS = []; if (this["class"]) {CLASS.push(this["class"])}
     79       if (this.isa(MML.TeXAtom) && SETTINGS.texHints) {
     80         var TEXCLASS = ["ORD","OP","BIN","REL","OPEN","CLOSE","PUNCT","INNER","VCENTER"][this.texClass];
     81         if (TEXCLASS) {
     82           CLASS.push("MJX-TeXAtom-"+TEXCLASS)
     83           if (TEXCLASS === "OP" && !this.movablelimits) CLASS.push("MJX-fixedlimits");
     84         }
     85       }
     86       if (this.mathvariant && this.toMathMLvariants[this.mathvariant])
     87         {CLASS.push("MJX"+this.mathvariant)}
     88       if (this.variantForm) {CLASS.push("MJX-variant")}
     89       if (CLASS.length) {attr.unshift('class="'+CLASS.join(" ")+'"')}
     90     },
     91     toMathMLattribute: function (value) {
     92       if (typeof(value) === "string" &&
     93           value.replace(/ /g,"").match(/^(([-+])?(\d+(\.\d*)?|\.\d+))mu$/)) {
     94         // FIXME:  should take scriptlevel into account
     95         return (RegExp.$2||"")+((1/18)*RegExp.$3).toFixed(3).replace(/\.?0+$/,"")+"em";
     96       }
     97       else if (this.toMathMLvariants[value]) {return this.toMathMLvariants[value]}
     98       return this.toMathMLquote(value);
     99     },
    100     toMathMLvariants: {
    101       "-tex-caligraphic":      MML.VARIANT.SCRIPT,
    102       "-tex-caligraphic-bold": MML.VARIANT.BOLDSCRIPT,
    103       "-tex-oldstyle":         MML.VARIANT.NORMAL,
    104       "-tex-oldstyle-bold":    MML.VARIANT.BOLD,
    105       "-tex-mathit":           MML.VARIANT.ITALIC
    106     },
    107     
    108     toMathMLquote: function (string) {
    109       string = String(string).split("");
    110       for (var i = 0, m = string.length; i < m; i++) {
    111         var n = string[i].charCodeAt(0);
    112         if (n <= 0xD7FF || 0xE000 <= n) {
    113           // Code points U+0000 to U+D7FF and U+E000 to U+FFFF.
    114           // They are directly represented by n.
    115           if (n > 0x7E || (n < 0x20 && n !== 0x0A && n !== 0x0D && n !== 0x09)) {
    116             string[i] = "&#x"+n.toString(16).toUpperCase()+";";
    117           } else {
    118             var c =
    119               {'&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;'}[string[i]];
    120             if (c) {string[i] = c}
    121           }
    122         } else if (i+1 < m) {
    123           // Code points U+10000 to U+10FFFF.
    124           // n is the lead surrogate, let's read the trail surrogate.
    125           var trailSurrogate = string[i+1].charCodeAt(0);
    126           var codePoint = (((n-0xD800)<<10)+(trailSurrogate-0xDC00)+0x10000);
    127           string[i] = "&#x"+codePoint.toString(16).toUpperCase()+";";
    128           string[i+1] = "";
    129           i++;
    130         } else {
    131           // n is a lead surrogate without corresponding trail surrogate:
    132           // remove that character.
    133           string[i] = "";
    134         }
    135       }
    136       return string.join("");
    137     }
    138   });
    139   
    140   //
    141   //  Override math.toMathML in order to add semantics tag
    142   //  for the input format, if the user requests that in the
    143   //  Show As menu.
    144   //
    145   MML.math.Augment({
    146     toMathML: function (space,jax) {
    147       var annotation;
    148       if (space == null) {space = ""}
    149       if (jax && jax.originalText && SETTINGS.semantics)
    150         {annotation = MathJax.InputJax[jax.inputJax].annotationEncoding}
    151       var nested = (this.data[0] && this.data[0].data.length > 1);
    152       var tag = this.type, attr = this.toMathMLattributes();
    153       var data = [], SPACE = space + (annotation ? "  " + (nested ? "  " : "") : "") + "  ";
    154       for (var i = 0, m = this.data.length; i < m; i++) {
    155         if (this.data[i]) {data.push(this.data[i].toMathML(SPACE))}
    156           else {data.push(SPACE+"<mrow />")}
    157       }
    158       if (data.length === 0 || (data.length === 1 && data[0] === "")) {
    159         if (!annotation) {return "<"+tag+attr+" />"}
    160         data.push(SPACE+"<mrow />");
    161       }
    162       if (annotation) {
    163         if (nested) {data.unshift(space+"    <mrow>"); data.push(space+"    </mrow>")}
    164         data.unshift(space+"  <semantics>");
    165         var xmlEscapedTex = jax.originalText.replace(/[&<>]/g, function(item) {
    166             return { '>': '&gt;', '<': '&lt;','&': '&amp;' }[item]
    167         });
    168         data.push(space+'    <annotation encoding="'+annotation+'">'+xmlEscapedTex+"</annotation>");
    169         data.push(space+"  </semantics>");
    170       }
    171       return space+"<"+tag+attr+">\n"+data.join("\n")+"\n"+space+"</"+tag+">";
    172     }
    173   });
    174   
    175   MML.msubsup.Augment({
    176     toMathML: function (space) {
    177       var tag = this.type;
    178       if (this.data[this.sup] == null) {tag = "msub"}
    179       if (this.data[this.sub] == null) {tag = "msup"}
    180       var attr = this.toMathMLattributes();
    181       delete this.data[0].inferred;
    182       var data = [];
    183       for (var i = 0, m = this.data.length; i < m; i++)
    184         {if (this.data[i]) {data.push(this.data[i].toMathML(space+"  "))}}
    185       return space + "<"+tag+attr+">\n" + data.join("\n") + "\n" + space + "</"+tag+">";
    186     }
    187   });
    188   
    189   MML.munderover.Augment({
    190     toMathML: function (space) {
    191       var tag = this.type;
    192       var base = this.data[this.base];
    193       if (base && base.isa(MML.TeXAtom) && base.movablelimits && !base.Get("displaystyle")) {
    194         type = "msubsup";
    195         if (this.data[this.under] == null) {tag = "msup"}
    196         if (this.data[this.over] == null)  {tag = "msub"}
    197       } else {
    198         if (this.data[this.under] == null) {tag = "mover"}
    199         if (this.data[this.over] == null)  {tag = "munder"}
    200       }
    201       var attr = this.toMathMLattributes();
    202       delete this.data[0].inferred;
    203       var data = [];
    204       for (var i = 0, m = this.data.length; i < m; i++)
    205         {if (this.data[i]) {data.push(this.data[i].toMathML(space+"  "))}}
    206       return space + "<"+tag+attr+">\n" + data.join("\n") + "\n" + space + "</"+tag+">";
    207     }
    208   });
    209   
    210   MML.TeXAtom.Augment({
    211     toMathML: function (space) {
    212       // FIXME:  Handle spacing using mpadded?
    213       var attr = this.toMathMLattributes();
    214       if (!attr && this.data[0].data.length === 1) {return space.substr(2) + this.data[0].toMathML(space)}
    215       return space+"<mrow"+attr+">\n" + this.data[0].toMathML(space+"  ")+"\n"+space+"</mrow>";
    216     }
    217   });
    218   
    219   MML.chars.Augment({
    220     toMathML: function (space) {return (space||"") + this.toMathMLquote(this.toString())}
    221   });
    222   
    223   MML.entity.Augment({
    224     toMathML: function (space) {return (space||"") + "&"+this.data[0]+";<!-- "+this.toString()+" -->"}
    225   });
    226   
    227   MML.xml.Augment({
    228    toMathML: function (space) {return (space||"") + this.toString()}
    229   });
    230   
    231   MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function () {
    232     MML.TeXmathchoice.Augment({
    233       toMathML: function (space) {return this.Core().toMathML(space)}
    234     });
    235   });
    236   
    237   MathJax.Hub.Startup.signal.Post("toMathML Ready");
    238   
    239 });
    240 
    241 MathJax.Ajax.loadComplete("[MathJax]/extensions/toMathML.js");