www

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

AMSmath.js (23992B)


      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/TeX/AMSmath.js
      7  *
      8  *  Implements AMS math environments and macros.
      9  *  
     10  *  ---------------------------------------------------------------------
     11  *  
     12  *  Copyright (c) 2009-2015 The MathJax Consortium
     13  * 
     14  *  Licensed under the Apache License, Version 2.0 (the "License");
     15  *  you may not use this file except in compliance with the License.
     16  *  You may obtain a copy of the License at
     17  * 
     18  *      http://www.apache.org/licenses/LICENSE-2.0
     19  * 
     20  *  Unless required by applicable law or agreed to in writing, software
     21  *  distributed under the License is distributed on an "AS IS" BASIS,
     22  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     23  *  See the License for the specific language governing permissions and
     24  *  limitations under the License.
     25  */
     26 
     27 MathJax.Extension["TeX/AMSmath"] = {
     28   version: "2.6.1",
     29   
     30   number: 0,        // current equation number
     31   startNumber: 0,   // current starting equation number (for when equation is restarted)
     32   IDs: {},          // IDs used in previous equations
     33   eqIDs: {},        // IDs used in this equation
     34   labels: {},       // the set of labels
     35   eqlabels: {},     // labels in the current equation
     36   refs: []          // array of jax with unresolved references
     37 };
     38 
     39 MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
     40   
     41   var MML = MathJax.ElementJax.mml,
     42       TEX = MathJax.InputJax.TeX,
     43       AMS = MathJax.Extension["TeX/AMSmath"];
     44 
     45   var TEXDEF = TEX.Definitions,
     46       STACKITEM = TEX.Stack.Item,
     47       CONFIG = TEX.config.equationNumbers;
     48       
     49   var COLS = function (W) {
     50     var WW = [];
     51     for (var i = 0, m = W.length; i < m; i++) 
     52       {WW[i] = TEX.Parse.prototype.Em(W[i])}
     53     return WW.join(" ");
     54   };
     55   
     56   /******************************************************************************/
     57   
     58   TEXDEF.Add({
     59     mathchar0mo: {
     60       iiiint:     ['2A0C',{texClass: MML.TEXCLASS.OP}]
     61     },
     62     
     63     macros: {
     64       mathring:   ['Accent','2DA'],  // or 0x30A
     65       
     66       nobreakspace: 'Tilde',
     67       negmedspace:    ['Spacer',MML.LENGTH.NEGATIVEMEDIUMMATHSPACE],
     68       negthickspace:  ['Spacer',MML.LENGTH.NEGATIVETHICKMATHSPACE],
     69       
     70 //    intI:       ['Macro','\\mathchoice{\\!}{}{}{}\\!\\!\\int'],
     71 //    iint:       ['MultiIntegral','\\int\\intI'],          // now in core TeX input jax
     72 //    iiint:      ['MultiIntegral','\\int\\intI\\intI'],    // now in core TeX input jax
     73 //    iiiint:     ['MultiIntegral','\\int\\intI\\intI\\intI'], // now in mathchar0mo above
     74       idotsint:   ['MultiIntegral','\\int\\cdots\\int'],
     75       
     76 //    dddot:      ['Macro','\\mathop{#1}\\limits^{\\textstyle \\mathord{.}\\mathord{.}\\mathord{.}}',1],
     77 //    ddddot:     ['Macro','\\mathop{#1}\\limits^{\\textstyle \\mathord{.}\\mathord{.}\\mathord{.}\\mathord{.}}',1],
     78       dddot:      ['Accent','20DB'],
     79       ddddot:     ['Accent','20DC'],
     80       
     81       sideset:    ['Macro','\\mathop{\\mathop{\\rlap{\\phantom{#3}}}\\nolimits#1\\!\\mathop{#3}\\nolimits#2}',3],
     82       
     83       boxed:      ['Macro','\\fbox{$\\displaystyle{#1}$}',1],
     84       
     85       tag:         'HandleTag',
     86       notag:       'HandleNoTag',
     87       label:       'HandleLabel',
     88       ref:         'HandleRef',
     89       eqref:       ['HandleRef',true],
     90       
     91       substack:   ['Macro','\\begin{subarray}{c}#1\\end{subarray}',1],
     92       
     93       injlim:     ['NamedOp','inj&thinsp;lim'],
     94       projlim:    ['NamedOp','proj&thinsp;lim'],
     95       varliminf:  ['Macro','\\mathop{\\underline{\\mmlToken{mi}{lim}}}'],
     96       varlimsup:  ['Macro','\\mathop{\\overline{\\mmlToken{mi}{lim}}}'],
     97       varinjlim:  ['Macro','\\mathop{\\underrightarrow{\\mmlToken{mi}{lim}}}'],
     98       varprojlim: ['Macro','\\mathop{\\underleftarrow{\\mmlToken{mi}{lim}}}'],
     99       
    100       DeclareMathOperator: 'HandleDeclareOp',
    101       operatorname:        'HandleOperatorName',
    102       SkipLimits:          'SkipLimits',
    103       
    104       genfrac:     'Genfrac',
    105       frac:       ['Genfrac',"","","",""],
    106       tfrac:      ['Genfrac',"","","",1],
    107       dfrac:      ['Genfrac',"","","",0],
    108       binom:      ['Genfrac',"(",")","0",""],
    109       tbinom:     ['Genfrac',"(",")","0",1],
    110       dbinom:     ['Genfrac',"(",")","0",0],
    111       
    112       cfrac:       'CFrac',
    113       
    114       shoveleft:  ['HandleShove',MML.ALIGN.LEFT],
    115       shoveright: ['HandleShove',MML.ALIGN.RIGHT],
    116       
    117       xrightarrow: ['xArrow',0x2192,5,6],
    118       xleftarrow:  ['xArrow',0x2190,7,3]
    119     },
    120     
    121     environment: {
    122       align:         ['AMSarray',null,true,true,  'rlrlrlrlrlrl',COLS([0,2,0,2,0,2,0,2,0,2,0])],
    123       'align*':      ['AMSarray',null,false,true, 'rlrlrlrlrlrl',COLS([0,2,0,2,0,2,0,2,0,2,0])],
    124       multline:      ['Multline',null,true],
    125       'multline*':   ['Multline',null,false],
    126       split:         ['AMSarray',null,false,false,'rl',COLS([0])],
    127       gather:        ['AMSarray',null,true,true,  'c'],
    128       'gather*':     ['AMSarray',null,false,true, 'c'],
    129       
    130       alignat:       ['AlignAt',null,true,true],
    131       'alignat*':    ['AlignAt',null,false,true],
    132       alignedat:     ['AlignAt',null,false,false],
    133 
    134       aligned:       ['AlignedAMSArray',null,null,null,'rlrlrlrlrlrl',COLS([0,2,0,2,0,2,0,2,0,2,0]),".5em",'D'],
    135       gathered:      ['AlignedAMSArray',null,null,null,'c',null,".5em",'D'],
    136 
    137       subarray:      ['Array',null,null,null,null,COLS([0]),"0.1em",'S',1],
    138       smallmatrix:   ['Array',null,null,null,'c',COLS([1/3]),".2em",'S',1],
    139       
    140       'equation':    ['EquationBegin','Equation',true],
    141       'equation*':   ['EquationBegin','EquationStar',false],
    142 
    143       eqnarray:      ['AMSarray',null,true,true, 'rcl',"0 "+MML.LENGTH.THICKMATHSPACE,".5em"],
    144       'eqnarray*':   ['AMSarray',null,false,true,'rcl',"0 "+MML.LENGTH.THICKMATHSPACE,".5em"]
    145     },
    146     
    147     delimiter: {
    148       '\\lvert':     ['2223',{texClass:MML.TEXCLASS.OPEN}],
    149       '\\rvert':     ['2223',{texClass:MML.TEXCLASS.CLOSE}],
    150       '\\lVert':     ['2225',{texClass:MML.TEXCLASS.OPEN}],
    151       '\\rVert':     ['2225',{texClass:MML.TEXCLASS.CLOSE}]
    152     }
    153   },null,true);
    154     
    155 
    156   /******************************************************************************/
    157   
    158   TEX.Parse.Augment({
    159 
    160     /*
    161      *  Add the tag to the environment (to be added to the table row later)
    162      */
    163     HandleTag: function (name) {
    164       var star = this.GetStar();
    165       var arg = this.trimSpaces(this.GetArgument(name)), tag = arg;
    166       if (!star) {arg = CONFIG.formatTag(arg)}
    167       var global = this.stack.global; global.tagID = tag;
    168       if (global.notags) {
    169         TEX.Error(["CommandNotAllowedInEnv",
    170                    "%1 not allowed in %2 environment",
    171                    name,global.notags]
    172         );
    173       }
    174       if (global.tag) {TEX.Error(["MultipleCommand","Multiple %1",name])}
    175       global.tag = MML.mtd.apply(MML,this.InternalMath(arg)).With({id:CONFIG.formatID(tag)});
    176     },
    177     HandleNoTag: function (name) {
    178       if (this.stack.global.tag) {delete this.stack.global.tag}
    179       this.stack.global.notag = true;  // prevent auto-tagging
    180     },
    181     
    182     /*
    183      *  Record a label name for a tag
    184      */
    185     HandleLabel: function (name) {
    186       var global = this.stack.global, label = this.GetArgument(name);
    187       if (label === "") return;
    188       if (!AMS.refUpdate) {
    189         if (global.label) {TEX.Error(["MultipleCommand","Multiple %1",name])}
    190         global.label = label;
    191         if (AMS.labels[label] || AMS.eqlabels[label])
    192           {TEX.Error(["MultipleLabel","Label '%1' multiply defined",label])}
    193         AMS.eqlabels[label] = {tag:"???", id:""}; // will be replaced by tag value later
    194       }
    195     },
    196     
    197     /*
    198      *  Handle a label reference
    199      */
    200     HandleRef: function (name,eqref) {
    201       var label = this.GetArgument(name);
    202       var ref = AMS.labels[label] || AMS.eqlabels[label];
    203       if (!ref) {ref = {tag:"???",id:""}; AMS.badref = !AMS.refUpdate}
    204       var tag = ref.tag; if (eqref) {tag = CONFIG.formatTag(tag)}
    205       this.Push(MML.mrow.apply(MML,this.InternalMath(tag)).With({
    206         href:CONFIG.formatURL(ref.id), "class":"MathJax_ref"
    207       }));
    208     },
    209     
    210     /*
    211      *  Handle \DeclareMathOperator
    212      */
    213     HandleDeclareOp: function (name) {
    214       var limits = (this.GetStar() ? "" : "\\nolimits\\SkipLimits");
    215       var cs = this.trimSpaces(this.GetArgument(name));
    216       if (cs.charAt(0) == "\\") {cs = cs.substr(1)}
    217       var op = this.GetArgument(name);
    218       op = op.replace(/\*/g,'\\text{*}').replace(/-/g,'\\text{-}');
    219       TEX.Definitions.macros[cs] = ['Macro','\\mathop{\\rm '+op+'}'+limits];
    220     },
    221     
    222     HandleOperatorName: function (name) {
    223       var limits = (this.GetStar() ? "" : "\\nolimits\\SkipLimits");
    224       var op = this.trimSpaces(this.GetArgument(name));
    225       op = op.replace(/\*/g,'\\text{*}').replace(/-/g,'\\text{-}');
    226       this.string = '\\mathop{\\rm '+op+'}'+limits+" "+this.string.slice(this.i);
    227       this.i = 0;
    228     },
    229     
    230     SkipLimits: function (name) {
    231       var c = this.GetNext(), i = this.i;
    232       if (c === "\\" && ++this.i && this.GetCS() !== "limits") this.i = i;
    233     },
    234 
    235     /*
    236      *  Record presence of \shoveleft and \shoveright
    237      */
    238     HandleShove: function (name,shove) {
    239       var top = this.stack.Top();
    240       if (top.type !== "multline" || top.data.length) {
    241         TEX.Error(["CommandAtTheBeginingOfLine",
    242                    "%1 must come at the beginning of the line",name]);
    243       }
    244       top.data.shove = shove;
    245     },
    246     
    247     /*
    248      *  Handle \cfrac
    249      */
    250     CFrac: function (name) {
    251       var lr  = this.trimSpaces(this.GetBrackets(name,"")),
    252           num = this.GetArgument(name),
    253           den = this.GetArgument(name);
    254       var frac = MML.mfrac(TEX.Parse('\\strut\\textstyle{'+num+'}',this.stack.env).mml(),
    255                            TEX.Parse('\\strut\\textstyle{'+den+'}',this.stack.env).mml());
    256       lr = ({l:MML.ALIGN.LEFT, r:MML.ALIGN.RIGHT,"":""})[lr];
    257       if (lr == null)
    258         {TEX.Error(["IllegalAlign","Illegal alignment specified in %1",name])}
    259       if (lr) {frac.numalign = frac.denomalign = lr}
    260       this.Push(frac);
    261     },
    262     
    263     /*
    264      *  Implement AMS generalized fraction
    265      */
    266     Genfrac: function (name,left,right,thick,style) {
    267       if (left  == null) {left  = this.GetDelimiterArg(name)}
    268       if (right == null) {right = this.GetDelimiterArg(name)}
    269       if (thick == null) {thick = this.GetArgument(name)}
    270       if (style == null) {style = this.trimSpaces(this.GetArgument(name))}
    271       var num = this.ParseArg(name);
    272       var den = this.ParseArg(name);
    273       var frac = MML.mfrac(num,den);
    274       if (thick !== "") {frac.linethickness = thick}
    275       if (left || right) {frac = TEX.fixedFence(left,frac.With({texWithDelims:true}),right)}
    276       if (style !== "") {
    277         var STYLE = (["D","T","S","SS"])[style];
    278         if (STYLE == null)
    279           {TEX.Error(["BadMathStyleFor","Bad math style for %1",name])}
    280         frac = MML.mstyle(frac);
    281         if (STYLE === "D") {frac.displaystyle = true; frac.scriptlevel = 0}
    282           else {frac.displaystyle = false; frac.scriptlevel = style - 1}
    283       }
    284       this.Push(frac);
    285     },
    286 
    287     /*
    288      *  Implements multline environment (mostly handled through STACKITEM below)
    289      */
    290     Multline: function (begin,numbered) {
    291       this.Push(begin); this.checkEqnEnv();
    292       return STACKITEM.multline(numbered,this.stack).With({
    293         arraydef: {
    294           displaystyle: true,
    295           rowspacing: ".5em",
    296           width: TEX.config.MultLineWidth, columnwidth:"100%",
    297           side: TEX.config.TagSide,
    298           minlabelspacing: TEX.config.TagIndent
    299         }
    300       });
    301     },
    302 
    303     /*
    304      *  Handle AMS aligned environments
    305      */
    306     AMSarray: function (begin,numbered,taggable,align,spacing) {
    307       this.Push(begin); if (taggable) {this.checkEqnEnv()}
    308       align = align.replace(/[^clr]/g,'').split('').join(' ');
    309       align = align.replace(/l/g,'left').replace(/r/g,'right').replace(/c/g,'center');
    310       return STACKITEM.AMSarray(begin.name,numbered,taggable,this.stack).With({
    311         arraydef: {
    312           displaystyle: true,
    313           rowspacing: ".5em",
    314           columnalign: align,
    315           columnspacing: (spacing||"1em"),
    316           rowspacing: "3pt",
    317           side: TEX.config.TagSide,
    318           minlabelspacing: TEX.config.TagIndent
    319         }
    320       });
    321     },
    322     
    323     AlignedAMSArray: function (begin) {
    324       var align = this.GetBrackets("\\begin{"+begin.name+"}");
    325       return this.setArrayAlign(this.AMSarray.apply(this,arguments),align);
    326     },
    327 
    328     /*
    329      *  Handle alignat environments
    330      */
    331     AlignAt: function (begin,numbered,taggable) {
    332       var n, valign, align = "", spacing = [];
    333       if (!taggable) {valign = this.GetBrackets("\\begin{"+begin.name+"}")}
    334       n = this.GetArgument("\\begin{"+begin.name+"}");
    335       if (n.match(/[^0-9]/)) {
    336         TEX.Error(["PositiveIntegerArg","Argument to %1 must me a positive integer",
    337                   "\\begin{"+begin.name+"}"]);
    338       }
    339       while (n > 0) {align += "rl"; spacing.push("0em 0em"); n--}
    340       spacing = spacing.join(" ");
    341       if (taggable) {return this.AMSarray(begin,numbered,taggable,align,spacing)}
    342       var array = this.AMSarray(begin,numbered,taggable,align,spacing);
    343       return this.setArrayAlign(array,valign);
    344     },
    345     
    346     /*
    347      *  Handle equation environment
    348      */
    349     EquationBegin: function (begin,force) {
    350       this.checkEqnEnv();
    351       this.stack.global.forcetag = (force && CONFIG.autoNumber !== "none");
    352       return begin;
    353     },
    354     EquationStar: function (begin,row) {
    355       this.stack.global.tagged = true; // prevent automatic tagging
    356       return row;
    357     },
    358     
    359     /*
    360      *  Check for bad nesting of equation environments
    361      */
    362     checkEqnEnv: function () {
    363       if (this.stack.global.eqnenv)
    364         {TEX.Error(["ErroneousNestingEq","Erroneous nesting of equation structures"])}
    365       this.stack.global.eqnenv = true;
    366     },
    367     
    368     /*
    369      *  Handle multiple integrals (make a mathop if followed by limits)
    370      */
    371     MultiIntegral: function (name,integral) {
    372       var next = this.GetNext();
    373       if (next === "\\") {
    374         var i = this.i; next = this.GetArgument(name); this.i = i;
    375         if (next === "\\limits") {
    376           if (name === "\\idotsint") {integral = "\\!\\!\\mathop{\\,\\,"+integral+"}"}
    377                            else {integral = "\\!\\!\\!\\mathop{\\,\\,\\,"+integral+"}"}
    378         }
    379       }
    380       this.string = integral + " " + this.string.slice(this.i);
    381       this.i = 0;
    382     },
    383     
    384     /*
    385      *  Handle stretchable arrows
    386      */
    387     xArrow: function (name,chr,l,r) {
    388       var def = {width: "+"+(l+r)+"mu", lspace: l+"mu"};
    389       var bot = this.GetBrackets(name),
    390           top = this.ParseArg(name);
    391       var arrow = MML.mo(MML.chars(String.fromCharCode(chr))).With({
    392         stretchy: true, texClass: MML.TEXCLASS.REL
    393       });
    394       var mml = MML.munderover(arrow);
    395       mml.SetData(mml.over,MML.mpadded(top).With(def).With({voffset:".15em"}));
    396       if (bot) {
    397         bot = TEX.Parse(bot,this.stack.env).mml()
    398         mml.SetData(mml.under,MML.mpadded(bot).With(def).With({voffset:"-.24em"}));
    399       }
    400       this.Push(mml.With({subsupOK:true}));
    401     },
    402     
    403     /*
    404      *  Get a delimiter or empty argument
    405      */
    406     GetDelimiterArg: function (name) {
    407       var c = this.trimSpaces(this.GetArgument(name));
    408       if (c == "") return null;
    409       if (c in TEXDEF.delimiter) return c;
    410       TEX.Error(["MissingOrUnrecognizedDelim","Missing or unrecognized delimiter for %1",name]);
    411     },
    412     
    413     /*
    414      *  Get a star following a control sequence name, if any
    415      */
    416     GetStar: function () {
    417       var star = (this.GetNext() === "*");
    418       if (star) {this.i++}
    419       return star;
    420     }
    421     
    422   });
    423   
    424   /******************************************************************************/
    425   
    426   STACKITEM.Augment({
    427     /*
    428      *  Increment equation number and form tag mtd element
    429      */
    430     autoTag: function () {
    431       var global = this.global;
    432       if (!global.notag) {
    433         AMS.number++; global.tagID = CONFIG.formatNumber(AMS.number.toString());
    434         var mml = TEX.Parse("\\text{"+CONFIG.formatTag(global.tagID)+"}",{}).mml();
    435         global.tag = MML.mtd(mml).With({id:CONFIG.formatID(global.tagID)});
    436       }
    437     },
    438   
    439     /*
    440      *  Get the tag and record the label, if any
    441      */
    442     getTag: function () {
    443       var global = this.global, tag = global.tag; global.tagged = true;
    444       if (global.label) {
    445         if (CONFIG.useLabelIds) {tag.id = CONFIG.formatID(global.label)}
    446         AMS.eqlabels[global.label] = {tag:global.tagID, id:tag.id};        
    447       }
    448       //
    449       //  Check for repeated ID's (either in the document or as
    450       //  a previous tag) and find a unique related one. (#240)
    451       //
    452       if (document.getElementById(tag.id) || AMS.IDs[tag.id] || AMS.eqIDs[tag.id]) {
    453         var i = 0, ID;
    454         do {i++; ID = tag.id+"_"+i}
    455           while (document.getElementById(ID) || AMS.IDs[ID] || AMS.eqIDs[ID]);
    456         tag.id = ID; if (global.label) {AMS.eqlabels[global.label].id = ID}
    457       }
    458       AMS.eqIDs[tag.id] = 1;
    459       this.clearTag();
    460       return tag;
    461     },
    462     clearTag: function () {
    463       var global = this.global;
    464       delete global.tag; delete global.tagID; delete global.label;
    465     },
    466 
    467     /*
    468      *  If the initial child, skipping any initial space or
    469      *  empty braces (TeXAtom with child being an empty inferred row),
    470      *  is an <mo>, preceed it by an empty <mi> to force the <mo> to
    471      *  be infix.
    472      */
    473     fixInitialMO: function (data) {
    474       for (var i = 0, m = data.length; i < m; i++) {
    475         if (data[i] && (data[i].type !== "mspace" &&
    476            (data[i].type !== "texatom" || (data[i].data[0] && data[i].data[0].data.length)))) {
    477           if (data[i].isEmbellished()) data.unshift(MML.mi());
    478           break;
    479         }
    480       }
    481     }
    482   });
    483   
    484   /*
    485    *  Implement multline environment via a STACKITEM
    486    */
    487   STACKITEM.multline = STACKITEM.array.Subclass({
    488     type: "multline",
    489     Init: function (numbered,stack) {
    490       this.SUPER(arguments).Init.apply(this);
    491       this.numbered = (numbered && CONFIG.autoNumber !== "none");
    492       this.save = {notag: stack.global.notag};
    493       stack.global.tagged = !numbered && !stack.global.forcetag; // prevent automatic tagging in starred environments
    494     },
    495     EndEntry: function () {
    496       if (this.table.length) {this.fixInitialMO(this.data)}
    497       var mtd = MML.mtd.apply(MML,this.data);
    498       if (this.data.shove) {mtd.columnalign = this.data.shove}
    499       this.row.push(mtd);
    500       this.data = [];
    501     },
    502     EndRow: function () {
    503       if (this.row.length != 1) {
    504         TEX.Error(["MultlineRowsOneCol",
    505                    "The rows within the %1 environment must have exactly one column",
    506                    "multline"]);
    507       }
    508       this.table.push(this.row); this.row = [];
    509     },
    510     EndTable: function () {
    511       this.SUPER(arguments).EndTable.call(this);
    512       if (this.table.length) {
    513         var m = this.table.length-1, i, label = -1;
    514         if (!this.table[0][0].columnalign) {this.table[0][0].columnalign = MML.ALIGN.LEFT}
    515         if (!this.table[m][0].columnalign) {this.table[m][0].columnalign = MML.ALIGN.RIGHT}
    516         if (!this.global.tag && this.numbered) {this.autoTag()}
    517         if (this.global.tag && !this.global.notags) {
    518           label = (this.arraydef.side === "left" ? 0 : this.table.length - 1);
    519           this.table[label] = [this.getTag()].concat(this.table[label]);
    520         }
    521         for (i = 0, m = this.table.length; i < m; i++) {
    522           var mtr = (i === label ? MML.mlabeledtr : MML.mtr);
    523           this.table[i] = mtr.apply(MML,this.table[i]);
    524         }
    525       }
    526       this.global.notag  = this.save.notag;
    527     }
    528   });
    529   
    530   /*
    531    *  Save data about numbering and taging equations, and add
    532    *  tags at the ends of rows.
    533    */
    534   STACKITEM.AMSarray = STACKITEM.array.Subclass({
    535     type: "AMSarray",
    536     Init: function (name,numbered,taggable,stack) {
    537       this.SUPER(arguments).Init.apply(this);
    538       this.numbered = (numbered && CONFIG.autoNumber !== "none");
    539       this.save = {notags: stack.global.notags, notag: stack.global.notag};
    540       stack.global.notags = (taggable ? null : name);
    541       stack.global.tagged = !numbered && !stack.global.forcetag; // prevent automatic tagging in starred environments
    542     },
    543     EndEntry: function () {
    544       if (this.row.length) {this.fixInitialMO(this.data)}
    545       this.row.push(MML.mtd.apply(MML,this.data));
    546       this.data = [];
    547     },
    548     EndRow: function () {
    549       var mtr = MML.mtr;
    550       if (!this.global.tag && this.numbered) {this.autoTag()}
    551       if (this.global.tag && !this.global.notags) {
    552         this.row = [this.getTag()].concat(this.row);
    553         mtr = MML.mlabeledtr;
    554       } else {this.clearTag()}
    555       if (this.numbered) {delete this.global.notag}
    556       this.table.push(mtr.apply(MML,this.row)); this.row = [];
    557     },
    558     EndTable: function () {
    559       this.SUPER(arguments).EndTable.call(this);
    560       this.global.notags = this.save.notags;
    561       this.global.notag  = this.save.notag;
    562     }
    563   });
    564   
    565   //
    566   //  Look for \tag on a formula and make an mtable to include it
    567   //
    568   STACKITEM.start.Augment({
    569     oldCheckItem: STACKITEM.start.prototype.checkItem,
    570     checkItem: function (item) {
    571       if (item.type === "stop") {
    572         var mml = this.mmlData(), global = this.global;
    573         if (AMS.display && !global.tag && !global.tagged && !global.isInner &&
    574             (CONFIG.autoNumber === "all" || global.forcetag)) {this.autoTag()}
    575         if (global.tag) {
    576           var row = [this.getTag(),MML.mtd(mml)];
    577           var def = {
    578             side: TEX.config.TagSide,
    579             minlabelspacing: TEX.config.TagIndent,
    580             displaystyle: "inherit"   // replaced by TeX input jax Translate() function with actual value
    581           };
    582           mml = MML.mtable(MML.mlabeledtr.apply(MML,row)).With(def);
    583         }
    584         return STACKITEM.mml(mml);
    585       }
    586       return this.oldCheckItem.call(this,item);
    587     }
    588   });
    589   
    590   /******************************************************************************/
    591 
    592   /*
    593    *  Add pre- and post-filters to handle the equation number maintainance.
    594    */
    595   TEX.prefilterHooks.Add(function (data) {
    596     AMS.display = data.display;
    597     AMS.number = AMS.startNumber;  // reset equation numbers (in case the equation restarted)
    598     AMS.eqlabels = AMS.eqIDs = {}; AMS.badref = false;
    599     if (AMS.refUpdate) {AMS.number = data.script.MathJax.startNumber}
    600   });
    601   TEX.postfilterHooks.Add(function (data) {
    602     data.script.MathJax.startNumber = AMS.startNumber;
    603     AMS.startNumber = AMS.number;                // equation numbers for next equation
    604     MathJax.Hub.Insert(AMS.IDs,AMS.eqIDs);       // save IDs from this equation
    605     MathJax.Hub.Insert(AMS.labels,AMS.eqlabels); // save labels from this equation
    606     if (AMS.badref && !data.math.texError) {AMS.refs.push(data.script)}  // reprocess later
    607   },100);
    608   
    609   MathJax.Hub.Register.MessageHook("Begin Math Input",function () {
    610     AMS.refs = [];                 // array of jax with bad references
    611     AMS.refUpdate = false;
    612   });
    613   MathJax.Hub.Register.MessageHook("End Math Input",function (message) {
    614     if (AMS.refs.length) {
    615       AMS.refUpdate = true;
    616       for (var i = 0, m = AMS.refs.length; i < m; i++)
    617         {AMS.refs[i].MathJax.state = MathJax.ElementJax.STATE.UPDATE}
    618       return MathJax.Hub.processInput({
    619         scripts:AMS.refs,
    620         start: new Date().getTime(),
    621         i:0, j:0, jax:{}, jaxIDs:[]
    622       });
    623     }
    624     return null;
    625   });
    626   
    627   //
    628   //  Clear the equation numbers and labels
    629   //
    630   TEX.resetEquationNumbers = function (n,keepLabels) {
    631     AMS.startNumber = (n || 0);
    632     if (!keepLabels) {AMS.labels = AMS.IDs = {}}
    633   }
    634 
    635   /******************************************************************************/
    636 
    637   MathJax.Hub.Startup.signal.Post("TeX AMSmath Ready");
    638   
    639 });
    640 
    641 MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/AMSmath.js");