PageRenderTime 33ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/talk2/mathjax/unpacked/jax/input/TeX/jax.js

https://github.com/williamstein/mazur-explicit-formula
JavaScript | 2095 lines | 1812 code | 147 blank | 136 comment | 343 complexity | c24e204f5491d4128de12342506cce71 MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, MIT
  1. /*************************************************************
  2. *
  3. * MathJax/jax/input/TeX/jax.js
  4. *
  5. * Implements the TeX InputJax that reads mathematics in
  6. * TeX and LaTeX format and converts it to the MML ElementJax
  7. * internal format.
  8. *
  9. * ---------------------------------------------------------------------
  10. *
  11. * Copyright (c) 2009-2012 Design Science, Inc.
  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. (function (TEX,HUB,AJAX) {
  26. var MML, NBSP = "\u00A0";
  27. var STACK = MathJax.Object.Subclass({
  28. Init: function (env,inner) {
  29. this.global = {isInner: inner};
  30. this.data = [STACKITEM.start(this.global)];
  31. if (env) {this.data[0].env = env}
  32. this.env = this.data[0].env;
  33. },
  34. Push: function () {
  35. var i, m, item, top;
  36. for (i = 0, m = arguments.length; i < m; i++) {
  37. item = arguments[i];
  38. if (item instanceof MML.mbase) {item = STACKITEM.mml(item)}
  39. item.global = this.global;
  40. top = (this.data.length ? this.Top().checkItem(item) : true);
  41. if (top instanceof Array) {this.Pop(); this.Push.apply(this,top)}
  42. else if (top instanceof STACKITEM) {this.Pop(); this.Push(top)}
  43. else if (top) {
  44. this.data.push(item);
  45. if (item.env) {
  46. for (var id in this.env)
  47. {if (this.env.hasOwnProperty(id)) {item.env[id] = this.env[id]}}
  48. this.env = item.env;
  49. } else {item.env = this.env}
  50. }
  51. }
  52. },
  53. Pop: function () {
  54. var item = this.data.pop(); if (!item.isOpen) {delete item.env}
  55. this.env = (this.data.length ? this.Top().env : {});
  56. return item;
  57. },
  58. Top: function (n) {
  59. if (n == null) {n = 1}
  60. if (this.data.length < n) {return null}
  61. return this.data[this.data.length-n];
  62. },
  63. Prev: function (noPop) {
  64. var top = this.Top();
  65. if (noPop) {return top.data[top.data.length-1]}
  66. else {return top.Pop()}
  67. },
  68. toString: function () {return "stack[\n "+this.data.join("\n ")+"\n]"}
  69. });
  70. var STACKITEM = STACK.Item = MathJax.Object.Subclass({
  71. type: "base",
  72. closeError: "Extra close brace or missing open brace",
  73. rightError: "Missing \\left or extra \\right",
  74. Init: function () {
  75. if (this.isOpen) {this.env = {}}
  76. this.data = [];
  77. this.Push.apply(this,arguments);
  78. },
  79. Push: function () {this.data.push.apply(this.data,arguments)},
  80. Pop: function () {return this.data.pop()},
  81. mmlData: function (inferred,forceRow) {
  82. if (inferred == null) {inferred = true}
  83. if (this.data.length === 1 && !forceRow) {return this.data[0]}
  84. return MML.mrow.apply(MML,this.data).With((inferred ? {inferred: true}: {}));
  85. },
  86. checkItem: function (item) {
  87. if (item.type === "over" && this.isOpen) {item.num = this.mmlData(false); this.data = []}
  88. if (item.type === "cell" && this.isOpen) {
  89. if (item.linebreak) {return false}
  90. TEX.Error("Misplaced "+item.name);
  91. }
  92. if (item.isClose && this[item.type+"Error"]) {TEX.Error(this[item.type+"Error"])}
  93. if (!item.isNotStack) {return true}
  94. this.Push(item.data[0]); return false;
  95. },
  96. With: function (def) {
  97. for (var id in def) {if (def.hasOwnProperty(id)) {this[id] = def[id]}}
  98. return this;
  99. },
  100. toString: function () {return this.type+"["+this.data.join("; ")+"]"}
  101. });
  102. STACKITEM.start = STACKITEM.Subclass({
  103. type: "start", isOpen: true,
  104. Init: function (global) {
  105. this.SUPER(arguments).Init.call(this);
  106. this.global = global;
  107. },
  108. checkItem: function (item) {
  109. if (item.type === "stop") {return STACKITEM.mml(this.mmlData())}
  110. return this.SUPER(arguments).checkItem.call(this,item);
  111. }
  112. });
  113. STACKITEM.stop = STACKITEM.Subclass({
  114. type: "stop", isClose: true
  115. });
  116. STACKITEM.open = STACKITEM.Subclass({
  117. type: "open", isOpen: true,
  118. stopError: "Extra open brace or missing close brace",
  119. checkItem: function (item) {
  120. if (item.type === "close") {
  121. var mml = this.mmlData(); // this.mmlData(true,true); // force row
  122. return STACKITEM.mml(MML.TeXAtom(mml)); // TeXAtom make it an ORD to prevent spacing (FIXME: should be another way)
  123. }
  124. return this.SUPER(arguments).checkItem.call(this,item);
  125. }
  126. });
  127. STACKITEM.close = STACKITEM.Subclass({
  128. type: "close", isClose: true
  129. });
  130. STACKITEM.prime = STACKITEM.Subclass({
  131. type: "prime",
  132. checkItem: function (item) {
  133. if (this.data[0].type !== "msubsup")
  134. {return [MML.msup(this.data[0],this.data[1]),item]}
  135. this.data[0].SetData(this.data[0].sup,this.data[1]);
  136. return [this.data[0],item];
  137. }
  138. });
  139. STACKITEM.subsup = STACKITEM.Subclass({
  140. type: "subsup",
  141. stopError: "Missing superscript or subscript argument",
  142. checkItem: function (item) {
  143. var script = ["","subscript","superscript"][this.position];
  144. if (item.type === "open" || item.type === "left") {return true}
  145. if (item.type === "mml") {
  146. if (this.primes) {
  147. if (this.position !== 2) {this.data[0].SetData(2,this.primes)}
  148. else {item.data[0] = MML.mrow(this.primes.With({variantForm:true}),item.data[0])}
  149. }
  150. this.data[0].SetData(this.position,item.data[0]);
  151. return STACKITEM.mml(this.data[0]);
  152. }
  153. if (this.SUPER(arguments).checkItem.call(this,item))
  154. {TEX.Error("Missing open brace for "+script)}
  155. },
  156. Pop: function () {}
  157. });
  158. STACKITEM.over = STACKITEM.Subclass({
  159. type: "over", isClose: true, name: "\\over",
  160. checkItem: function (item,stack) {
  161. if (item.type === "over") {TEX.Error("Ambiguous use of "+item.name)}
  162. if (item.isClose) {
  163. var mml = MML.mfrac(this.num,this.mmlData(false));
  164. if (this.thickness != null) {mml.linethickness = this.thickness}
  165. if (this.open || this.close) {
  166. mml.texClass = MML.TEXCLASS.INNER;
  167. mml.texWithDelims = true;
  168. mml = MML.mfenced(mml).With({open: this.open, close: this.close});
  169. }
  170. return [STACKITEM.mml(mml), item];
  171. }
  172. return this.SUPER(arguments).checkItem.call(this,item);
  173. },
  174. toString: function () {return "over["+this.num+" / "+this.data.join("; ")+"]"}
  175. });
  176. STACKITEM.left = STACKITEM.Subclass({
  177. type: "left", isOpen: true, delim: '(',
  178. stopError: "Extra \\left or missing \\right",
  179. checkItem: function (item) {
  180. if (item.type === "right") {
  181. var mml = MML.mfenced(this.data.length === 1 ? this.data[0] : MML.mrow.apply(MML,this.data));
  182. return STACKITEM.mml(mml.With({open: this.delim, close: item.delim}));
  183. }
  184. return this.SUPER(arguments).checkItem.call(this,item);
  185. }
  186. });
  187. STACKITEM.right = STACKITEM.Subclass({
  188. type: "right", isClose: true, delim: ')'
  189. });
  190. STACKITEM.begin = STACKITEM.Subclass({
  191. type: "begin", isOpen: true,
  192. checkItem: function (item) {
  193. if (item.type === "end") {
  194. if (item.name !== this.name)
  195. {TEX.Error("\\begin{"+this.name+"} ended with \\end{"+item.name+"}")}
  196. if (!this.end) {return STACKITEM.mml(this.mmlData())}
  197. return this.parse[this.end].call(this.parse,this,this.data);
  198. }
  199. if (item.type === "stop") {TEX.Error("Missing \\end{"+this.name+"}")}
  200. return this.SUPER(arguments).checkItem.call(this,item);
  201. }
  202. });
  203. STACKITEM.end = STACKITEM.Subclass({
  204. type: "end", isClose: true
  205. });
  206. STACKITEM.style = STACKITEM.Subclass({
  207. type: "style",
  208. checkItem: function (item) {
  209. if (!item.isClose) {return this.SUPER(arguments).checkItem.call(this,item)}
  210. var mml = MML.mstyle.apply(MML,this.data).With(this.styles);
  211. return [STACKITEM.mml(mml),item];
  212. }
  213. });
  214. STACKITEM.position = STACKITEM.Subclass({
  215. type: "position",
  216. checkItem: function (item) {
  217. if (item.isClose) {TEX.Error("Missing box for "+this.name)}
  218. if (item.isNotStack) {
  219. var mml = item.mmlData();
  220. switch (this.move) {
  221. case 'vertical':
  222. mml = MML.mpadded(mml).With({height: this.dh, depth: this.dd, voffset: this.dh});
  223. return [STACKITEM.mml(mml)];
  224. case 'horizontal':
  225. return [STACKITEM.mml(this.left),item,STACKITEM.mml(this.right)];
  226. }
  227. }
  228. return this.SUPER(arguments).checkItem.call(this,item);
  229. }
  230. });
  231. STACKITEM.array = STACKITEM.Subclass({
  232. type: "array", isOpen: true, arraydef: {},
  233. Init: function () {
  234. this.table = []; this.row = []; this.env = {}; this.frame = []
  235. this.SUPER(arguments).Init.apply(this,arguments);
  236. },
  237. checkItem: function (item) {
  238. if (item.isClose && item.type !== "over") {
  239. if (item.isEntry) {this.EndEntry(); this.clearEnv(); return false}
  240. if (item.isCR) {this.EndEntry(); this.EndRow(); this.clearEnv(); return false}
  241. this.EndTable(); this.clearEnv();
  242. var mml = MML.mtable.apply(MML,this.table).With(this.arraydef);
  243. if (this.frame.length === 4) {
  244. mml.frame = (this.frame.dashed ? "dashed" : "solid");
  245. } else if (this.frame.length) {
  246. mml.hasFrame = true;
  247. if (this.arraydef.rowlines) {this.arraydef.rowlines = this.arraydef.rowlines.replace(/none( none)+$/,"none")}
  248. mml = MML.menclose(mml).With({notation: this.frame.join(" "), isFrame: true});
  249. if ((this.arraydef.columnlines||"none") != "none" ||
  250. (this.arraydef.rowlines||"none") != "none") {mml.padding = 0} // HTML-CSS jax implements this
  251. }
  252. if (this.open || this.close) {
  253. mml = MML.mfenced(mml).With({open: this.open, close: this.close});
  254. }
  255. mml = STACKITEM.mml(mml);
  256. if (this.requireClose) {
  257. if (item.type === 'close') {return mml}
  258. TEX.Error("Missing close brace");
  259. }
  260. return [mml,item];
  261. }
  262. return this.SUPER(arguments).checkItem.call(this,item);
  263. },
  264. EndEntry: function () {this.row.push(MML.mtd.apply(MML,this.data)); this.data = []},
  265. EndRow: function () {this.table.push(MML.mtr.apply(MML,this.row)); this.row = []},
  266. EndTable: function () {
  267. if (this.data.length || this.row.length) {this.EndEntry(); this.EndRow()}
  268. this.checkLines();
  269. },
  270. checkLines: function () {
  271. if (this.arraydef.rowlines) {
  272. var lines = this.arraydef.rowlines.split(/ /);
  273. if (lines.length === this.table.length) {
  274. this.frame.push("bottom"); lines.pop();
  275. this.arraydef.rowlines = lines.join(' ');
  276. } else if (lines.length < this.table.length-1) {
  277. this.arraydef.rowlines += " none";
  278. }
  279. }
  280. if (this.rowspacing) {
  281. var rows = this.arraydef.rowspacing.split(/ /);
  282. while (rows.length < this.table.length) {rows.push(this.rowspacing+"em")}
  283. this.arraydef.rowspacing = rows.join(' ');
  284. }
  285. },
  286. clearEnv: function () {
  287. for (var id in this.env) {if (this.env.hasOwnProperty(id)) {delete this.env[id]}}
  288. }
  289. });
  290. STACKITEM.cell = STACKITEM.Subclass({
  291. type: "cell", isClose: true
  292. });
  293. STACKITEM.mml = STACKITEM.Subclass({
  294. type: "mml", isNotStack: true,
  295. Add: function () {this.data.push.apply(this.data,arguments); return this}
  296. });
  297. STACKITEM.fn = STACKITEM.Subclass({
  298. type: "fn",
  299. checkItem: function (item) {
  300. if (this.data[0]) {
  301. if (item.type !== "mml" || !item.data[0]) {return [this.data[0],item]}
  302. if (item.data[0].isa(MML.mspace)) {return [this.data[0],item]}
  303. var mml = item.data[0]; if (mml.isEmbellished()) {mml = mml.CoreMO()}
  304. if ([0,0,1,1,0,1,1,0,0,0][mml.Get("texClass")]) {return [this.data[0],item]}
  305. return [this.data[0],MML.mo(MML.entity("#x2061")).With({texClass:MML.TEXCLASS.NONE}),item];
  306. }
  307. return this.SUPER(arguments).checkItem.apply(this,arguments);
  308. }
  309. });
  310. STACKITEM.not = STACKITEM.Subclass({
  311. type: "not",
  312. checkItem: function (item) {
  313. var mml, c;
  314. if (item.type === "open" || item.type === "left") {return true}
  315. if (item.type === "mml" && item.data[0].type.match(/^(mo|mi|mtext)$/)) {
  316. mml = item.data[0], c = mml.data.join("");
  317. if (c.length === 1 && !mml.movesupsub) {
  318. c = STACKITEM.not.remap[c.charCodeAt(0)];
  319. if (c) {mml.SetData(0,MML.chars(String.fromCharCode(c)))}
  320. else {mml.Append(MML.chars("\u0338"))}
  321. return item;
  322. }
  323. }
  324. // \mathrel{\rlap{\notChar}}
  325. mml = MML.mpadded(MML.mtext("\u29F8")).With({width:0});
  326. mml = MML.TeXAtom(mml).With({texClass:MML.TEXCLASS.REL});
  327. return [mml,item];
  328. }
  329. });
  330. STACKITEM.not.remap = {
  331. 0x2190:0x219A, 0x2192:0x219B, 0x2194:0x21AE,
  332. 0x21D0:0x21CD, 0x21D2:0x21CF, 0x21D4:0x21CE,
  333. 0x2208:0x2209, 0x220B:0x220C, 0x2223:0x2224, 0x2225:0x2226,
  334. 0x223C:0x2241, 0x007E:0x2241, 0x2243:0x2244, 0x2245:0x2247,
  335. 0x2248:0x2249, 0x224D:0x226D, 0x003D:0x2260, 0x2261:0x2262,
  336. 0x003C:0x226E, 0x003E:0x226F, 0x2264:0x2270, 0x2265:0x2271,
  337. 0x2272:0x2274, 0x2273:0x2275, 0x2276:0x2278, 0x2277:0x2279,
  338. 0x227A:0x2280, 0x227B:0x2281, 0x2282:0x2284, 0x2283:0x2285,
  339. 0x2286:0x2288, 0x2287:0x2289, 0x22A2:0x22AC, 0x22A8:0x22AD,
  340. 0x22A9:0x22AE, 0x22AB:0x22AF, 0x227C:0x22E0, 0x227D:0x22E1,
  341. 0x2291:0x22E2, 0x2292:0x22E3, 0x22B2:0x22EA, 0x22B3:0x22EB,
  342. 0x22B4:0x22EC, 0x22B5:0x22ED, 0x2203:0x2204
  343. };
  344. STACKITEM.dots = STACKITEM.Subclass({
  345. type: "dots",
  346. checkItem: function (item) {
  347. if (item.type === "open" || item.type === "left") {return true}
  348. var dots = this.ldots;
  349. if (item.type === "mml" && item.data[0].isEmbellished()) {
  350. var tclass = item.data[0].CoreMO().Get("texClass");
  351. if (tclass === MML.TEXCLASS.BIN || tclass === MML.TEXCLASS.REL) {dots = this.cdots}
  352. }
  353. return [dots,item];
  354. }
  355. });
  356. var TEXDEF = {
  357. //
  358. // Add new definitions without overriding user-defined ones
  359. //
  360. Add: function (src,dst,nouser) {
  361. if (!dst) {dst = this}
  362. for (var id in src) {if (src.hasOwnProperty(id)) {
  363. if (typeof src[id] === 'object' && !(src[id] instanceof Array) &&
  364. (typeof dst[id] === 'object' || typeof dst[id] === 'function'))
  365. {this.Add(src[id],dst[id],src[id],nouser)}
  366. else if (!dst[id] || !dst[id].isUser || !nouser) {dst[id] = src[id]}
  367. }}
  368. return dst;
  369. }
  370. };
  371. var STARTUP = function () {
  372. MML = MathJax.ElementJax.mml;
  373. HUB.Insert(TEXDEF,{
  374. // patterns for letters and numbers
  375. letter: /[a-z]/i,
  376. digit: /[0-9.]/,
  377. number: /^(?:[0-9]+(?:\{,\}[0-9]{3})*(?:\.[0-9]*)*|\.[0-9]+)/,
  378. special: {
  379. '\\': 'ControlSequence',
  380. '{': 'Open',
  381. '}': 'Close',
  382. '~': 'Tilde',
  383. '^': 'Superscript',
  384. '_': 'Subscript',
  385. ' ': 'Space',
  386. "\t": 'Space',
  387. "\r": 'Space',
  388. "\n": 'Space',
  389. "'": 'Prime',
  390. '%': 'Comment',
  391. '&': 'Entry',
  392. '#': 'Hash',
  393. '\u2019': 'Prime'
  394. },
  395. remap: {
  396. '-': '2212',
  397. '*': '2217'
  398. },
  399. mathchar0mi: {
  400. // Lower-case greek
  401. alpha: '03B1',
  402. beta: '03B2',
  403. gamma: '03B3',
  404. delta: '03B4',
  405. epsilon: '03F5',
  406. zeta: '03B6',
  407. eta: '03B7',
  408. theta: '03B8',
  409. iota: '03B9',
  410. kappa: '03BA',
  411. lambda: '03BB',
  412. mu: '03BC',
  413. nu: '03BD',
  414. xi: '03BE',
  415. omicron: '03BF', // added for completeness
  416. pi: '03C0',
  417. rho: '03C1',
  418. sigma: '03C3',
  419. tau: '03C4',
  420. upsilon: '03C5',
  421. phi: '03D5',
  422. chi: '03C7',
  423. psi: '03C8',
  424. omega: '03C9',
  425. varepsilon: '03B5',
  426. vartheta: '03D1',
  427. varpi: '03D6',
  428. varrho: '03F1',
  429. varsigma: '03C2',
  430. varphi: '03C6',
  431. // Ord symbols
  432. S: ['00A7',{mathvariant: MML.VARIANT.NORMAL}],
  433. aleph: ['2135',{mathvariant: MML.VARIANT.NORMAL}],
  434. hbar: ['210F',{variantForm:true}],
  435. imath: '0131',
  436. jmath: '0237',
  437. ell: '2113',
  438. wp: ['2118',{mathvariant: MML.VARIANT.NORMAL}],
  439. Re: ['211C',{mathvariant: MML.VARIANT.NORMAL}],
  440. Im: ['2111',{mathvariant: MML.VARIANT.NORMAL}],
  441. partial: ['2202',{mathvariant: MML.VARIANT.NORMAL}],
  442. infty: ['221E',{mathvariant: MML.VARIANT.NORMAL}],
  443. prime: ['2032',{mathvariant: MML.VARIANT.NORMAL, variantForm:true}],
  444. emptyset: ['2205',{mathvariant: MML.VARIANT.NORMAL}],
  445. nabla: ['2207',{mathvariant: MML.VARIANT.NORMAL}],
  446. top: ['22A4',{mathvariant: MML.VARIANT.NORMAL}],
  447. bot: ['22A5',{mathvariant: MML.VARIANT.NORMAL}],
  448. angle: ['2220',{mathvariant: MML.VARIANT.NORMAL}],
  449. triangle: ['25B3',{mathvariant: MML.VARIANT.NORMAL}],
  450. backslash: ['2216',{mathvariant: MML.VARIANT.NORMAL, variantForm:true}],
  451. forall: ['2200',{mathvariant: MML.VARIANT.NORMAL}],
  452. exists: ['2203',{mathvariant: MML.VARIANT.NORMAL}],
  453. neg: ['00AC',{mathvariant: MML.VARIANT.NORMAL}],
  454. lnot: ['00AC',{mathvariant: MML.VARIANT.NORMAL}],
  455. flat: ['266D',{mathvariant: MML.VARIANT.NORMAL}],
  456. natural: ['266E',{mathvariant: MML.VARIANT.NORMAL}],
  457. sharp: ['266F',{mathvariant: MML.VARIANT.NORMAL}],
  458. clubsuit: ['2663',{mathvariant: MML.VARIANT.NORMAL}],
  459. diamondsuit: ['2662',{mathvariant: MML.VARIANT.NORMAL}],
  460. heartsuit: ['2661',{mathvariant: MML.VARIANT.NORMAL}],
  461. spadesuit: ['2660',{mathvariant: MML.VARIANT.NORMAL}]
  462. },
  463. mathchar0mo: {
  464. surd: '221A',
  465. // big ops
  466. coprod: ['2210',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  467. bigvee: ['22C1',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  468. bigwedge: ['22C0',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  469. biguplus: ['2A04',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  470. bigcap: ['22C2',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  471. bigcup: ['22C3',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  472. 'int': ['222B',{texClass: MML.TEXCLASS.OP}],
  473. intop: ['222B',{texClass: MML.TEXCLASS.OP, movesupsub:true, movablelimits:true}],
  474. iint: ['222C',{texClass: MML.TEXCLASS.OP}],
  475. iiint: ['222D',{texClass: MML.TEXCLASS.OP}],
  476. prod: ['220F',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  477. sum: ['2211',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  478. bigotimes: ['2A02',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  479. bigoplus: ['2A01',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  480. bigodot: ['2A00',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  481. oint: ['222E',{texClass: MML.TEXCLASS.OP}],
  482. bigsqcup: ['2A06',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
  483. smallint: ['222B',{largeop:false}],
  484. // binary operations
  485. triangleleft: '25C3',
  486. triangleright: '25B9',
  487. bigtriangleup: '25B3',
  488. bigtriangledown: '25BD',
  489. wedge: '2227',
  490. land: '2227',
  491. vee: '2228',
  492. lor: '2228',
  493. cap: '2229',
  494. cup: '222A',
  495. ddagger: '2021',
  496. dagger: '2020',
  497. sqcap: '2293',
  498. sqcup: '2294',
  499. uplus: '228E',
  500. amalg: '2A3F',
  501. diamond: '22C4',
  502. bullet: '2219',
  503. wr: '2240',
  504. div: '00F7',
  505. odot: ['2299',{largeop: false}],
  506. oslash: ['2298',{largeop: false}],
  507. otimes: ['2297',{largeop: false}],
  508. ominus: ['2296',{largeop: false}],
  509. oplus: ['2295',{largeop: false}],
  510. mp: '2213',
  511. pm: '00B1',
  512. circ: '2218',
  513. bigcirc: '25EF',
  514. setminus: ['2216',{variantForm:true}],
  515. cdot: '22C5',
  516. ast: '2217',
  517. times: '00D7',
  518. star: '22C6',
  519. // Relations
  520. propto: '221D',
  521. sqsubseteq: '2291',
  522. sqsupseteq: '2292',
  523. parallel: '2225',
  524. mid: '2223',
  525. dashv: '22A3',
  526. vdash: '22A2',
  527. leq: '2264',
  528. le: '2264',
  529. geq: '2265',
  530. ge: '2265',
  531. lt: '003C',
  532. gt: '003E',
  533. succ: '227B',
  534. prec: '227A',
  535. approx: '2248',
  536. succeq: '2AB0', // or '227C',
  537. preceq: '2AAF', // or '227D',
  538. supset: '2283',
  539. subset: '2282',
  540. supseteq: '2287',
  541. subseteq: '2286',
  542. 'in': '2208',
  543. ni: '220B',
  544. notin: '2209',
  545. owns: '220B',
  546. gg: '226B',
  547. ll: '226A',
  548. sim: '223C',
  549. simeq: '2243',
  550. perp: '22A5',
  551. equiv: '2261',
  552. asymp: '224D',
  553. smile: '2323',
  554. frown: '2322',
  555. ne: '2260',
  556. neq: '2260',
  557. cong: '2245',
  558. doteq: '2250',
  559. bowtie: '22C8',
  560. models: '22A8',
  561. notChar: '29F8',
  562. // Arrows
  563. Leftrightarrow: '21D4',
  564. Leftarrow: '21D0',
  565. Rightarrow: '21D2',
  566. leftrightarrow: '2194',
  567. leftarrow: '2190',
  568. gets: '2190',
  569. rightarrow: '2192',
  570. to: '2192',
  571. mapsto: '21A6',
  572. leftharpoonup: '21BC',
  573. leftharpoondown: '21BD',
  574. rightharpoonup: '21C0',
  575. rightharpoondown: '21C1',
  576. nearrow: '2197',
  577. searrow: '2198',
  578. nwarrow: '2196',
  579. swarrow: '2199',
  580. rightleftharpoons: '21CC',
  581. hookrightarrow: '21AA',
  582. hookleftarrow: '21A9',
  583. longleftarrow: '27F5',
  584. Longleftarrow: '27F8',
  585. longrightarrow: '27F6',
  586. Longrightarrow: '27F9',
  587. Longleftrightarrow: '27FA',
  588. longleftrightarrow: '27F7',
  589. longmapsto: '27FC',
  590. // Misc.
  591. ldots: '2026',
  592. cdots: '22EF',
  593. vdots: '22EE',
  594. ddots: '22F1',
  595. dotsc: '2026', // dots with commas
  596. dotsb: '22EF', // dots with binary ops and relations
  597. dotsm: '22EF', // dots with multiplication
  598. dotsi: '22EF', // dots with integrals
  599. dotso: '2026', // other dots
  600. ldotp: ['002E', {texClass: MML.TEXCLASS.PUNCT}],
  601. cdotp: ['22C5', {texClass: MML.TEXCLASS.PUNCT}],
  602. colon: ['003A', {texClass: MML.TEXCLASS.PUNCT}]
  603. },
  604. mathchar7: {
  605. Gamma: '0393',
  606. Delta: '0394',
  607. Theta: '0398',
  608. Lambda: '039B',
  609. Xi: '039E',
  610. Pi: '03A0',
  611. Sigma: '03A3',
  612. Upsilon: '03A5',
  613. Phi: '03A6',
  614. Psi: '03A8',
  615. Omega: '03A9',
  616. '_': '005F',
  617. '#': '0023',
  618. '$': '0024',
  619. '%': '0025',
  620. '&': '0026',
  621. And: '0026'
  622. },
  623. delimiter: {
  624. '(': '(',
  625. ')': ')',
  626. '[': '[',
  627. ']': ']',
  628. '<': '27E8',
  629. '>': '27E9',
  630. '\\lt': '27E8',
  631. '\\gt': '27E9',
  632. '/': '/',
  633. '|': ['|',{texClass:MML.TEXCLASS.ORD}],
  634. '.': '',
  635. '\\\\': '\\',
  636. '\\lmoustache': '23B0', // non-standard
  637. '\\rmoustache': '23B1', // non-standard
  638. '\\lgroup': '27EE', // non-standard
  639. '\\rgroup': '27EF', // non-standard
  640. '\\arrowvert': '23D0',
  641. '\\Arrowvert': '2016',
  642. '\\bracevert': '23AA', // non-standard
  643. '\\Vert': ['2225',{texClass:MML.TEXCLASS.ORD}],
  644. '\\|': ['2225',{texClass:MML.TEXCLASS.ORD}],
  645. '\\vert': ['|',{texClass:MML.TEXCLASS.ORD}],
  646. '\\uparrow': '2191',
  647. '\\downarrow': '2193',
  648. '\\updownarrow': '2195',
  649. '\\Uparrow': '21D1',
  650. '\\Downarrow': '21D3',
  651. '\\Updownarrow': '21D5',
  652. '\\backslash': '\\',
  653. '\\rangle': '27E9',
  654. '\\langle': '27E8',
  655. '\\rbrace': '}',
  656. '\\lbrace': '{',
  657. '\\}': '}',
  658. '\\{': '{',
  659. '\\rceil': '2309',
  660. '\\lceil': '2308',
  661. '\\rfloor': '230B',
  662. '\\lfloor': '230A',
  663. '\\lbrack': '[',
  664. '\\rbrack': ']'
  665. },
  666. macros: {
  667. displaystyle: ['SetStyle','D',true,0],
  668. textstyle: ['SetStyle','T',false,0],
  669. scriptstyle: ['SetStyle','S',false,1],
  670. scriptscriptstyle: ['SetStyle','SS',false,2],
  671. rm: ['SetFont',MML.VARIANT.NORMAL],
  672. mit: ['SetFont',MML.VARIANT.ITALIC],
  673. oldstyle: ['SetFont',MML.VARIANT.OLDSTYLE],
  674. cal: ['SetFont',MML.VARIANT.CALIGRAPHIC],
  675. it: ['SetFont',"-tex-mathit"], // needs special handling
  676. bf: ['SetFont',MML.VARIANT.BOLD],
  677. bbFont: ['SetFont',MML.VARIANT.DOUBLESTRUCK],
  678. scr: ['SetFont',MML.VARIANT.SCRIPT],
  679. frak: ['SetFont',MML.VARIANT.FRAKTUR],
  680. sf: ['SetFont',MML.VARIANT.SANSSERIF],
  681. tt: ['SetFont',MML.VARIANT.MONOSPACE],
  682. // font:
  683. tiny: ['SetSize',0.5],
  684. Tiny: ['SetSize',0.6], // non-standard
  685. scriptsize: ['SetSize',0.7],
  686. small: ['SetSize',0.85],
  687. normalsize: ['SetSize',1.0],
  688. large: ['SetSize',1.2],
  689. Large: ['SetSize',1.44],
  690. LARGE: ['SetSize',1.73],
  691. huge: ['SetSize',2.07],
  692. Huge: ['SetSize',2.49],
  693. arcsin: ['NamedFn'],
  694. arccos: ['NamedFn'],
  695. arctan: ['NamedFn'],
  696. arg: ['NamedFn'],
  697. cos: ['NamedFn'],
  698. cosh: ['NamedFn'],
  699. cot: ['NamedFn'],
  700. coth: ['NamedFn'],
  701. csc: ['NamedFn'],
  702. deg: ['NamedFn'],
  703. det: 'NamedOp',
  704. dim: ['NamedFn'],
  705. exp: ['NamedFn'],
  706. gcd: 'NamedOp',
  707. hom: ['NamedFn'],
  708. inf: 'NamedOp',
  709. ker: ['NamedFn'],
  710. lg: ['NamedFn'],
  711. lim: 'NamedOp',
  712. liminf: ['NamedOp','lim&thinsp;inf'],
  713. limsup: ['NamedOp','lim&thinsp;sup'],
  714. ln: ['NamedFn'],
  715. log: ['NamedFn'],
  716. max: 'NamedOp',
  717. min: 'NamedOp',
  718. Pr: 'NamedOp',
  719. sec: ['NamedFn'],
  720. sin: ['NamedFn'],
  721. sinh: ['NamedFn'],
  722. sup: 'NamedOp',
  723. tan: ['NamedFn'],
  724. tanh: ['NamedFn'],
  725. limits: ['Limits',1],
  726. nolimits: ['Limits',0],
  727. overline: ['UnderOver','00AF'],
  728. underline: ['UnderOver','005F'],
  729. overbrace: ['UnderOver','23DE',1],
  730. underbrace: ['UnderOver','23DF',1],
  731. overrightarrow: ['UnderOver','2192'],
  732. underrightarrow: ['UnderOver','2192'],
  733. overleftarrow: ['UnderOver','2190'],
  734. underleftarrow: ['UnderOver','2190'],
  735. overleftrightarrow: ['UnderOver','2194'],
  736. underleftrightarrow: ['UnderOver','2194'],
  737. overset: 'Overset',
  738. underset: 'Underset',
  739. stackrel: ['Macro','\\mathrel{\\mathop{#2}\\limits^{#1}}',2],
  740. over: 'Over',
  741. overwithdelims: 'Over',
  742. atop: 'Over',
  743. atopwithdelims: 'Over',
  744. above: 'Over',
  745. abovewithdelims: 'Over',
  746. brace: ['Over','{','}'],
  747. brack: ['Over','[',']'],
  748. choose: ['Over','(',')'],
  749. frac: 'Frac',
  750. sqrt: 'Sqrt',
  751. root: 'Root',
  752. uproot: ['MoveRoot','upRoot'],
  753. leftroot: ['MoveRoot','leftRoot'],
  754. left: 'LeftRight',
  755. right: 'LeftRight',
  756. middle: 'Middle',
  757. llap: 'Lap',
  758. rlap: 'Lap',
  759. raise: 'RaiseLower',
  760. lower: 'RaiseLower',
  761. moveleft: 'MoveLeftRight',
  762. moveright: 'MoveLeftRight',
  763. ',': ['Spacer',MML.LENGTH.THINMATHSPACE],
  764. ':': ['Spacer',MML.LENGTH.MEDIUMMATHSPACE], // for LaTeX
  765. '>': ['Spacer',MML.LENGTH.MEDIUMMATHSPACE],
  766. ';': ['Spacer',MML.LENGTH.THICKMATHSPACE],
  767. '!': ['Spacer',MML.LENGTH.NEGATIVETHINMATHSPACE],
  768. enspace: ['Spacer',".5em"],
  769. quad: ['Spacer',"1em"],
  770. qquad: ['Spacer',"2em"],
  771. thinspace: ['Spacer',MML.LENGTH.THINMATHSPACE],
  772. negthinspace: ['Spacer',MML.LENGTH.NEGATIVETHINMATHSPACE],
  773. hskip: 'Hskip',
  774. hspace: 'Hskip',
  775. kern: 'Hskip',
  776. mskip: 'Hskip',
  777. mspace: 'Hskip',
  778. mkern: 'Hskip',
  779. Rule: ['Rule'],
  780. Space: ['Rule','blank'],
  781. big: ['MakeBig',MML.TEXCLASS.ORD,0.85],
  782. Big: ['MakeBig',MML.TEXCLASS.ORD,1.15],
  783. bigg: ['MakeBig',MML.TEXCLASS.ORD,1.45],
  784. Bigg: ['MakeBig',MML.TEXCLASS.ORD,1.75],
  785. bigl: ['MakeBig',MML.TEXCLASS.OPEN,0.85],
  786. Bigl: ['MakeBig',MML.TEXCLASS.OPEN,1.15],
  787. biggl: ['MakeBig',MML.TEXCLASS.OPEN,1.45],
  788. Biggl: ['MakeBig',MML.TEXCLASS.OPEN,1.75],
  789. bigr: ['MakeBig',MML.TEXCLASS.CLOSE,0.85],
  790. Bigr: ['MakeBig',MML.TEXCLASS.CLOSE,1.15],
  791. biggr: ['MakeBig',MML.TEXCLASS.CLOSE,1.45],
  792. Biggr: ['MakeBig',MML.TEXCLASS.CLOSE,1.75],
  793. bigm: ['MakeBig',MML.TEXCLASS.REL,0.85],
  794. Bigm: ['MakeBig',MML.TEXCLASS.REL,1.15],
  795. biggm: ['MakeBig',MML.TEXCLASS.REL,1.45],
  796. Biggm: ['MakeBig',MML.TEXCLASS.REL,1.75],
  797. mathord: ['TeXAtom',MML.TEXCLASS.ORD],
  798. mathop: ['TeXAtom',MML.TEXCLASS.OP],
  799. mathopen: ['TeXAtom',MML.TEXCLASS.OPEN],
  800. mathclose: ['TeXAtom',MML.TEXCLASS.CLOSE],
  801. mathbin: ['TeXAtom',MML.TEXCLASS.BIN],
  802. mathrel: ['TeXAtom',MML.TEXCLASS.REL],
  803. mathpunct: ['TeXAtom',MML.TEXCLASS.PUNCT],
  804. mathinner: ['TeXAtom',MML.TEXCLASS.INNER],
  805. vcenter: ['TeXAtom',MML.TEXCLASS.VCENTER],
  806. mathchoice: ['Extension','mathchoice'],
  807. buildrel: 'BuildRel',
  808. hbox: ['HBox',0],
  809. text: 'HBox',
  810. mbox: ['HBox',0],
  811. fbox: 'FBox',
  812. strut: 'Strut',
  813. mathstrut: ['Macro','\\vphantom{(}'],
  814. phantom: 'Phantom',
  815. vphantom: ['Phantom',1,0],
  816. hphantom: ['Phantom',0,1],
  817. smash: 'Smash',
  818. acute: ['Accent', "00B4"], // or 0301 or 02CA
  819. grave: ['Accent', "0060"], // or 0300 or 02CB
  820. ddot: ['Accent', "00A8"], // or 0308
  821. tilde: ['Accent', "007E"], // or 0303 or 02DC
  822. bar: ['Accent', "00AF"], // or 0304 or 02C9
  823. breve: ['Accent', "02D8"], // or 0306
  824. check: ['Accent', "02C7"], // or 030C
  825. hat: ['Accent', "005E"], // or 0302 or 02C6
  826. vec: ['Accent', "2192"], // or 20D7
  827. dot: ['Accent', "02D9"], // or 0307
  828. widetilde: ['Accent', "007E",1], // or 0303 or 02DC
  829. widehat: ['Accent', "005E",1], // or 0302 or 02C6
  830. matrix: 'Matrix',
  831. array: 'Matrix',
  832. pmatrix: ['Matrix','(',')'],
  833. cases: ['Matrix','{','',"left left",null,".1em",null,true],
  834. eqalign: ['Matrix',null,null,"right left",MML.LENGTH.THICKMATHSPACE,".5em",'D'],
  835. displaylines: ['Matrix',null,null,"center",null,".5em",'D'],
  836. cr: 'Cr',
  837. '\\': 'CrLaTeX',
  838. newline: 'Cr',
  839. hline: ['HLine','solid'],
  840. hdashline: ['HLine','dashed'],
  841. // noalign: 'HandleNoAlign',
  842. eqalignno: ['Matrix',null,null,"right left right",MML.LENGTH.THICKMATHSPACE+" 3em",".5em",'D'],
  843. leqalignno: ['Matrix',null,null,"right left right",MML.LENGTH.THICKMATHSPACE+" 3em",".5em",'D'],
  844. // TeX substitution macros
  845. bmod: ['Macro','\\mathbin{\\mmlToken{mo}{mod}}'],
  846. pmod: ['Macro','\\pod{\\mmlToken{mi}{mod}\\kern 6mu #1}',1],
  847. mod: ['Macro','\\mathchoice{\\kern18mu}{\\kern12mu}{\\kern12mu}{\\kern12mu}\\mmlToken{mi}{mod}\\,\\,#1',1],
  848. pod: ['Macro','\\mathchoice{\\kern18mu}{\\kern8mu}{\\kern8mu}{\\kern8mu}(#1)',1],
  849. iff: ['Macro','\\;\\Longleftrightarrow\\;'],
  850. skew: ['Macro','{{#2{#3\\mkern#1mu}\\mkern-#1mu}{}}',3],
  851. mathcal: ['Macro','{\\cal #1}',1],
  852. mathscr: ['Macro','{\\scr #1}',1],
  853. mathrm: ['Macro','{\\rm #1}',1],
  854. mathbf: ['Macro','{\\bf #1}',1],
  855. mathbb: ['Macro','{\\bbFont #1}',1],
  856. Bbb: ['Macro','{\\bbFont #1}',1],
  857. mathit: ['Macro','{\\it #1}',1],
  858. mathfrak: ['Macro','{\\frak #1}',1],
  859. mathsf: ['Macro','{\\sf #1}',1],
  860. mathtt: ['Macro','{\\tt #1}',1],
  861. textrm: ['Macro','\\mathord{\\rm\\text{#1}}',1],
  862. textit: ['Macro','\\mathord{\\it{\\text{#1}}}',1],
  863. textbf: ['Macro','\\mathord{\\bf{\\text{#1}}}',1],
  864. pmb: ['Macro','\\rlap{#1}\\kern1px{#1}',1],
  865. TeX: ['Macro','T\\kern-.14em\\lower.5ex{E}\\kern-.115em X'],
  866. LaTeX: ['Macro','L\\kern-.325em\\raise.21em{\\scriptstyle{A}}\\kern-.17em\\TeX'],
  867. ' ': ['Macro','\\text{ }'],
  868. // Specially handled
  869. not: 'Not',
  870. dots: 'Dots',
  871. space: 'Tilde',
  872. // LaTeX
  873. begin: 'Begin',
  874. end: 'End',
  875. newcommand: ['Extension','newcommand'],
  876. renewcommand: ['Extension','newcommand'],
  877. newenvironment: ['Extension','newcommand'],
  878. renewenvironment: ['Extension','newcommand'],
  879. def: ['Extension','newcommand'],
  880. let: ['Extension','newcommand'],
  881. verb: ['Extension','verb'],
  882. boldsymbol: ['Extension','boldsymbol'],
  883. tag: ['Extension','AMSmath'],
  884. notag: ['Extension','AMSmath'],
  885. label: ['Extension','AMSmath'],
  886. ref: ['Extension','AMSmath'],
  887. eqref: ['Extension','AMSmath'],
  888. nonumber: ['Macro','\\notag'],
  889. // Extensions to TeX
  890. unicode: ['Extension','unicode'],
  891. color: 'Color',
  892. href: ['Extension','HTML'],
  893. 'class': ['Extension','HTML'],
  894. style: ['Extension','HTML'],
  895. cssId: ['Extension','HTML'],
  896. bbox: ['Extension','bbox'],
  897. mmlToken: 'MmlToken',
  898. require: 'Require'
  899. },
  900. environment: {
  901. array: ['AlignedArray'],
  902. matrix: ['Array',null,null,null,'c'],
  903. pmatrix: ['Array',null,'(',')','c'],
  904. bmatrix: ['Array',null,'[',']','c'],
  905. Bmatrix: ['Array',null,'\\{','\\}','c'],
  906. vmatrix: ['Array',null,'\\vert','\\vert','c'],
  907. Vmatrix: ['Array',null,'\\Vert','\\Vert','c'],
  908. cases: ['Array',null,'\\{','.','ll',null,".1em"],
  909. equation: [null,'Equation'],
  910. 'equation*': [null,'Equation'],
  911. eqnarray: ['ExtensionEnv',null,'AMSmath'],
  912. 'eqnarray*': ['ExtensionEnv',null,'AMSmath'],
  913. align: ['ExtensionEnv',null,'AMSmath'],
  914. 'align*': ['ExtensionEnv',null,'AMSmath'],
  915. aligned: ['ExtensionEnv',null,'AMSmath'],
  916. multline: ['ExtensionEnv',null,'AMSmath'],
  917. 'multline*': ['ExtensionEnv',null,'AMSmath'],
  918. split: ['ExtensionEnv',null,'AMSmath'],
  919. gather: ['ExtensionEnv',null,'AMSmath'],
  920. 'gather*': ['ExtensionEnv',null,'AMSmath'],
  921. gathered: ['ExtensionEnv',null,'AMSmath'],
  922. alignat: ['ExtensionEnv',null,'AMSmath'],
  923. 'alignat*': ['ExtensionEnv',null,'AMSmath'],
  924. alignedat: ['ExtensionEnv',null,'AMSmath']
  925. },
  926. p_height: 1.2 / .85 // cmex10 height plus depth over .85
  927. });
  928. //
  929. // Add macros defined in the configuration
  930. //
  931. if (this.config.Macros) {
  932. var MACROS = this.config.Macros;
  933. for (var id in MACROS) {if (MACROS.hasOwnProperty(id)) {
  934. if (typeof(MACROS[id]) === "string") {TEXDEF.macros[id] = ['Macro',MACROS[id]]}
  935. else {TEXDEF.macros[id] = ["Macro"].concat(MACROS[id])}
  936. TEXDEF.macros[id].isUser = true;
  937. }}
  938. }
  939. };
  940. /************************************************************************/
  941. /*
  942. * The TeX Parser
  943. */
  944. var PARSE = MathJax.Object.Subclass({
  945. Init: function (string,env) {
  946. this.string = string; this.i = 0; this.macroCount = 0;
  947. var ENV; if (env) {ENV = {}; for (var id in env) {if (env.hasOwnProperty(id)) {ENV[id] = env[id]}}}
  948. this.stack = TEX.Stack(ENV,!!env);
  949. this.Parse(); this.Push(STACKITEM.stop());
  950. },
  951. Parse: function () {
  952. var c, n;
  953. while (this.i < this.string.length) {
  954. c = this.string.charAt(this.i++); n = c.charCodeAt(0);
  955. if (n >= 0xD800 && n < 0xDC00) {c += this.string.charAt(this.i++)}
  956. if (TEXDEF.special[c]) {this[TEXDEF.special[c]](c)}
  957. else if (TEXDEF.letter.test(c)) {this.Variable(c)}
  958. else if (TEXDEF.digit.test(c)) {this.Number(c)}
  959. else {this.Other(c)}
  960. }
  961. },
  962. Push: function () {this.stack.Push.apply(this.stack,arguments)},
  963. mml: function () {
  964. if (this.stack.Top().type !== "mml") {return null}
  965. return this.stack.Top().data[0];
  966. },
  967. mmlToken: function (token) {return token}, // used by boldsymbol extension
  968. /************************************************************************/
  969. /*
  970. * Handle various token classes
  971. */
  972. /*
  973. * Lookup a control-sequence and process it
  974. */
  975. ControlSequence: function (c) {
  976. var name = this.GetCS(), macro = this.csFindMacro(name);
  977. if (macro) {
  978. if (!(macro instanceof Array)) {macro = [macro]}
  979. var fn = macro[0]; if (!(fn instanceof Function)) {fn = this[fn]}
  980. fn.apply(this,[c+name].concat(macro.slice(1)));
  981. } else if (TEXDEF.mathchar0mi[name]) {this.csMathchar0mi(name,TEXDEF.mathchar0mi[name])}
  982. else if (TEXDEF.mathchar0mo[name]) {this.csMathchar0mo(name,TEXDEF.mathchar0mo[name])}
  983. else if (TEXDEF.mathchar7[name]) {this.csMathchar7(name,TEXDEF.mathchar7[name])}
  984. else if (TEXDEF.delimiter["\\"+name] != null) {this.csDelimiter(name,TEXDEF.delimiter["\\"+name])}
  985. else {this.csUndefined(c+name)}
  986. },
  987. //
  988. // Look up a macro in the macros list
  989. // (overridden in begingroup extension)
  990. //
  991. csFindMacro: function (name) {return TEXDEF.macros[name]},
  992. //
  993. // Handle normal mathchar (as an mi)
  994. //
  995. csMathchar0mi: function (name,mchar) {
  996. var def = {mathvariant: MML.VARIANT.ITALIC};
  997. if (mchar instanceof Array) {def = mchar[1]; mchar = mchar[0]}
  998. this.Push(this.mmlToken(MML.mi(MML.entity("#x"+mchar)).With(def)));
  999. },
  1000. //
  1001. // Handle normal mathchar (as an mo)
  1002. //
  1003. csMathchar0mo: function (name,mchar) {
  1004. var def = {stretchy: false};
  1005. if (mchar instanceof Array) {def = mchar[1]; def.stretchy = false; mchar = mchar[0]}
  1006. this.Push(this.mmlToken(MML.mo(MML.entity("#x"+mchar)).With(def)));
  1007. },
  1008. //
  1009. // Handle mathchar in current family
  1010. //
  1011. csMathchar7: function (name,mchar) {
  1012. var def = {mathvariant: MML.VARIANT.NORMAL};
  1013. if (mchar instanceof Array) {def = mchar[1]; mchar = mchar[0]}
  1014. if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
  1015. this.Push(this.mmlToken(MML.mi(MML.entity("#x"+mchar)).With(def)));
  1016. },
  1017. //
  1018. // Handle delimiter
  1019. //
  1020. csDelimiter: function (name,delim) {
  1021. var def = {};
  1022. if (delim instanceof Array) {def = delim[1]; delim = delim[0]}
  1023. if (delim.length === 4) {delim = MML.entity('#x'+delim)} else {delim = MML.chars(delim)}
  1024. this.Push(this.mmlToken(MML.mo(delim).With({fence: false, stretchy: false}).With(def)));
  1025. },
  1026. //
  1027. // Handle undefined control sequence
  1028. // (overridden in noUndefined extension)
  1029. //
  1030. csUndefined: function (name) {
  1031. TEX.Error("Undefined control sequence "+name);
  1032. },
  1033. /*
  1034. * Handle a variable (a single letter)
  1035. */
  1036. Variable: function (c) {
  1037. var def = {}; if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
  1038. this.Push(this.mmlToken(MML.mi(MML.chars(c)).With(def)));
  1039. },
  1040. /*
  1041. * Determine the extent of a number (pattern may need work)
  1042. */
  1043. Number: function (c) {
  1044. var mml, n = this.string.slice(this.i-1).match(TEXDEF.number);
  1045. if (n) {mml = MML.mn(n[0].replace(/[{}]/g,"")); this.i += n[0].length - 1}
  1046. else {mml = MML.mo(MML.chars(c))}
  1047. if (this.stack.env.font) {mml.mathvariant = this.stack.env.font}
  1048. this.Push(this.mmlToken(mml));
  1049. },
  1050. /*
  1051. * Handle { and }
  1052. */
  1053. Open: function (c) {this.Push(STACKITEM.open())},
  1054. Close: function (c) {this.Push(STACKITEM.close())},
  1055. /*
  1056. * Handle tilde and spaces
  1057. */
  1058. Tilde: function (c) {this.Push(MML.mtext(MML.chars(NBSP)))},
  1059. Space: function (c) {},
  1060. /*
  1061. * Handle ^, _, and '
  1062. */
  1063. Superscript: function (c) {
  1064. if (this.GetNext().match(/\d/)) // don't treat numbers as a unit
  1065. {this.string = this.string.substr(0,this.i+1)+" "+this.string.substr(this.i+1)}
  1066. var position, primes, base, top = this.stack.Top();
  1067. if (top.type === "prime") {base = top.data[0]; primes = top.data[1]; this.stack.Pop()}
  1068. else {base = this.stack.Prev(); if (!base) {base = MML.mi("")}}
  1069. if (base.isEmbellishedWrapper) {base = base.data[0].data[0]}
  1070. if (base.type === "msubsup") {
  1071. if (base.data[base.sup]) {TEX.Error("Double exponent: use braces to clarify")}
  1072. position = base.sup;
  1073. } else if (base.movesupsub) {
  1074. if (base.type !== "munderover" || base.data[base.over]) {
  1075. if (base.movablelimits && base.isa(MML.mi)) {base = this.mi2mo(base)}
  1076. base = MML.munderover(base,null,null).With({movesupsub:true})
  1077. }
  1078. position = base.over;
  1079. } else {
  1080. base = MML.msubsup(base,null,null);
  1081. position = base.sup;
  1082. }
  1083. this.Push(STACKITEM.subsup(base).With({position: position, primes: primes}));
  1084. },
  1085. Subscript: function (c) {
  1086. if (this.GetNext().match(/\d/)) // don't treat numbers as a unit
  1087. {this.string = this.string.substr(0,this.i+1)+" "+this.string.substr(this.i+1)}
  1088. var position, primes, base, top = this.stack.Top();
  1089. if (top.type === "prime") {base = top.data[0]; primes = top.data[1]; this.stack.Pop()}
  1090. else {base = this.stack.Prev(); if (!base) {base = MML.mi("")}}
  1091. if (base.isEmbellishedWrapper) {base = base.data[0].data[0]}
  1092. if (base.type === "msubsup") {
  1093. if (base.data[base.sub]) {TEX.Error("Double subscripts: use braces to clarify")}
  1094. position = base.sub;
  1095. } else if (base.movesupsub) {
  1096. if (base.type !== "munderover" || base.data[base.under]) {
  1097. if (base.movablelimits && base.isa(MML.mi)) {base = this.mi2mo(base)}
  1098. base = MML.munderover(base,null,null).With({movesupsub:true})
  1099. }
  1100. position = base.under;
  1101. } else {
  1102. base = MML.msubsup(base,null,null);
  1103. position = base.sub;
  1104. }
  1105. this.Push(STACKITEM.subsup(base).With({position: position, primes: primes}));
  1106. },
  1107. PRIME: "\u2032", SMARTQUOTE: "\u2019",
  1108. Prime: function (c) {
  1109. var base = this.stack.Prev(); if (!base) {base = MML.mi()}
  1110. if (base.type === "msubsup" && base.data[base.sup])
  1111. {TEX.Error("Prime causes double exponent: use braces to clarify")}
  1112. var sup = ""; this.i--;
  1113. do {sup += this.PRIME; this.i++, c = this.GetNext()}
  1114. while (c === "'" || c === this.SMARTQUOTE);
  1115. sup = ["","\u2032","\u2033","\u2034","\u2057"][sup.length] || sup;
  1116. this.Push(STACKITEM.prime(base,this.mmlToken(MML.mo(sup))));
  1117. },
  1118. mi2mo: function (mi) {
  1119. var mo = MML.mo(); mo.Append.apply(mo,mi.data); var id;
  1120. for (id in mo.defaults)
  1121. {if (mo.defaults.hasOwnProperty(id) && mi[id] != null) {mo[id] = mi[id]}}
  1122. for (id in MML.copyAttributes)
  1123. {if (MML.copyAttributes.hasOwnProperty(id) && mi[id] != null) {mo[id] = mi[id]}}
  1124. return mo;
  1125. },
  1126. /*
  1127. * Handle comments
  1128. */
  1129. Comment: function (c) {
  1130. while (this.i < this.string.length && this.string.charAt(this.i) != "\n") {this.i++}
  1131. },
  1132. /*
  1133. * Handle hash marks outside of definitions
  1134. */
  1135. Hash: function (c) {
  1136. TEX.Error("You can't use 'macro parameter character #' in math mode");
  1137. },
  1138. /*
  1139. * Handle other characters (as <mo> elements)
  1140. */
  1141. Other: function (c) {
  1142. var def = {stretchy: false}, mo;
  1143. if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
  1144. if (TEXDEF.remap[c]) {
  1145. c = TEXDEF.remap[c];
  1146. if (c instanceof Array) {def = c[1]; c = c[0]}
  1147. mo = MML.mo(MML.entity('#x'+c)).With(def);
  1148. } else {
  1149. mo = MML.mo(c).With(def);
  1150. }
  1151. if (mo.autoDefault("texClass",true) == "") {mo = MML.TeXAtom(mo)}
  1152. this.Push(this.mmlToken(mo));
  1153. },
  1154. /************************************************************************/
  1155. /*
  1156. * Macros
  1157. */
  1158. SetFont: function (name,font) {this.stack.env.font = font},
  1159. SetStyle: function (name,texStyle,style,level) {
  1160. this.stack.env.style = texStyle; this.stack.env.level = level;
  1161. this.Push(STACKITEM.style().With({styles: {displaystyle: style, scriptlevel: level}}));
  1162. },
  1163. SetSize: function (name,size) {
  1164. this.stack.env.size = size;
  1165. this.Push(STACKITEM.style().With({styles: {mathsize: size+"em"}})); // convert to absolute?
  1166. },
  1167. Color: function (name) {
  1168. var color = this.GetArgument(name);
  1169. var old = this.stack.env.color; this.stack.env.color = color;
  1170. var math = this.ParseArg(name);
  1171. if (old) {this.stack.env.color} else {delete this.stack.env.color}
  1172. this.Push(MML.mstyle(math).With({mathcolor: color}));
  1173. },
  1174. Spacer: function (name,space) {
  1175. this.Push(MML.mspace().With({width: space, mathsize: MML.SIZE.NORMAL, scriptlevel:0}));
  1176. },
  1177. LeftRight: function (name) {
  1178. this.Push(STACKITEM[name.substr(1)]().With({delim: this.GetDelimiter(name)}));
  1179. },
  1180. Middle: function (name) {
  1181. var delim = this.GetDelimiter(name);
  1182. if (this.stack.Top().type !== "left") {TEX.Error(name+" must be within \\left and \\right")}
  1183. this.Push(MML.mo(delim).With({stretchy:true}));
  1184. },
  1185. NamedFn: function (name,id) {
  1186. if (!id) {id = name.substr(1)};
  1187. var mml = MML.mi(id).With({texClass: MML.TEXCLASS.OP});
  1188. this.Push(STACKITEM.fn(this.mmlToken(mml)));
  1189. },
  1190. NamedOp: function (name,id) {
  1191. if (!id) {id = name.substr(1)};
  1192. id = id.replace(/&thinsp;/,"\u2006");
  1193. var mml = MML.mo(id).With({
  1194. movablelimits: true,
  1195. movesupsub: true,
  1196. form: MML.FORM.PREFIX,
  1197. texClass: MML.TEXCLASS.OP
  1198. });
  1199. mml.useMMLspacing &= ~mml.SPACE_ATTR.form; // don't count this explicit form setting
  1200. this.Push(this.mmlToken(mml));
  1201. },
  1202. Limits: function (name,limits) {
  1203. var op = this.stack.Prev("nopop");
  1204. if (!op || op.texClass !== MML.TEXCLASS.OP) {TEX.Error(name+" is allowed only on operators")}
  1205. op.movesupsub = (limits ? true : false);
  1206. op.movablelimits = false;
  1207. },
  1208. Over: function (name,open,close) {
  1209. var mml = STACKITEM.over().With({name: name});
  1210. if (open || close) {
  1211. mml.open = open; mml.close = close;
  1212. } else if (name.match(/withdelims$/)) {
  1213. mml.open = this.GetDelimiter(name);
  1214. mml.close = this.GetDelimiter(name);
  1215. }
  1216. if (name.match(/^\\above/)) {mml.thickness = this.GetDimen(name)}
  1217. else if (name.match(/^\\atop/) || open || close) {mml.thickness = 0}
  1218. this.Push(mml);
  1219. },
  1220. Frac: function (name) {
  1221. var num = this.ParseArg(name);
  1222. var den = this.ParseArg(name);
  1223. this.Push(MML.mfrac(num,den));
  1224. },
  1225. Sqrt: function (name) {
  1226. var n = this.GetBrackets(name), arg = this.GetArgument(name);
  1227. if (arg === "\\frac") {arg += "{"+this.GetArgument(arg)+"}{"+this.GetArgument(arg)+"}"}
  1228. var mml = TEX.Parse(arg,this.stack.env).mml();
  1229. if (!n) {mml = MML.msqrt.apply(MML,mml.array())}
  1230. else {mml = MML.mroot(mml,this.parseRoot(n))}
  1231. this.Push(mml);
  1232. },
  1233. Root: function (name) {
  1234. var n = this.GetUpTo(name,"\\of");
  1235. var arg = this.ParseArg(name);
  1236. this.Push(MML.mroot(arg,this.parseRoot(n)));
  1237. },
  1238. parseRoot: function (n) {
  1239. var env = this.stack.env, inRoot = env.inRoot; env.inRoot = true;
  1240. var parser = TEX.Parse(n,env); n = parser.mml(); var global = parser.stack.global;
  1241. if (global.leftRoot || global.upRoot) {
  1242. n = MML.mpadded(n);
  1243. if (global.leftRoot) {n.width = global.leftRoot}
  1244. if (global.upRoot) {n.voffset = global.upRoot; n.height = global.upRoot}
  1245. }
  1246. env.inRoot = inRoot;
  1247. return n;
  1248. },
  1249. MoveRoot: function (name,id) {
  1250. if (!this.stack.env.inRoot) TEX.Error(name+" can appear only within a root");
  1251. if (this.stack.global[id]) TEX.Error("Multiple use of "+name);
  1252. var n = this.GetArgument(name);
  1253. if (!n.match(/-?[0-9]+/)) TEX.Error("The argument to "+name+" must be an integer");
  1254. n = (n/15)+"em";
  1255. if (n.substr(0,1) !== "-") {n = "+"+n}
  1256. this.stack.global[id] = n;
  1257. },
  1258. Accent: function (name,accent,stretchy) {
  1259. var c = this.ParseArg(name);
  1260. var def = {accent: true}; if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
  1261. var mml = this.mmlToken(MML.mo(MML.entity("#x"+accent)).With(def));
  1262. mml.stretchy = (stretchy ? true : false);
  1263. this.Push(MML.TeXAtom(MML.munderover(c,null,mml).With({accent: true})));
  1264. },
  1265. UnderOver: function (name,c,stack) {
  1266. var pos = {o: "over", u: "under"}[name.charAt(1)];
  1267. var base = this.ParseArg(name);
  1268. if (base.Get("movablelimits")) {base.movablelimits = false}
  1269. var mml = MML.munderover(base,null,null);
  1270. if (stack) {mml.movesupsub = true}
  1271. mml.data[mml[pos]] =
  1272. this.mmlToken(MML.mo(MML.entity("#x"+c)).With({stretchy:true, accent:(pos == "under")}));
  1273. this.Push(mml);
  1274. },
  1275. Overset: function (name) {
  1276. var top = this.ParseArg(name), base = this.ParseArg(name);
  1277. this.Push(MML.mover(base,top));
  1278. },
  1279. Underset: function (name) {
  1280. var bot = this.ParseArg(name), base = this.ParseArg(name);
  1281. this.Push(MML.munder(base,bot));
  1282. },
  1283. TeXAtom: function (name,mclass) {
  1284. var def = {texClass: mclass}, mml;
  1285. if (mclass == MML.TEXCLASS.OP) {
  1286. def.movesupsub = def.movablelimits = true;
  1287. var arg = this.GetArgument(name);
  1288. var match = arg.match(/^\s*\\rm\s+([a-zA-Z0-9 ]+)$/);
  1289. if (match) {
  1290. def.mathvariant = MML.VARIANT.NORMAL;
  1291. mml = STACKITEM.fn(this.mmlToken(MML.mi(match[1]).With(def)));
  1292. } else {
  1293. mml = STACKITEM.fn(MML.TeXAtom(TEX.Parse(arg,this.stack.env).mml()).With(def));
  1294. }
  1295. } else {mml = MML.TeXAtom(this.ParseArg(name)).With(def)}
  1296. this.Push(mml);
  1297. },
  1298. MmlToken: function (name) {
  1299. var type = this.GetArgument(name),
  1300. attr = this.GetBrackets(name,"").replace(/^\s+/,""),
  1301. data = this.GetArgument(name),
  1302. def = {attrNames:[]}, match;
  1303. if (!MML[type] || !MML[type].prototype.isToken) {TEX.Error(type+" is not a token element")}
  1304. while (attr !== "") {
  1305. match = attr.match(/^([a-z]+)\s*=\s*('[^']*'|"[^"]*"|[^ ]*)\s*/i);
  1306. if (!match) {TEX.Error("Invalid MathML attribute: "+attr)}
  1307. if (!MML[type].prototype.defaults[match[1]] && !this.MmlTokenAllow[match[1]])
  1308. {TEX.Error(match[1]+" is not a recognized attribute for "+type)}
  1309. def[match[1]] = match[2].replace(/^(['"])(.*)\1$/,"$2");
  1310. def.attrNames.push(match[1]);
  1311. attr = attr.substr(match[0].length);
  1312. }
  1313. this.Push(this.mmlToken(MML[type](data).With(def)));
  1314. },
  1315. MmlTokenAllow: {
  1316. fontfamily:1, fontsize:1, fontweight:1, fontstyle:1,
  1317. color:1, background:1,
  1318. id:1, "class":1, href:1, style:1
  1319. },
  1320. Strut: function (name) {
  1321. this.Push(MML.mpadded(MML.mrow()).With({height: "8.6pt", depth: "3pt", width: 0}));
  1322. },
  1323. Phantom: function (name,v,h) {
  1324. var box = MML.mphantom(this.ParseArg(name));
  1325. if (v || h) {
  1326. box = MML.mpadded(box);
  1327. if (h) {box.height = box.depth = 0}
  1328. if (v) {box.width = 0}
  1329. }
  1330. this.Push(MML.TeXAtom(box));
  1331. },
  1332. Smash: function (name) {
  1333. var bt = this.trimSpaces(this.GetBrackets(name,""));
  1334. var smash = MML.mpadded(this.ParseArg(name));
  1335. switch (bt) {
  1336. case "b": smash.depth = 0; break;
  1337. case "t": smash.height = 0; break;
  1338. default: smash.height = smash.depth = 0;
  1339. }
  1340. this.Push(MML.TeXAtom(smash));
  1341. },
  1342. Lap: function (name) {
  1343. var mml = MML.mpadded(this.ParseArg(name)).With({width: 0});
  1344. if (name === "\\llap") {mml.lspace = "-1 width"}
  1345. this.Push(MML.TeXAtom(mml));
  1346. },
  1347. RaiseLower: function (name) {
  1348. var h = this.GetDimen(name);
  1349. var item = STACKITEM.position().With({name: name, move: 'vertical'});
  1350. if (h.charAt(0) === '-') {h = h.slice(1); name = {raise: "\\lower", lower: "\\raise"}[name.substr(1)]}
  1351. if (name === "\\lower") {item.dh = '-'+h; item.dd = '+'+h} else {item.dh = '+'+h; item.dd = '-'+h}
  1352. this.Push(item);
  1353. },
  1354. MoveLeftRight: function (name) {
  1355. var h = this.GetDimen(name);
  1356. var nh = (h.charAt(0) === '-' ? h.slice(1) : '-'+h);
  1357. if (name === "\\moveleft") {var tmp = h; h = nh; nh = tmp}
  1358. this.Push(STACKITEM.position().With({
  1359. name: name, move: 'horizontal',
  1360. left: MML.mspace().With({width: h, mathsize: MML.SIZE.NORMAL}),
  1361. right: MML.mspace().With({width: nh, mathsize: MML.SIZE.NORMAL})
  1362. }));
  1363. },
  1364. Hskip: function (name) {
  1365. this.Push(MML.mspace().With({width: this.GetDimen(name), mathsize: MML.SIZE.NORMAL}));
  1366. },
  1367. Rule: function (name,style) {
  1368. var w = this.GetDimen(name),
  1369. h = this.GetDimen(name),
  1370. d = this.GetDimen(name);
  1371. var mml, def = {width:w, height:h, depth:d};
  1372. if (style !== 'blank') {
  1373. if (parseFloat(w) && parseFloat(h)+parseFloat(d))
  1374. {def.mathbackground = (this.stack.env.color || "black")}
  1375. mml = MML.mpadded(MML.mrow()).With(def);
  1376. } else {
  1377. mml = MML.mspace().With(def);
  1378. }
  1379. this.Push(mml);
  1380. },
  1381. MakeBig: function (name,mclass,size) {
  1382. size *= TEXDEF.p_height;
  1383. size = String(size).replace(/(\.\d\d\d).+/,'$1')+"em";
  1384. var delim = this.GetDelimiter(name);
  1385. this.Push(MML.TeXAtom(MML.mo(delim).With({
  1386. minsize: size, maxsize: size, scriptlevel: 0,
  1387. fence: true, stretchy: true, symmetric: true
  1388. })).With({texClass: mclass}));
  1389. },
  1390. BuildRel: function (name) {
  1391. var top = this.ParseUpTo(name,"\\over");
  1392. var bot = this.ParseArg(name);
  1393. this.Push(MML.TeXAtom(MML.munderover(bot,null,top)).With({mclass: MML.TEXCLASS.REL}));
  1394. },
  1395. HBox: function (name,style) {
  1396. this.Push.apply(this,this.InternalMath(this.GetArgument(name),style));
  1397. },
  1398. FBox: function (name) {
  1399. this.Push(MML.menclose.apply(MML,this.InternalMath(this.GetArgument(name))).With({notation:"box"}));
  1400. },
  1401. Not: function (name) {
  1402. this.Push(STACKITEM.not());
  1403. },
  1404. Dots: function (name) {
  1405. this.Push(STACKITEM.dots().With({
  1406. ldots: this.mmlToken(MML.mo(MML.entity("#x2026")).With({stretchy:false})),
  1407. cdots: this.mmlToken(MML.mo(MML.entity("#x22EF")).With({stretchy:false}))
  1408. }));
  1409. },
  1410. Require: function (name) {
  1411. var file = this.GetArgument(name)
  1412. .replace(/.*\//,"") // remove any leading path
  1413. .replace(/[^a-z0-9_.-]/ig,""); // remove illegal characters
  1414. this.Extension(null,file);
  1415. },
  1416. Extension: function (name,file,array) {
  1417. if (name && !typeof(name) === "string") {name = name.name}
  1418. file = TEX.extensionDir+"/"+file;
  1419. if (!file.match(/\.js$/)) {file += ".js"}
  1420. if (!AJAX.loaded[AJAX.fileURL(file)]) {
  1421. if (name != null) {delete TEXDEF[array || 'macros'][name.replace(/^\\/,"")]}
  1422. HUB.RestartAfter(AJAX.Require(file));
  1423. }
  1424. },
  1425. Macro: function (name,macro,argcount,def) {
  1426. if (argcount) {
  1427. var args = [];
  1428. if (def != null) {
  1429. var optional = this.GetBrackets(name);
  1430. args.push(optional == null ? def : optional);
  1431. }
  1432. for (var i = args.length; i < argcount; i++) {args.push(this.GetArgument(name))}
  1433. macro = this.SubstituteArgs(args,macro);
  1434. }
  1435. this.string = this.AddArgs(macro,this.string.slice(this.i));
  1436. this.i = 0;
  1437. if (++this.macroCount > TEX.config.MAXMACROS)
  1438. {TEX.Error("MathJax maximum macro substitution count exceeded; is there a recursive macro call?")}
  1439. },
  1440. Matrix: function (name,open,close,align,spacing,vspacing,style,cases) {
  1441. var c = this.GetNext(); if (c === "") {TEX.Error("Missing argument for "+name)}
  1442. if (c === "{") {this.i++} else {this.string = c+"}"+this.string.slice(this.i+1); this.i = 0}
  1443. var array = STACKITEM.array().With({
  1444. requireClose: true,
  1445. arraydef: {
  1446. rowspacing: (vspacing||"4pt"),
  1447. columnspacing: (spacing||"1em")
  1448. }
  1449. });
  1450. if (cases) {array.isCases = true}
  1451. if (open || close) {array.open = open; array.close = close}
  1452. if (style === "D") {array.arraydef.displaystyle = true}
  1453. if (align != null) {array.arraydef.columnalign = align}
  1454. this.Push(array);
  1455. },
  1456. Entry: function (name) {
  1457. this.Push(STACKITEM.cell().With({isEntry: true, name: name}));
  1458. if (this.stack.Top().isCases) {
  1459. var string = this.string;
  1460. var braces = 0, i = this.i, m = string.length;
  1461. while (i < m) {
  1462. var c = string.charAt(i);
  1463. if (c === "{") {braces++; i++}
  1464. else if (c === "}") {if (braces === 0) {m = 0} else {braces--; i++}}
  1465. else if (c === "&" && braces === 0) {TEX.Error("Extra alignment tab in \\cases text")}
  1466. else if (c === "\\") {
  1467. if (string.substr(i).match(/^((\\cr)[^a-zA-Z]|\\\\)/)) {m = 0} else {i += 2}
  1468. } else {i++}
  1469. }
  1470. var text = string.substr(this.i,i-this.i);
  1471. if (!text.match(/^\s*\\text[^a-zA-Z]/)) {
  1472. this.Push.apply(this,this.InternalMath(text));
  1473. this.i = i;
  1474. }
  1475. }
  1476. },
  1477. Cr: function (name) {
  1478. this.Push(STACKITEM.cell().With({isCR: true, name: name}));
  1479. },
  1480. CrLaTeX: function (name) {
  1481. var n;
  1482. if (this.string.charAt(this.i) === "[") {
  1483. n = this.GetBrackets(name,"").replace(/ /g,"");
  1484. if (n && !n.match(/^((-?(\.\d+|\d+(\.\d*)?))(pt|em|ex|mu|mm|cm|in|pc))$/))
  1485. {TEX.Error("Bracket argument to "+name+" must be a dimension")}
  1486. }
  1487. this.Push(STACKITEM.cell().With({isCR: true, name: name, linebreak: true}));
  1488. var top = this.stack.Top();
  1489. if (top.isa(STACKITEM.array)) {
  1490. if (n && top.arraydef.rowspacing) {
  1491. var rows = top.arraydef.rowspacing.split(/ /);
  1492. if (!top.rowspacing) {top.rowspacing = this.dimen2em(rows[0])}
  1493. while (rows.length < top.table.length) {rows.push(this.Em(top.rowspacing))}
  1494. rows[top.table.length-1] = this.Em(Math.max(0,top.rowspacing+this.dimen2em(n)));
  1495. top.arraydef.rowspacing = rows.join(' ');
  1496. }
  1497. } else {
  1498. if (n) {this.Push(MML.mspace().With({depth:n}))}
  1499. this.Push(MML.mo().With({linebreak:MML.LINEBREAK.NEWLINE}));
  1500. }
  1501. },
  1502. emPerInch: 7.2,
  1503. dimen2em: function (dim) {
  1504. var match = dim.match(/^(-?(?:\.\d+|\d+(?:\.\d*)?))(pt|em|ex|mu|pc|in|mm|cm)/);
  1505. var m = parseFloat(match[1]||"1"), unit = match[2];
  1506. if (unit === "em") {return m}
  1507. if (unit === "ex") {return m * .43}
  1508. if (unit === "pt") {return m / 10} // 10 pt to an em
  1509. if (unit === "pc") {return m * 1.2} // 12 pt to a pc
  1510. if (unit === "in") {return m * this.emPerInch}
  1511. if (unit === "cm") {return m * this.emPerInch / 2.54} // 2.54 cm to an inch
  1512. if (unit === "mm") {return m * this.emPerInch / 25.4} // 10 mm to a cm
  1513. if (unit === "mu") {return m / 18}
  1514. return 0;
  1515. },
  1516. Em: function (m) {
  1517. if (Math.abs(m) < .0006) {return "0em"}
  1518. return m.toFixed(3).replace(/\.?0+$/,"") + "em";
  1519. },
  1520. HLine: function (name,style) {
  1521. if (style == null) {style = "solid"}
  1522. var top = this.stack.Top();
  1523. if (!top.isa(STACKITEM.array) || top.data.length) {TEX.Error("Misplaced "+name)}
  1524. if (top.table.length == 0) {
  1525. top.frame.push("top");
  1526. } else {
  1527. var lines = (top.arraydef.rowlines ? top.arraydef.rowlines.split(/ /) : []);
  1528. while (lines.length < top.table.length) {lines.push("none")}
  1529. lines[top.table.length-1] = style;
  1530. top.arraydef.rowlines = lines.join(' ');
  1531. }
  1532. },
  1533. /************************************************************************/
  1534. /*
  1535. * LaTeX environments
  1536. */
  1537. Begin: function (name) {
  1538. var env = this.GetArgument(name);
  1539. if (env.match(/[^a-z*]/i)) {TEX.Error('Invalid environment name "'+env+'"')}
  1540. var cmd = this.envFindName(env); if (!cmd) {TEX.Error('Unknown environment "'+env+'"')}
  1541. if (++this.macroCount > TEX.config.MAXMACROS)
  1542. {TEX.Error("MathJax maximum substitution count exceeded; is there a recursive latex environment?")}
  1543. if (!(cmd instanceof Array)) {cmd = [cmd]}
  1544. var mml = STACKITEM.begin().With({name: env, end: cmd[1], parse:this});
  1545. if (cmd[0] && this[cmd[0]]) {mml = this[cmd[0]].apply(this,[mml].concat(cmd.slice(2)))}
  1546. this.Push(mml);
  1547. },
  1548. End: function (name) {
  1549. this.Push(STACKITEM.end().With({name: this.GetArgument(name)}));
  1550. },
  1551. envFindName: function (name) {return TEXDEF.environment[name]},
  1552. Equation: function (begin,row) {return row},
  1553. ExtensionEnv: function (begin,file) {this.Extension(begin.name,file,"environment")},
  1554. Array: function (begin,open,close,align,spacing,vspacing,style,raggedHeight) {
  1555. if (!align) {align = this.GetArgument("\\begin{"+begin.name+"}")}
  1556. var lines = ("c"+align).replace(/[^clr|:]/g,'').replace(/[^|:]([|:])+/g,'$1');
  1557. align = align.replace(/[^clr]/g,'').split('').join(' ');
  1558. align = align.replace(/l/g,'left').replace(/r/g,'right').replace(/c/g,'center');
  1559. var array = STACKITEM.array().With({
  1560. arraydef: {
  1561. columnalign: align,
  1562. columnspacing: (spacing||"1em"),
  1563. rowspacing: (vspacing||"4pt")
  1564. }
  1565. });
  1566. if (lines.match(/[|:]/)) {
  1567. if (lines.charAt(0).match(/[|:]/)) {array.frame.push("left"); array.frame.dashed = lines.charAt(0) === ":"}
  1568. if (lines.charAt(lines.length-1).match(/[|:]/)) {array.frame.push("right")}
  1569. lines = lines.substr(1,lines.length-2);
  1570. array.arraydef.columnlines =
  1571. lines.split('').join(' ').replace(/[^|: ]/g,'none').replace(/\|/g,'solid').replace(/:/g,'dashed');
  1572. }
  1573. if (open) {array.open = this.convertDelimiter(open)}
  1574. if (close) {array.close = this.convertDelimiter(close)}
  1575. if (style === "D") {array.arraydef.displaystyle = true}
  1576. if (style === "S") {array.arraydef.scriptlevel = 1} // FIXME: should use mstyle?
  1577. if (raggedHeight) {array.arraydef.useHeight = false}
  1578. this.Push(begin);
  1579. return array;
  1580. },
  1581. AlignedArray: function (begin) {
  1582. var align = this.GetBrackets("\\begin{"+begin.name+"}");
  1583. return this.setArrayAlign(this.Array.apply(this,arguments),align);
  1584. },
  1585. setArrayAlign: function (array,align) {
  1586. align = this.trimSpaces(align||"");
  1587. if (align === "t") {array.arraydef.align = "baseline 1"}
  1588. else if (align === "b") {array.arraydef.align = "baseline -1"}
  1589. else if (align === "c") {array.arraydef.align = "center"}
  1590. else if (align) {array.arraydef.align = align} // FIXME: should be an error?
  1591. return array;
  1592. },
  1593. /************************************************************************/
  1594. /*
  1595. * String handling routines
  1596. */
  1597. /*
  1598. * Convert delimiter to character
  1599. */
  1600. convertDelimiter: function (c) {
  1601. if (c) {c = TEXDEF.delimiter[c]}
  1602. if (c == null) {return null}
  1603. if (c instanceof Array) {c = c[0]}
  1604. if (c.length === 4) {c = String.fromCharCode(parseInt(c,16))}
  1605. return c;
  1606. },
  1607. /*
  1608. * Trim spaces from a string
  1609. */
  1610. trimSpaces: function (text) {
  1611. if (typeof(text) != 'string') {return text}
  1612. return text.replace(/^\s+|\s+$/g,'');
  1613. },
  1614. /*
  1615. * Check if the next character is a space
  1616. */
  1617. nextIsSpace: function () {
  1618. return this.string.charAt(this.i).match(/[ \n\r\t]/);
  1619. },
  1620. /*
  1621. * Get the next non-space character
  1622. */
  1623. GetNext: function () {
  1624. while (this.nextIsSpace()) {this.i++}
  1625. return this.string.charAt(this.i);
  1626. },
  1627. /*
  1628. * Get and return a control-sequence name
  1629. */
  1630. GetCS: function () {
  1631. var CS = this.string.slice(this.i).match(/^([a-z]+|.) ?/i);
  1632. if (CS) {this.i += CS[1].length; return CS[1]} else {this.i++; return " "}
  1633. },
  1634. /*
  1635. * Get and return a TeX argument (either a single character or control sequence,
  1636. * or the contents of the next set of braces).
  1637. */
  1638. GetArgument: function (name,noneOK) {
  1639. switch (this.GetNext()) {
  1640. case "":
  1641. if (!noneOK) {TEX.Error("Missing argument for "+name)}
  1642. return null;
  1643. case '}':
  1644. if (!noneOK) {TEX.Error("Extra close brace or missing open brace")}
  1645. return null;
  1646. case '\\':
  1647. this.i++; return "\\"+this.GetCS();
  1648. case '{':
  1649. var j = ++this.i, parens = 1;
  1650. while (this.i < this.string.length) {
  1651. switch (this.string.charAt(this.i++)) {
  1652. case '\\': this.i++; break;
  1653. case '{': parens++; break;
  1654. case '}':
  1655. if (parens == 0) {TEX.Error("Extra close brace")}
  1656. if (--parens == 0) {return this.string.slice(j,this.i-1)}
  1657. break;
  1658. }
  1659. }
  1660. TEX.Error("Missing close brace");
  1661. break;
  1662. }
  1663. return this.string.charAt(this.i++);
  1664. },
  1665. /*
  1666. * Get an optional LaTeX argument in brackets
  1667. */
  1668. GetBrackets: function (name,def) {
  1669. if (this.GetNext() != '[') {return def};
  1670. var j = ++this.i, parens = 0;
  1671. while (this.i < this.string.length) {
  1672. switch (this.string.charAt(this.i++)) {
  1673. case '{': parens++; break;
  1674. case '\\': this.i++; break;
  1675. case '}':
  1676. if (parens-- <= 0) {TEX.Error("Extra close brace while looking for ']'")}
  1677. break;
  1678. case ']':
  1679. if (parens == 0) {return this.string.slice(j,this.i-1)}
  1680. break;
  1681. }
  1682. }
  1683. TEX.Error("Couldn't find closing ']' for argument to "+name);
  1684. },
  1685. /*
  1686. * Get the name of a delimiter (check it in the delimiter list).
  1687. */
  1688. GetDelimiter: function (name) {
  1689. while (this.nextIsSpace()) {this.i++}
  1690. var c = this.string.charAt(this.i);
  1691. if (this.i < this.string.length) {
  1692. this.i++; if (c == "\\") {c += this.GetCS(name)}
  1693. if (TEXDEF.delimiter[c] != null) {return this.convertDelimiter(c)}
  1694. }
  1695. TEX.Error("Missing or unrecognized delimiter for "+name);
  1696. },
  1697. /*
  1698. * Get a dimension (including its units).
  1699. */
  1700. GetDimen: function (name) {
  1701. var dimen;
  1702. if (this.nextIsSpace()) {this.i++}
  1703. if (this.string.charAt(this.i) == '{') {
  1704. dimen = this.GetArgument(name);
  1705. if (dimen.match(/^\s*([-+]?(\.\d+|\d+(\.\d*)?))\s*(pt|em|ex|mu|px|mm|cm|in|pc)\s*$/))
  1706. {return dimen.replace(/ /g,"")}
  1707. } else {
  1708. dimen = this.string.slice(this.i);
  1709. var match = dimen.match(/^\s*(([-+]?(\.\d+|\d+(\.\d*)?))\s*(pt|em|ex|mu|px|mm|cm|in|pc)) ?/);
  1710. if (match) {
  1711. this.i += match[0].length;
  1712. return match[1].replace(/ /g,"");
  1713. }
  1714. }
  1715. TEX.Error("Missing dimension or its units for "+name);
  1716. },
  1717. /*
  1718. * Get everything up to the given control sequence (token)
  1719. */
  1720. GetUpTo: function (name,token) {
  1721. while (this.nextIsSpace()) {this.i++}
  1722. var j = this.i, k, c, parens = 0;
  1723. while (this.i < this.string.length) {
  1724. k = this.i; c = this.string.charAt(this.i++);
  1725. switch (c) {
  1726. case '\\': c += this.GetCS(); break;
  1727. case '{': parens++; break;
  1728. case '}':
  1729. if (parens == 0) {TEX.Error("Extra close brace while looking for "+token)}
  1730. parens--;
  1731. break;
  1732. }
  1733. if (parens == 0 && c == token) {return this.string.slice(j,k)}
  1734. }
  1735. TEX.Error("Couldn't find "+token+" for "+name);
  1736. },
  1737. /*
  1738. * Parse various substrings
  1739. */
  1740. ParseArg: function (name) {return TEX.Parse(this.GetArgument(name),this.stack.env).mml()},
  1741. ParseUpTo: function (name,token) {return TEX.Parse(this.GetUpTo(name,token),this.stack.env).mml()},
  1742. /*
  1743. * Break up a string into text and math blocks
  1744. * @@@ FIXME: skip over braced groups? @@@
  1745. * @@@ FIXME: pass environment to TEX.Parse? @@@
  1746. */
  1747. InternalMath: function (text,level) {
  1748. var def = {displaystyle: false}; if (level != null) {def.scriptlevel = level}
  1749. if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
  1750. if (!text.match(/\$|\\\(|\\(eq)?ref\s*\{/)) {return [this.InternalText(text,def)]}
  1751. var i = 0, k = 0, c, match = '';
  1752. var mml = [];
  1753. while (i < text.length) {
  1754. c = text.charAt(i++);
  1755. if (c === '$') {
  1756. if (match === '$') {
  1757. mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i-1),{}).mml().With(def)));
  1758. match = ''; k = i;
  1759. } else if (match === '') {
  1760. if (k < i-1) {mml.push(this.InternalText(text.slice(k,i-1),def))}
  1761. match = '$'; k = i;
  1762. }
  1763. } else if (c === '}' && match === '}') {
  1764. mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i),{}).mml().With(def)));
  1765. match = ''; k = i;
  1766. } else if (c === '\\') {
  1767. if (match === '' && text.substr(i).match(/^(eq)?ref\s*\{/)) {
  1768. if (k < i-1) {mml.push(this.InternalText(text.slice(k,i-1),def))}
  1769. match = '}'; k = i-1;
  1770. } else {
  1771. c = text.charAt(i++);
  1772. if (c === '(' && match === '') {
  1773. if (k < i-2) {mml.push(this.InternalText(text.slice(k,i-2),def))}
  1774. match = ')'; k = i;
  1775. } else if (c === ')' && match === ')') {
  1776. mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i-2),{}).mml().With(def)));
  1777. match = ''; k = i;
  1778. }
  1779. }
  1780. }
  1781. }
  1782. if (match !== '') {TEX.Error("Math not terminated in text box")}
  1783. if (k < text.length) {mml.push(this.InternalText(text.slice(k),def))}
  1784. return mml;
  1785. },
  1786. InternalText: function (text,def) {
  1787. text = text.replace(/^\s+/,NBSP).replace(/\s+$/,NBSP);
  1788. return MML.mtext(MML.chars(text)).With(def);
  1789. },
  1790. /*
  1791. * Replace macro paramters with their values
  1792. */
  1793. SubstituteArgs: function (args,string) {
  1794. var text = ''; var newstring = ''; var c; var i = 0;
  1795. while (i < string.length) {
  1796. c = string.charAt(i++);
  1797. if (c === "\\") {text += c + string.charAt(i++)}
  1798. else if (c === '#') {
  1799. c = string.charAt(i++);
  1800. if (c === '#') {text += c} else {
  1801. if (!c.match(/[1-9]/) || c > args.length)
  1802. {TEX.Error("Illegal macro parameter reference")}
  1803. newstring = this.AddArgs(this.AddArgs(newstring,text),args[c-1]);
  1804. text = '';
  1805. }
  1806. } else {text += c}
  1807. }
  1808. return this.AddArgs(newstring,text);
  1809. },
  1810. /*
  1811. * Make sure that macros are followed by a space if their names
  1812. * could accidentally be continued into the following text.
  1813. */
  1814. AddArgs: function (s1,s2) {
  1815. if (s2.match(/^[a-z]/i) && s1.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)) {s1 += ' '}
  1816. if (s1.length + s2.length > TEX.config.MAXBUFFER)
  1817. {TEX.Error("MathJax internal buffer size exceeded; is there a recursive macro call?")}
  1818. return s1+s2;
  1819. }
  1820. });
  1821. /************************************************************************/
  1822. TEX.Augment({
  1823. Stack: STACK, Parse: PARSE, Definitions: TEXDEF, Startup: STARTUP,
  1824. config: {
  1825. MAXMACROS: 10000, // maximum number of macro substitutions per equation
  1826. MAXBUFFER: 5*1024 // maximum size of TeX string to process
  1827. },
  1828. sourceMenuTitle: "TeX Commands",
  1829. prefilterHooks: MathJax.Callback.Hooks(true), // hooks to run before processing TeX
  1830. postfilterHooks: MathJax.Callback.Hooks(true), // hooks to run after processing TeX
  1831. //
  1832. // Check if AMSmath extension must be loaded and push
  1833. // it on the extensions array, if needed
  1834. //
  1835. Config: function () {
  1836. this.SUPER(arguments).Config.apply(this,arguments);
  1837. if (this.config.equationNumbers.autoNumber !== "none") {
  1838. if (!this.config.extensions) {this.config.extensions = []}
  1839. this.config.extensions.push("AMSmath.js");
  1840. }
  1841. },
  1842. //
  1843. // Convert TeX to ElementJax
  1844. //
  1845. Translate: function (script) {
  1846. var mml, isError = false, math = MathJax.HTML.getScript(script);
  1847. var display = (script.type.replace(/\n/g," ").match(/(;|\s|\n)mode\s*=\s*display(;|\s|\n|$)/) != null);
  1848. var data = {math:math, display:display, script:script};
  1849. this.prefilterHooks.Execute(data); math = data.math;
  1850. try {
  1851. mml = TEX.Parse(math).mml();
  1852. // mml = MML.semantics(mml,MML.annotation(math).With({encoding:"application/x-tex"}));
  1853. } catch(err) {
  1854. if (!err.texError) {throw err}
  1855. mml = this.formatError(err,math,display,script);
  1856. isError = true;
  1857. }
  1858. if (mml.inferred) {mml = MML.apply(MathJax.ElementJax,mml.data)} else {mml = MML(mml)}
  1859. if (display) {mml.root.display = "block"}
  1860. if (isError) {mml.texError = true}
  1861. data.math = mml; this.postfilterHooks.Execute(data);
  1862. return data.math;
  1863. },
  1864. prefilterMath: function (math,displaystyle,script) {
  1865. return math;
  1866. },
  1867. postfilterMath: function (math,displaystyle,script) {
  1868. this.combineRelations(math.root);
  1869. return math;
  1870. },
  1871. formatError: function (err,math,display,script) {
  1872. var message = err.message.replace(/\n.*/,"");
  1873. HUB.signal.Post(["TeX Jax - parse error",message,math,display,script]);
  1874. return MML.merror(message);
  1875. },
  1876. //
  1877. // Produce an error and stop processing this equation
  1878. //
  1879. Error: function (message) {
  1880. throw HUB.Insert(Error(message),{texError: true});
  1881. },
  1882. //
  1883. // Add a user-defined macro to the macro list
  1884. //
  1885. Macro: function (name,def,argn) {
  1886. TEXDEF.macros[name] = ['Macro'].concat([].slice.call(arguments,1));
  1887. TEXDEF.macros[name].isUser = true;
  1888. },
  1889. //
  1890. // Combine adjacent <mo> elements that are relations
  1891. // (since MathML treats the spacing very differently)
  1892. //
  1893. combineRelations: function (mml) {
  1894. var i, m, m1, m2;
  1895. for (i = 0, m = mml.data.length; i < m; i++) {
  1896. if (mml.data[i]) {
  1897. if (mml.isa(MML.mrow)) {
  1898. while (i+1 < m && (m1 = mml.data[i]) && (m2 = mml.data[i+1]) &&
  1899. m1.isa(MML.mo) && m2.isa(MML.mo) &&
  1900. m1.Get("texClass") === MML.TEXCLASS.REL &&
  1901. m2.Get("texClass") === MML.TEXCLASS.REL) {
  1902. if (m1.variantForm == m2.variantForm &&
  1903. m1.Get("mathvariant") == m2.Get("mathvariant") && m1.style == m2.style &&
  1904. m1["class"] == m2["class"] && !m1.id && !m2.id) {
  1905. m1.Append.apply(m1,m2.data);
  1906. mml.data.splice(i+1,1); m--;
  1907. } else {
  1908. m1.rspace = m2.lspace = "0pt"; i++;
  1909. }
  1910. }
  1911. }
  1912. if (!mml.data[i].isToken) {this.combineRelations(mml.data[i])}
  1913. }
  1914. }
  1915. }
  1916. });
  1917. //
  1918. // Add the default filters
  1919. //
  1920. TEX.prefilterHooks.Add(function (data) {
  1921. data.math = TEX.prefilterMath(data.math,data.display,data.script);
  1922. });
  1923. TEX.postfilterHooks.Add(function (data) {
  1924. data.math = TEX.postfilterMath(data.math,data.display,data.script);
  1925. });
  1926. TEX.loadComplete("jax.js");
  1927. })(MathJax.InputJax.TeX,MathJax.Hub,MathJax.Ajax);