AMSmath.js 24 KB

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