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