AMSmath.js 24 KB

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