jax.js (108246B)
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/output/CommonHTML/jax.js 7 * 8 * Implements the CommonHTML OutputJax that displays mathematics 9 * using HTML and CSS to position the characters from math fonts 10 * in their proper locations. Unlike the HTML-CSS output jax, 11 * this HTML is browswer and OS independent. 12 * 13 * --------------------------------------------------------------------- 14 * 15 * Copyright (c) 2013-2015 The MathJax Consortium 16 * 17 * Licensed under the Apache License, Version 2.0 (the "License"); 18 * you may not use this file except in compliance with the License. 19 * You may obtain a copy of the License at 20 * 21 * http://www.apache.org/licenses/LICENSE-2.0 22 * 23 * Unless required by applicable law or agreed to in writing, software 24 * distributed under the License is distributed on an "AS IS" BASIS, 25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 * See the License for the specific language governing permissions and 27 * limitations under the License. 28 */ 29 30 31 (function (AJAX,HUB,HTML,CHTML) { 32 var MML; 33 34 var EVENT, TOUCH, HOVER; // filled in later 35 36 var STRUTHEIGHT = 1, 37 EFUZZ = .1, // overlap needed for stretchy delimiters 38 HFUZZ = .025, DFUZZ = .025; // adjustments to bounding box of character boxes 39 40 var STYLES = { 41 ".mjx-chtml": { 42 display: "inline-block", 43 "line-height": 0, 44 "text-indent": 0, 45 "text-align": "left", 46 "text-transform": "none", 47 "font-style": "normal", 48 "font-weight": "normal", 49 "font-size": "100%", 50 "font-size-adjust":"none", 51 "letter-spacing": "normal", 52 "word-wrap": "normal", 53 "word-spacing": "normal", 54 "white-space": "nowrap", 55 "float": "none", 56 "direction": "ltr", 57 "max-width": "none", 58 "max-height": "none", 59 "min-width": 0, 60 "min-height": 0, 61 border: 0, 62 margin: 0, 63 padding: "1px 0" 64 }, 65 ".MJXc-display": { 66 display: "block", 67 "text-align": "center", 68 "margin": "1em 0", 69 padding: 0 70 }, 71 ".mjx-chtml[tabindex]:focus, body :focus .mjx-chtml[tabindex]": { 72 display: "inline-table" // see issues #1282 and #1338 73 }, 74 75 ".mjx-math": { 76 "display": "inline-block", 77 "border-collapse": "separate", 78 "border-spacing": 0, 79 }, 80 ".mjx-math *": {display:"inline-block", "text-align":"left"}, 81 82 ".mjx-numerator": {display:"block", "text-align":"center"}, 83 ".mjx-denominator": {display:"block", "text-align":"center"}, 84 ".MJXc-stacked": {height:0, position:"relative"}, 85 ".MJXc-stacked > *": {position: "absolute"}, 86 ".MJXc-bevelled > *": {display:"inline-block"}, 87 88 ".mjx-stack": {display:"inline-block"}, 89 ".mjx-op": {display:"block"}, 90 ".mjx-under": {display:"table-cell"}, 91 ".mjx-over": {display:"block"}, 92 ".mjx-over > *": {"padding-left":"0px!important", "padding-right":"0px!important"}, 93 ".mjx-under > *": {"padding-left":"0px!important", "padding-right":"0px!important"}, 94 95 ".mjx-stack > .mjx-sup": {display:"block"}, 96 ".mjx-stack > .mjx-sub": {display:"block"}, 97 ".mjx-prestack > .mjx-presup": {display:"block"}, 98 ".mjx-prestack > .mjx-presub": {display:"block"}, 99 100 ".mjx-delim-h > .mjx-char": {display:"inline-block"}, 101 102 ".mjx-surd": {"vertical-align":"top"}, 103 104 ".mjx-mphantom *": {visibility:"hidden"}, 105 106 ".mjx-merror": { 107 "background-color":"#FFFF88", 108 color: "#CC0000", 109 border: "1px solid #CC0000", 110 padding: "2px 3px", 111 "font-style": "normal", 112 "font-size": "90%" 113 }, 114 115 ".mjx-annotation-xml": {"line-height":"normal"}, 116 117 ".mjx-menclose > svg": {fill:"none", stroke:"currentColor"}, 118 119 ".mjx-mtr": {display:"table-row"}, 120 ".mjx-mlabeledtr": {display:"table-row"}, 121 ".mjx-mtd": {display:"table-cell", "text-align":"center"}, 122 ".mjx-label": {display:"block"}, 123 124 ".mjx-box": {display:"inline-block"}, 125 ".mjx-block": {display:"block"}, 126 ".mjx-span": {display:"span"}, 127 ".mjx-char": {display:"block", "white-space":"pre"}, 128 ".mjx-itable": {display:"inline-table"}, 129 ".mjx-row": {display:"table-row"}, 130 ".mjx-cell": {display:"table-cell"}, 131 ".mjx-table": {display:"table", width:"100%"}, 132 ".mjx-line": {display:"block", height:0}, 133 ".mjx-strut": {width:0, "padding-top":STRUTHEIGHT+"em"}, 134 ".mjx-vsize": {width:0}, 135 136 ".MJXc-space1": {"margin-left":".167em"}, 137 ".MJXc-space2": {"margin-left":".222em"}, 138 ".MJXc-space3": {"margin-left":".278em"}, 139 140 ".mjx-chartest": { 141 display:"block", 142 visibility: "hidden", 143 position:"absolute", top:0, 144 "line-height":"normal", 145 "font-size":"500%" 146 }, 147 ".mjx-chartest .mjx-char": {display:"inline"}, 148 ".mjx-chartest .mjx-box": {"padding-top": "1000px"}, 149 150 ".MJXc-processing": { 151 visibility: "hidden", position:"fixed", 152 width: 0, height: 0, overflow:"hidden" 153 }, 154 ".MJXc-processed": {display:"none"}, 155 156 ".mjx-test": { 157 display: "block", 158 "font-style": "normal", 159 "font-weight": "normal", 160 "font-size": "100%", 161 "font-size-adjust":"none", 162 "text-indent": 0, 163 "text-transform": "none", 164 "letter-spacing": "normal", 165 "word-spacing": "normal", 166 overflow: "hidden", 167 height: "1px" 168 }, 169 ".mjx-ex-box-test": { 170 position: "absolute", 171 width:"1px", height:"60ex" 172 }, 173 174 "#MathJax_CHTML_Tooltip": { 175 "background-color": "InfoBackground", color: "InfoText", 176 border: "1px solid black", 177 "box-shadow": "2px 2px 5px #AAAAAA", // Opera 10.5 178 "-webkit-box-shadow": "2px 2px 5px #AAAAAA", // Safari 3 and Chrome 179 "-moz-box-shadow": "2px 2px 5px #AAAAAA", // Forefox 3.5 180 "-khtml-box-shadow": "2px 2px 5px #AAAAAA", // Konqueror 181 padding: "3px 4px", 182 "z-index": 401, 183 position: "absolute", left: 0, top: 0, 184 width: "auto", height: "auto", 185 display: "none" 186 } 187 188 }; 189 190 191 /************************************************************/ 192 193 var BIGDIMEN = 1000000; 194 var LINEBREAKS = {}, CONFIG = MathJax.Hub.config; 195 196 CHTML.Augment({ 197 settings: HUB.config.menuSettings, 198 config: {styles: STYLES}, 199 200 /********************************************/ 201 202 Config: function () { 203 if (!this.require) {this.require = []} 204 this.SUPER(arguments).Config.call(this); var settings = this.settings; 205 if (settings.scale) {this.config.scale = settings.scale} 206 this.require.push(this.fontDir+"/TeX/fontdata.js"); 207 this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js"); 208 LINEBREAKS = this.config.linebreaks; 209 }, 210 211 Startup: function () { 212 // 213 // Set up event handling 214 // 215 EVENT = MathJax.Extension.MathEvents.Event; 216 TOUCH = MathJax.Extension.MathEvents.Touch; 217 HOVER = MathJax.Extension.MathEvents.Hover; 218 this.ContextMenu = EVENT.ContextMenu; 219 this.Mousedown = EVENT.AltContextMenu; 220 this.Mouseover = HOVER.Mouseover; 221 this.Mouseout = HOVER.Mouseout; 222 this.Mousemove = HOVER.Mousemove; 223 224 // 225 // Determine pixels per inch 226 // 227 var div = CHTML.addElement(document.body,"mjx-block",{style:{display:"block",width:"5in"}}); 228 this.pxPerInch = div.offsetWidth/5; div.parentNode.removeChild(div); 229 230 // 231 // Used in preTranslate to get scaling factors and line width 232 // 233 this.TestSpan = CHTML.Element("mjx-test",{style:{left:"1em"}},[["mjx-ex-box-test"]]); 234 235 // 236 // Set up styles and preload web fonts 237 // 238 return AJAX.Styles(this.config.styles,["InitializeCHTML",this]); 239 }, 240 241 InitializeCHTML: function () { 242 this.getDefaultExEm(); 243 // 244 // If the defaultEm size is zero, it might be that a web font hasn't 245 // arrived yet, so try to wait for it, but don't wait too long. 246 // 247 if (this.defaultEm) return; 248 var ready = MathJax.Callback(); 249 AJAX.timer.start(AJAX,function (check) { 250 if (check.time(ready)) {HUB.signal.Post(["CommonHTML Jax - no default em size"]); return} 251 CHTML.getDefaultExEm(); 252 if (CHTML.defaultEm) {ready()} else {setTimeout(check,check.delay)} 253 },this.defaultEmDelay,this.defaultEmTimeout); 254 return ready; 255 }, 256 defaultEmDelay: 100, // initial delay when checking for defaultEm 257 defaultEmTimeout: 1000, // when to stop looking for defaultEm 258 getDefaultExEm: function () { 259 // 260 // Get the default sizes (need styles in place to do this) 261 // 262 document.body.appendChild(this.TestSpan); 263 this.defaultEm = this.getFontSize(this.TestSpan); 264 this.defaultEx = this.TestSpan.firstChild.offsetHeight/60; 265 this.defaultWidth = this.TestSpan.offsetWidth; 266 document.body.removeChild(this.TestSpan); 267 }, 268 getFontSize: (window.getComputedStyle ? 269 function (node) { 270 var style = window.getComputedStyle(node); 271 return parseFloat(style.fontSize); 272 } : 273 // 274 // IE 8 doesn't do getComputedStyle, so use 275 // an alternative approach 276 // 277 function (node) { 278 return node.style.pixelLeft; 279 } 280 ), 281 getMaxWidth: (window.getComputedStyle ? 282 function (node) { 283 var style = window.getComputedStyle(node); 284 if (style.maxWidth !== "none") return parseFloat(style.maxWidth); 285 return 0; 286 } : 287 // 288 // IE 8 doesn't do getComputedStyle, so use 289 // currentStyle, and a hack to get the pixels for 290 // a non-px max-width 291 // 292 function (node) { 293 var max = node.currentStyle.maxWidth; 294 if (max !== "none") { 295 if (max.match(/\d*px/)) return parseFloat(max); 296 var left = node.style.left; 297 node.style.left = max; max = node.style.pixelLeft; 298 node.style.left = left; 299 return max; 300 } 301 return 0; 302 } 303 ), 304 305 // 306 // Load data for a font 307 // 308 loadFont: function (font) { 309 HUB.RestartAfter(AJAX.Require(this.fontDir+"/"+font)); 310 }, 311 // 312 // Signal that the font data are loaded 313 // 314 fontLoaded: function (font) { 315 if (!font.match(/-|fontdata/)) font += "-Regular"; 316 if (!font.match(/\.js$/)) font += ".js" 317 MathJax.Callback.Queue( 318 ["Post",HUB.Startup.signal,["CommonHTML - font data loaded",font]], 319 ["loadComplete",AJAX,this.fontDir+"/"+font] 320 ); 321 }, 322 323 Element: function (type,def,content) { 324 if (type.substr(0,4) === "mjx-") { 325 if (!def) def = {}; 326 if (def.isMathJax == null) def.isMathJax = true; 327 if (def.className) def.className = type+" "+def.className; else def.className = type; 328 type = "span"; 329 } 330 return this.HTMLElement(type,def,content); 331 }, 332 addElement: function (node,type,def,content) { 333 return node.appendChild(this.Element(type,def,content)); 334 }, 335 HTMLElement: HTML.Element, 336 ucMatch: HTML.ucMatch, 337 setScript: HTML.setScript, 338 339 getNodesByClass: (document.getElementsByClassName ? 340 function (node,type) {return node.getElementsByClassName(type)} : 341 function (node,type) { 342 var NODES = []; 343 var nodes = node.getElementsByTagName("span"); 344 var name = RegExp("\\b"+type+"\\b"); 345 for (var i = 0, m = nodes.length; i < m; i++) { 346 if (name.test(nodes[i].className)) NODES.push = nodes[i]; 347 } 348 return NODES; 349 } 350 ), 351 getNode: function (node,type) { 352 var nodes = this.getNodesByClass(node,type); 353 if (nodes.length === 1) return nodes[0]; 354 var closest = nodes[0], N = this.getNodeDepth(node,closest); 355 for (var i = 1, m = nodes.length; i < m; i++) { 356 var n = this.getNodeDepth(node,nodes[i]); 357 if (n < N) {closest = nodes[i]; N = n} 358 } 359 return closest; 360 }, 361 getNodeDepth: function (parent,node) { 362 var n = 0; 363 while (node && node !== parent) {node = node.parentNode; n++} 364 return n; 365 }, 366 367 368 /********************************************/ 369 370 preTranslate: function (state) { 371 var scripts = state.jax[this.id], i, m = scripts.length, 372 script, prev, node, jax, ex, em; 373 // 374 // Get linebreaking information 375 // 376 var maxwidth = 100000, relwidth = false, cwidth = 0, 377 linebreak = LINEBREAKS.automatic, width = LINEBREAKS.width; 378 if (linebreak) { 379 relwidth = !!width.match(/^\s*(\d+(\.\d*)?%\s*)?container\s*$/); 380 if (relwidth) {width = width.replace(/\s*container\s*/,"")} 381 else {maxwidth = this.defaultWidth} 382 if (width === "") {width = "100%"} 383 } 384 // 385 // Loop through the scripts 386 // 387 for (i = 0; i < m; i++) { 388 script = scripts[i]; if (!script.parentNode) continue; 389 // 390 // Remove any existing output 391 // 392 prev = script.previousSibling; 393 if (prev && prev.className && String(prev.className).substr(0,9) === "mjx-chtml") 394 prev.parentNode.removeChild(prev); 395 // 396 // Add the node for the math and mark it as being processed 397 // 398 jax = script.MathJax.elementJax; if (!jax) continue; 399 jax.CHTML = {display: (jax.root.Get("display") === "block")} 400 node = CHTML.Element("mjx-chtml",{ 401 id:jax.inputID+"-Frame", className:"MathJax_CHTML", isMathJax:true, jaxID:this.id, 402 oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown, 403 onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove, 404 onclick:EVENT.Click, ondblclick:EVENT.DblClick, 405 // Added for keyboard accessible menu. 406 onkeydown: EVENT.Keydown, tabIndex: HUB.getTabOrder(jax) 407 }); 408 if (jax.CHTML.display) { 409 // 410 // Zoom box requires an outer container to get the positioning right. 411 // 412 var NODE = CHTML.Element("mjx-chtml",{className:"MJXc-display",isMathJax:false}); 413 NODE.appendChild(node); node = NODE; 414 } 415 if (HUB.Browser.noContextMenu) { 416 node.ontouchstart = TOUCH.start; 417 node.ontouchend = TOUCH.end; 418 } 419 // 420 node.className += " MJXc-processing"; 421 script.parentNode.insertBefore(node,script); 422 // 423 // Add test nodes for determineing scales and linebreak widths 424 // 425 script.parentNode.insertBefore(this.TestSpan.cloneNode(true),script); 426 } 427 // 428 // Determine the scaling factors for each script 429 // (this only requires one reflow rather than a reflow for each equation) 430 // 431 for (i = 0; i < m; i++) { 432 script = scripts[i]; if (!script.parentNode) continue; 433 test = script.previousSibling; 434 jax = script.MathJax.elementJax; if (!jax) continue; 435 em = CHTML.getFontSize(test); 436 ex = test.firstChild.offsetHeight/60; 437 if (ex === 0 || ex === "NaN") ex = this.defaultEx 438 node = test; 439 while (node) { 440 cwidth = node.offsetWidth; if (cwidth) break; 441 cwidth = CHTML.getMaxWidth(node); if (cwidth) break; 442 node = node.parentNode; 443 } 444 if (relwidth) maxwidth = cwidth; 445 scale = (this.config.matchFontHeight ? ex/this.TEX.x_height/em : 1); 446 scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale)*this.config.scale); 447 jax.CHTML.scale = scale/100; jax.CHTML.fontSize = scale+"%"; 448 jax.CHTML.outerEm = em; jax.CHTML.em = this.em = em * scale/100; 449 jax.CHTML.ex = ex; jax.CHTML.cwidth = cwidth/this.em; 450 jax.CHTML.lineWidth = (linebreak ? this.length2em(width,maxwidth/this.em,1) : maxwidth); 451 } 452 // 453 // Remove the test spans used for determining scales and linebreak widths 454 // 455 for (i = 0; i < m; i++) { 456 script = scripts[i]; if (!script.parentNode) continue; 457 test = scripts[i].previousSibling; 458 jax = scripts[i].MathJax.elementJax; if (!jax) continue; 459 test.parentNode.removeChild(test); 460 } 461 state.CHTMLeqn = state.CHTMLlast = 0; state.CHTMLi = -1; 462 state.CHTMLchunk = this.config.EqnChunk; 463 state.CHTMLdelay = false; 464 }, 465 466 /********************************************/ 467 468 Translate: function (script,state) { 469 if (!script.parentNode) return; 470 471 // 472 // If we are supposed to do a chunk delay, do it 473 // 474 if (state.CHTMLdelay) { 475 state.CHTMLdelay = false; 476 HUB.RestartAfter(MathJax.Callback.Delay(this.config.EqnChunkDelay)); 477 } 478 479 // 480 // Get the data about the math 481 // 482 var jax = script.MathJax.elementJax, math = jax.root, 483 node = document.getElementById(jax.inputID+"-Frame"); 484 this.getMetrics(jax); 485 if (this.scale !== 1) node.style.fontSize = jax.CHTML.fontSize; 486 // 487 // Typeset the math 488 // 489 this.initCHTML(math,node); 490 this.savePreview(script); 491 this.CHTMLnode = node; 492 try { 493 math.setTeXclass(); 494 math.toCommonHTML(node); 495 } catch (err) { 496 while (node.firstChild) node.removeChild(node.firstChild); 497 delete this.CHTMLnode; 498 this.restorePreview(script); 499 throw err; 500 } 501 delete this.CHTMLnode; 502 this.restorePreview(script); 503 // 504 // Put it in place, and remove the processing marker 505 // 506 if (jax.CHTML.display) node = node.parentNode; 507 node.className = node.className.replace(/ [^ ]+$/,""); 508 // 509 // Hide the math and don't let its preview be removed 510 // 511 node.className += " MJXc-processed"; 512 if (script.MathJax.preview) { 513 jax.CHTML.preview = script.MathJax.preview; 514 delete script.MathJax.preview; 515 } 516 // 517 // Check if we should show this chunk of equations 518 // 519 state.CHTMLeqn += (state.i - state.CHTMLi); state.CHTMLi = state.i; 520 if (state.CHTMLeqn >= state.CHTMLlast + state.CHTMLchunk) { 521 this.postTranslate(state); 522 state.CHTMLchunk = Math.floor(state.CHTMLchunk*this.config.EqnChunkFactor); 523 state.CHTMLdelay = true; // delay if there are more scripts 524 } 525 }, 526 527 initCHTML: function (math,node) {}, 528 529 // 530 // MathML previews can contain the same ID's as the HTML output, 531 // which confuses CHTMLnodeElement(), so remove the preview temporarily 532 // and restore it after typesetting the math. 533 // 534 savePreview: function (script) { 535 var preview = script.MathJax.preview; 536 if (preview && preview.parentNode) { 537 script.MathJax.tmpPreview = document.createElement("span"); 538 preview.parentNode.replaceChild(script.MathJax.tmpPreview,preview); 539 } 540 }, 541 restorePreview: function (script) { 542 var tmpPreview = script.MathJax.tmpPreview; 543 if (tmpPreview) { 544 tmpPreview.parentNode.replaceChild(script.MathJax.preview,tmpPreview); 545 delete script.MathJax.tmpPreview; 546 } 547 }, 548 // 549 // Get the jax metric information 550 // 551 getMetrics: function(jax) { 552 var data = jax.CHTML; 553 this.jax = jax; 554 this.em = data.em; 555 this.outerEm = data.outerEm; 556 this.scale = data.scale; 557 this.cwidth = data.cwidth; 558 this.linebreakWidth = data.lineWidth; 559 }, 560 561 /********************************************/ 562 563 postTranslate: function (state) { 564 var scripts = state.jax[this.id]; 565 // 566 // Reveal this chunk of math 567 // 568 for (var i = state.CHTMLlast, m = state.CHTMLeqn; i < m; i++) { 569 var script = scripts[i]; 570 if (script && script.MathJax.elementJax) { 571 // 572 // Remove the processed marker 573 // 574 script.previousSibling.className = script.previousSibling.className.replace(/ [^ ]+$/,""); 575 var data = script.MathJax.elementJax.CHTML; 576 // 577 // Remove the preview, if any 578 // 579 if (data.preview) { 580 data.preview.innerHTML = ""; 581 script.MathJax.preview = data.preview; 582 delete data.preview; 583 } 584 } 585 } 586 // 587 // Save our place so we know what is revealed 588 // 589 state.CHTMLlast = state.CHTMLeqn; 590 }, 591 592 /********************************************/ 593 594 getJaxFromMath: function (math) { 595 if (math.parentNode.className.match(/MJXc-display/)) math = math.parentNode; 596 do {math = math.nextSibling} while (math && math.nodeName.toLowerCase() !== "script"); 597 return HUB.getJaxFor(math); 598 }, 599 getHoverSpan: function (jax,math) {return jax.root.CHTMLnodeElement()}, 600 getHoverBBox: function (jax,span,math) { 601 var bbox = jax.root.CHTML, em = jax.CHTML.outerEm; 602 var BBOX = {w:bbox.w*em, h:bbox.h*em, d:bbox.d*em}; 603 if (bbox.width) {BBOX.width = bbox.width} 604 return BBOX; 605 }, 606 607 Zoom: function (jax,span,math,Mw,Mh) { 608 // 609 // Re-render at larger size 610 // 611 this.getMetrics(jax); 612 var node = CHTML.addElement(span,"mjx-chtml",{style:{"font-size":Math.floor(CHTML.scale*100)+"%"},isMathJax:false}); 613 CHTML.CHTMLnode = node; 614 this.idPostfix = "-zoom"; jax.root.toCommonHTML(node); this.idPostfix = ""; 615 // 616 // Adjust margins to prevent overlaps at the edges 617 // 618 var style = node.style, bbox = jax.root.CHTML; 619 if (bbox.t > bbox.h) style.marginTop = CHTML.Em(bbox.t-bbox.h); 620 if (bbox.b > bbox.d) style.marginBottom = CHTML.Em(bbox.b-bbox.d); 621 if (bbox.l < 0) style.paddingLeft = CHTML.Em(-bbox.l); 622 if (bbox.r > bbox.w) style.marginRight = CHTML.Em(bbox.r-bbox.w); 623 // 624 // Get height and width of zoomed math and original math 625 // 626 style.position = "absolute"; 627 var zW = node.offsetWidth, zH = node.offsetHeight, 628 mH = math.firstChild.offsetHeight, mW = math.firstChild.offsetWidth; 629 node.style.position = ""; 630 // 631 return {Y:-EVENT.getBBox(span).h, mW:mW, mH:mH, zW:zW, zH:zH}; 632 }, 633 634 Remove: function (jax) { 635 var node = document.getElementById(jax.inputID+"-Frame"); 636 if (node && jax.CHTML.display) node = node.parentNode; 637 if (node) node.parentNode.removeChild(node); 638 delete jax.CHTML; 639 }, 640 641 /********************************************/ 642 643 ID: 0, idPostfix: "", 644 GetID: function () {this.ID++; return this.ID}, 645 646 /********************************************/ 647 648 MATHSPACE: { 649 veryverythinmathspace: 1/18, 650 verythinmathspace: 2/18, 651 thinmathspace: 3/18, 652 mediummathspace: 4/18, 653 thickmathspace: 5/18, 654 verythickmathspace: 6/18, 655 veryverythickmathspace: 7/18, 656 negativeveryverythinmathspace: -1/18, 657 negativeverythinmathspace: -2/18, 658 negativethinmathspace: -3/18, 659 negativemediummathspace: -4/18, 660 negativethickmathspace: -5/18, 661 negativeverythickmathspace: -6/18, 662 negativeveryverythickmathspace: -7/18, 663 664 thin: .04, 665 medium: .06, 666 thick: .1, 667 668 infinity: BIGDIMEN 669 }, 670 SPACECLASS: { 671 thinmathspace: "MJXc-space1", 672 mediummathspace: "MJXc-space2", 673 thickmathspace: "MJXc-space3" 674 }, 675 pxPerInch: 96, 676 em: 16, 677 678 maxStretchyParts: 1000, // limit the number of parts allowed for 679 // stretchy operators. See issue 366. 680 681 FONTDEF: {}, 682 TEXDEF: { 683 x_height: .442, 684 quad: 1, 685 num1: .676508, 686 num2: .393732, 687 num3: .44373, 688 denom1: .685951, 689 denom2: .344841, 690 sup1: .412892, 691 sup2: .362892, 692 sup3: .288888, 693 sub1: .15, 694 sub2: .247217, 695 sup_drop: .386108, 696 sub_drop: .05, 697 delim1: 2.39, 698 delim2: 1.0, 699 axis_height: .25, 700 rule_thickness: .06, 701 big_op_spacing1: .111111, 702 big_op_spacing2: .166666, 703 big_op_spacing3: .2, 704 big_op_spacing4: .45, //.6, // better spacing for under arrows and braces 705 big_op_spacing5: .1, 706 707 surd_height: .075, 708 709 scriptspace: .05, 710 nulldelimiterspace: .12, 711 delimiterfactor: 901, 712 delimitershortfall: .3, 713 714 min_rule_thickness: 1.25 // in pixels 715 }, 716 717 /********************************************************/ 718 719 // 720 // Get a unicode character by number (even when it takes two character) 721 // 722 unicodeChar: function (n) { 723 if (n < 0xFFFF) return String.fromCharCode(n); 724 n -= 0x10000; 725 return String.fromCharCode((n>>10)+0xD800) + String.fromCharCode((n&0x3FF)+0xDC00); 726 }, 727 // 728 // Get the unicode number of a (possibly multi-character) string 729 // 730 getUnicode: function (string) { 731 var n = string.text.charCodeAt(string.i); string.i++; 732 if (n >= 0xD800 && n < 0xDBFF) { 733 n = (((n-0xD800)<<10)+(string.text.charCodeAt(string.i)-0xDC00))+0x10000; 734 string.i++; 735 } 736 return n; 737 }, 738 // 739 // Get the list of actions for a given character in a given variant 740 // (processing remaps, multi-character results, and so on). Results are 741 // cached so that future lookups for the same variant/n pair will not 742 // require looking through the data again. 743 // 744 getCharList: function (variant,n) { 745 var id, M, list = [], cache = variant.cache, nn = n; 746 if (cache[n]) return cache[n]; 747 var RANGES = this.FONTDATA.RANGES, VARIANT = this.FONTDATA.VARIANT; 748 if (n >= RANGES[0].low && n <= RANGES[RANGES.length-1].high) { 749 for (id = 0, M = RANGES.length; id < M; id++) { 750 if (RANGES[id].name === "alpha" && variant.noLowerCase) continue; 751 var N = variant["offset"+RANGES[id].offset]; 752 if (N && n >= RANGES[id].low && n <= RANGES[id].high) { 753 if (RANGES[id].remap && RANGES[id].remap[n]) { 754 n = N + RANGES[id].remap[n]; 755 } else { 756 n = n - RANGES[id].low + N; 757 if (RANGES[id].add) {n += RANGES[id].add} 758 } 759 if (variant["variant"+RANGES[id].offset]) 760 variant = VARIANT[variant["variant"+RANGES[id].offset]]; 761 break; 762 } 763 } 764 } 765 if (variant.remap && variant.remap[n]) { 766 n = variant.remap[n]; 767 if (variant.remap.variant) {variant = VARIANT[variant.remap.variant]} 768 } else if (this.FONTDATA.REMAP[n] && !variant.noRemap) { 769 n = this.FONTDATA.REMAP[n]; 770 } 771 if (n instanceof Array) {variant = VARIANT[n[1]]; n = n[0]} 772 if (typeof(n) === "string") { 773 var string = {text:n, i:0, length:n.length}; 774 while (string.i < string.length) { 775 n = this.getUnicode(string); 776 var chars = this.getCharList(variant,n); 777 if (chars) list.push.apply(list,chars); 778 } 779 } else { 780 if (variant.cache[n]) {list = variant.cache[n]} 781 else {variant.cache[n] = list = [this.lookupChar(variant,n)]} 782 } 783 cache[nn] = list; 784 return list; 785 }, 786 // 787 // After all remapping has been done, look up a character 788 // in the fonts for a given variant, chaining to other 789 // variants as needed. Return an undefined character if 790 // it isnt' found in the given variant. 791 // 792 lookupChar: function (variant,n) { 793 var VARIANT = variant; 794 while (variant) { 795 for (var i = 0, m = variant.fonts.length; i < m; i++) { 796 var font = this.FONTDATA.FONTS[variant.fonts[i]]; 797 if (typeof(font) === "string") this.loadFont(font); 798 var C = font[n]; 799 if (C) { 800 if (C.length === 5) C[5] = {}; 801 if (C.c == null) { 802 C[0] /= 1000; C[1] /= 1000; C[2] /= 1000; C[3] /= 1000; C[4] /= 1000; 803 C.c = this.unicodeChar(n); 804 } 805 if (C[5].space) return {type:"space", w:C[2], font:font}; 806 return {type:"char", font:font, n:n}; 807 } else if (font.Extra) { 808 this.findBlock(font,n); 809 } 810 } 811 variant = this.FONTDATA.VARIANT[variant.chain]; 812 } 813 return this.unknownChar(VARIANT,n); 814 }, 815 findBlock: function (font,n) { 816 var extra = font.Extra, name = font.file, file; 817 for (var i = 0, m = extra.length; i < m; i++) { 818 if (typeof(extra[i]) === "number") { 819 if (n === extra[i]) {file = name; break} 820 } else { 821 if (n < extra[i][0]) return; 822 if (n <= extra[i][1]) {file = name; break} 823 } 824 } 825 // 826 // Currently this only loads one extra file, but that 827 // might need to be expanded in the future. 828 // 829 if (file) {delete font.Extra; this.loadFont(name)} 830 }, 831 // 832 // Create a fake font entry for an unknown character. 833 // 834 unknownChar: function (variant,n) { 835 HUB.signal.Post(["CommonHTML Jax - unknown char",n,variant]); 836 var id = ""; if (variant.bold) id += "B"; if (variant.italic) id += "I"; 837 var unknown = this.FONTDATA.UNKNOWN[id||"R"]; // cache of previously measured characters 838 if (!unknown[n]) this.getUnknownChar(unknown,n); 839 return {type:"unknown", n:n, font:unknown}; 840 }, 841 getUnknownChar: function (unknown,n) { 842 var c = this.unicodeChar(n); 843 var HDW = this.getHDW(c,unknown.className); 844 // ### FIXME: provide a means of setting the height and depth for individual characters 845 unknown[n] = [.8,.2,HDW.w,0,HDW.w,{a:Math.max(0,(HDW.h-HDW.d)/2), h:HDW.h, d:HDW.d}]; 846 unknown[n].c = c; 847 }, 848 styledText: function (variant,text) { 849 HUB.signal.Post(["CommonHTML Jax - styled text",text,variant]); 850 var style = variant.style; 851 var id = "_"+(style["font-family"]||variant.className||""); 852 if (style["font-weight"]) id += "_"+style["font-weight"]; 853 if (style["font-style"]) id += "_"+style["font-style"]; 854 if (!this.STYLEDTEXT) this.STYLEDTEXT = {}; 855 if (!this.STYLEDTEXT[id]) this.STYLEDTEXT[id] = {className:variant.className||""}; 856 var unknown = this.STYLEDTEXT[id]; 857 if (!unknown["_"+text]) { 858 var HDW = this.getHDW(text,variant.className||"",style); 859 unknown["_"+text] = [.8,.2,HDW.w,0,HDW.w,{a:Math.max(0,(HDW.h-HDW.d)/2), h:HDW.h, d:HDW.d}]; 860 unknown["_"+text].c = text; 861 } 862 return {type:"unknown", n:"_"+text, font:unknown, style:style, rscale:variant.rscale}; 863 }, 864 865 // 866 // Get the height, depth, and width of a character 867 // (height and depth are of the font, not the character). 868 // WARNING: causes reflow of the page! 869 // 870 getHDW: function (c,name,styles) { 871 var test1 = CHTML.addElement(CHTML.CHTMLnode,"mjx-chartest",{className:name},[["mjx-char",{style:styles},[c]]]); 872 var test2 = CHTML.addElement(CHTML.CHTMLnode,"mjx-chartest",{className:name},[["mjx-char",{style:styles},[c,["mjx-box"]]]]); 873 test1.firstChild.style.fontSize = test2.firstChild.style.fontSize = ""; 874 var em = 5*CHTML.em; 875 var H1 = test1.offsetHeight, H2 = test2.offsetHeight, W = test1.offsetWidth; 876 CHTML.CHTMLnode.removeChild(test1); 877 CHTML.CHTMLnode.removeChild(test2); 878 if (H2 === 0) { 879 em = 5*CHTML.defaultEm; 880 var test = document.body.appendChild(document.createElement("div")); 881 test.appendChild(test1); test.appendChild(test2); 882 H1 = test1.offsetHeight, H2 = test2.offsetHeight, W = test1.offsetWidth; 883 document.body.removeChild(test); 884 } 885 var d = (H2-1000)/em, w = W/em, h = H1/em - d; 886 return {h:h, d:d, w:w} 887 }, 888 889 890 /********************************************************/ 891 892 // 893 // Process a character list into a given node and return 894 // the updated bounding box. 895 // 896 addCharList: function (node,list,bbox) { 897 var state = {text:"", className:null, a:0}; 898 for (var i = 0, m = list.length; i < m; i++) { 899 var item = list[i]; 900 if (this.charList[item.type]) (this.charList[item.type])(item,node,bbox,state,m); 901 } 902 if (state.text !== "") { 903 if (node.childNodes.length) { 904 this.charList.flushText(node,state); 905 } else { 906 HTML.addText(node,state.text); 907 if (node.className) node.className += " "+state.className; 908 else node.className = state.className; 909 } 910 } 911 bbox.b = (state.flushed ? 0 : bbox.a); 912 }, 913 // 914 // The various item types are processed by these 915 // functions. 916 // 917 charList: { 918 // 919 // Character from the known fonts 920 // 921 "char": function (item,node,bbox,state,m) { 922 var font = item.font; 923 if (state.className && font.className !== state.className) this.flushText(node,state); 924 if (!state.a) state.a = font.centerline/1000; 925 if (state.a > (bbox.a||0)) bbox.a = state.a; 926 var C = font[item.n]; 927 state.text += C.c; state.className = font.className; 928 if (bbox.h < C[0]+HFUZZ) bbox.t = bbox.h = C[0]+HFUZZ; 929 if (bbox.d < C[1]+DFUZZ) bbox.b = bbox.d = C[1]+DFUZZ; 930 if (bbox.l > bbox.w+C[3]) bbox.l = bbox.w+C[3]; 931 if (bbox.r < bbox.w+C[4]) bbox.r = bbox.w+C[4]; 932 bbox.w += C[2] * (item.rscale||1); 933 if (m == 1 && font.skew && font.skew[item.n]) bbox.skew = font.skew[item.n]; 934 if (C[5].rfix) this.flushText(node,state).style.marginRight = CHTML.Em(C[5].rfix/1000); 935 }, 936 // 937 // Space characters (not actually in the fonts) 938 // 939 space: function (item,node,bbox,state) { 940 if (item.w) { 941 if (state.text === "") state.className = item.font.className; 942 this.flushText(node,state).style.marginRight = CHTML.Em(item.w); 943 bbox.w += item.w; 944 } 945 }, 946 // 947 // An unknown character (one not in the font data) 948 // 949 unknown: function (item,node,bbox,state) { 950 (this["char"])(item,node,bbox,state,0); 951 var C = item.font[item.n]; 952 if (C[5].a) { 953 state.a = C[5].a; 954 if (bbox.a == null || state.a > bbox.a) bbox.a = state.a; 955 } 956 node = this.flushText(node,state,item.style); 957 node.style.width = CHTML.Em(C[2]); 958 }, 959 // 960 // Put the pending text into a box of the class, and 961 // reset the data about the text. 962 // 963 flushText: function (node,state,style) { 964 node = CHTML.addElement(node,"mjx-charbox", 965 {className:state.className,style:style},[state.text]); 966 if (state.a) node.style.paddingBottom = CHTML.Em(state.a); 967 state.text = ""; state.className = null; state.a = 0; state.flushed = true; 968 return node; 969 } 970 }, 971 972 // 973 // Add the given text (in the given variant) into the given node, and 974 // update the bounding box of the result. Make sure the node's DOM 975 // bounding box matches the contents. 976 // 977 handleText: function (node,text,variant,bbox) { 978 if (node.childNodes.length === 0) { 979 CHTML.addElement(node,"mjx-char"); 980 bbox = CHTML.BBOX.empty(bbox); 981 } 982 if (typeof(variant) === "string") variant = this.FONTDATA.VARIANT[variant]; 983 if (!variant) variant = this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]; 984 var string = {text:text, i:0, length:text.length}, list = []; 985 if (variant.style && string.length) { 986 list.push(this.styledText(variant,text)); 987 } else { 988 while (string.i < string.length) { 989 var n = this.getUnicode(string); 990 list.push.apply(list,this.getCharList(variant,n)); 991 } 992 } 993 if (list.length) this.addCharList(node.firstChild,list,bbox); 994 bbox.clean(); 995 if (bbox.d < 0) {bbox.D = bbox.d; bbox.d = 0} 996 if (bbox.h - bbox.a) node.firstChild.style[bbox.h - bbox.a < 0 ? "marginTop" : "paddingTop"] = this.EmRounded(bbox.h-bbox.a); 997 if (bbox.d > -bbox.b) node.firstChild.style.paddingBottom = this.EmRounded(bbox.d+bbox.b); 998 return bbox; 999 }, 1000 1001 /********************************************************/ 1002 1003 createDelimiter: function (node,code,HW,BBOX,font) { 1004 if (!code) { 1005 var bbox = this.BBOX.zero(); 1006 bbox.w = bbox.r = this.TEX.nulldelimiterspace; 1007 CHTML.addElement(node,"mjx-box",{style:{width:bbox.w}}); 1008 return bbox; 1009 } 1010 if (!(HW instanceof Array)) HW = [HW,HW]; 1011 var hw = HW[1]; HW = HW[0]; 1012 var delim = {alias: code}; 1013 while (delim.alias) { 1014 code = delim.alias; delim = this.FONTDATA.DELIMITERS[code]; 1015 if (!delim) {delim = {HW: [0,this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]]}} 1016 } 1017 if (delim.load) HUB.RestartAfter(AJAX.Require(this.fontDir+"/TeX/fontdata-"+delim.load+".js")); 1018 for (var i = 0, m = delim.HW.length; i < m; i++) { 1019 if (delim.HW[i][0] >= HW-.01 || (i == m-1 && !delim.stretch)) { 1020 if (delim.HW[i][3]) code = delim.HW[i][3]; 1021 bbox = this.createChar(node,[code,delim.HW[i][1]],(delim.HW[i][2]||1),font); 1022 bbox.offset = .6 * bbox.w; 1023 if (BBOX) {bbox.scale = BBOX.scale; BBOX.rscale = BBOX.rscale} 1024 return bbox; 1025 } 1026 } 1027 if (!delim.stretch) return bbox; 1028 return this["extendDelimiter"+delim.dir](node,hw,delim.stretch,BBOX,font); 1029 }, 1030 extendDelimiterV: function (node,H,delim,BBOX,font) { 1031 node = CHTML.addElement(node,"mjx-delim-v"); var tmp = CHTML.Element("span"); 1032 var top, bot, mid, ext, tbox, bbox, mbox, ebox, k = 1, c; 1033 tbox = this.createChar(tmp,(delim.top||delim.ext),1,font); top = tmp.removeChild(tmp.firstChild); 1034 bbox = this.createChar(tmp,(delim.bot||delim.ext),1,font); bot = tmp.removeChild(tmp.firstChild); 1035 mbox = ebox = CHTML.BBOX.zero(); 1036 var h = tbox.h + tbox.d + bbox.h + bbox.d - EFUZZ; 1037 node.appendChild(top); 1038 if (delim.mid) { 1039 mbox = this.createChar(tmp,delim.mid,1,font); mid = tmp.removeChild(tmp.firstChild); 1040 h += mbox.h + mbox.d; k = 2; 1041 } 1042 if (delim.min && H < h*delim.min) H = h*delim.min; 1043 if (H > h) { 1044 ebox = this.createChar(tmp,delim.ext,1,font); ext = tmp.removeChild(tmp.firstChild); 1045 var eH = ebox.h + ebox.d, eh = eH - EFUZZ; 1046 var n = Math.min(Math.ceil((H-h)/(k*eh)),this.maxStretchyParts); 1047 if (delim.fullExtenders) H = n*k*eh + h; else eh = (H-h)/(k*n); 1048 c = ebox.d + ebox.a - eH/2; // for centering of extenders 1049 ext.style.margin = ext.style.padding = ""; 1050 ext.style.lineHeight = CHTML.Em(eh); 1051 ext.style.marginBottom = CHTML.Em(c-EFUZZ/2/k); 1052 ext.style.marginTop = CHTML.Em(-c-EFUZZ/2/k); 1053 var TEXT = ext.textContent, text = "\n"+TEXT; 1054 while (--n > 0) TEXT += text; 1055 ext.textContent = TEXT; 1056 node.appendChild(ext); 1057 if (delim.mid) { 1058 node.appendChild(mid); 1059 node.appendChild(ext.cloneNode(true)); 1060 } 1061 } else { 1062 c = (H-h-EFUZZ) / k; 1063 top.style.marginBottom = CHTML.Em(c+parseFloat(top.style.marginBottom||"0")); 1064 if (delim.mid) node.appendChild(mid); 1065 bot.style.marginTop = CHTML.Em(c+parseFloat(bot.style.marginTop||"0")); 1066 } 1067 node.appendChild(bot); 1068 var vbox = CHTML.BBOX({ 1069 w: Math.max(tbox.w,ebox.w,bbox.w,mbox.w), 1070 l: Math.min(tbox.l,ebox.l,bbox.l,mbox.l), 1071 r: Math.max(tbox.r,ebox.r,bbox.r,mbox.r), 1072 h: H-bbox.d, d: bbox.d, t: H-bbox.d, b: bbox.d 1073 }); 1074 vbox.offset = .5 * vbox.w; 1075 if (BBOX) {vbox.scale = BBOX.scale; vbox.rscale = BBOX.rscale} 1076 return vbox; 1077 }, 1078 extendDelimiterH: function (node,W,delim,BBOX,font) { 1079 node = CHTML.addElement(node,"mjx-delim-h"); var tmp = CHTML.Element("span"); 1080 var left, right, mid, ext, ext2, lbox, rbox, mbox, ebox, k = 1; 1081 lbox = this.createChar(tmp,(delim.left||delim.rep),1,font); left = tmp.removeChild(tmp.firstChild); 1082 rbox = this.createChar(tmp,(delim.right||delim.rep),1,font); right = tmp.removeChild(tmp.firstChild); 1083 ebox = this.createChar(tmp,delim.rep,1,font); ext = tmp.removeChild(tmp.firstChild); 1084 left.style.marginLeft = CHTML.Em(-lbox.l); 1085 right.style.marginRight = CHTML.Em(rbox.r-rbox.w); 1086 node.appendChild(left); 1087 var hbox = CHTML.BBOX.zero(); 1088 hbox.h = Math.max(lbox.h,rbox.h,ebox.h); 1089 hbox.d = Math.max(lbox.D||lbox.d,rbox.D||rbox.d,ebox.D||ebox.d); 1090 var w = (lbox.r - lbox.l) + (rbox.r - rbox.l) - EFUZZ; 1091 if (delim.mid) { 1092 mbox = this.createChar(tmp,delim.mid,1,font); 1093 mid = tmp.removeChild(tmp.firstChild); 1094 mid.style.marginleft = CHTML.Em(-mbox.l); mid.style.marginRight = CHTML.Em(mbox.r-mbox.w); 1095 w += mbox.r - mbox.l + EFUZZ; k = 2; 1096 if (mbox.h > hbox.h) hbox.h = mbox.h; 1097 if (mbox.d > hbox.d) hbox.d = mbox.d; 1098 } 1099 if (delim.min && W < w*delim.min) W = w*delim.min; 1100 hbox.w = hbox.r = W; 1101 if (W > w) { 1102 var eW = ebox.r-ebox.l, ew = eW - EFUZZ; 1103 var n = Math.min(Math.ceil((W-w)/(k*ew)),this.maxStretchyParts); 1104 if (delim.fullExtenders) W = n*k*ew + w; else ew = (W-w)/(k*n); 1105 var c = (eW - ew + EFUZZ/k) / 2; // for centering of extenders 1106 ext.style.marginLeft = CHTML.Em(-ebox.l-c); 1107 ext.style.marginRight = CHTML.Em(ebox.r-ebox.w+c); 1108 ext.style.letterSpacing = CHTML.Em(-(ebox.w-ew)); 1109 left.style.marginRight = CHTML.Em(lbox.r-lbox.w); 1110 right.style.marginleft = CHTML.Em(-rbox.l); 1111 var TEXT = ext.textContent, text = TEXT; 1112 while (--n > 0) TEXT += text; 1113 ext.textContent = TEXT; 1114 node.appendChild(ext); 1115 if (delim.mid) { 1116 node.appendChild(mid); 1117 ext2 = node.appendChild(ext.cloneNode(true)); 1118 } 1119 } else { 1120 c = (W-w-EFUZZ/k) / 2; 1121 left.style.marginRight = CHTML.Em(lbox.r-lbox.w+c); 1122 if (delim.mid) node.appendChild(mid); 1123 right.style.marginLeft = CHTML.Em(-rbox.l+c); 1124 } 1125 node.appendChild(right); 1126 this.adjustHeights([left,ext,mid,ext2,right],[lbox,ebox,mbox,ebox,rbox],hbox); 1127 if (BBOX) {hbox.scale = BBOX.scale; hbox.rscale = BBOX.rscale} 1128 return hbox; 1129 }, 1130 adjustHeights: function (nodes,box,bbox) { 1131 // 1132 // To get alignment right in horizontal delimiters, we force all 1133 // the elements to the same height and depth 1134 // 1135 var T = bbox.h, B = bbox.d; 1136 if (bbox.d < 0) {B = -bbox.d; bbox.D = bbox.d; bbox.d = 0} 1137 for (var i = 0, m = nodes.length; i < m; i++) if (nodes[i]) { 1138 nodes[i].style.paddingTop = CHTML.Em(T-box[i].a); 1139 nodes[i].style.paddingBottom = CHTML.Em(B+box[i].a); 1140 nodes[i].style.marginTop = nodes[i].style.marginBottom = 0; 1141 } 1142 }, 1143 createChar: function (node,data,scale,font) { 1144 // ### FIXME: handle cache better (by data[1] and font) 1145 var text = "", variant = {fonts: [data[1]], noRemap:true, cache:{}}; 1146 if (font && font === MML.VARIANT.BOLD && this.FONTDATA.FONTS[data[1]+"-Bold"]) 1147 variant.fonts = [data[1]+"-Bold",data[1]]; 1148 if (typeof(data[1]) !== "string") variant = data[1]; 1149 if (data[0] instanceof Array) { 1150 for (var i = 0, m = data[0].length; i < m; i++) text += String.fromCharCode(data[0][i]); 1151 } else text = String.fromCharCode(data[0]); 1152 if (data[4]) scale *= data[4]; 1153 var bbox = this.handleText(node,text,variant), style = node.firstChild.style; 1154 if (scale !== 1) style.fontSize = this.Percent(scale); 1155 if (data[2]) { // x offset 1156 style.paddingLeft = this.Em(data[2]); 1157 bbox.w += data[2]; bbox.r += data[2]; 1158 } 1159 if (data[3]) { // y offset 1160 style.verticalAlign = this.Em(data[3]); 1161 bbox.h += data[3]; if (bbox.h < 0) bbox.h = 0; 1162 } 1163 if (data[5]) { // extra height 1164 style.marginTop = this.Em(data[5]); 1165 bbox.h += data[5]; bbox.t += data[5]; 1166 } 1167 if (data[6]) { // extra depth 1168 style.marginBottom = this.Em(data[6]); 1169 bbox.d += data[6]; bbox.b += data[6]; 1170 } 1171 return bbox; 1172 }, 1173 1174 /********************************************************/ 1175 1176 // 1177 // ### FIXME: Handle mu's 1178 // 1179 length2em: function (length,size,scale) { 1180 if (typeof(length) !== "string") length = length.toString(); 1181 if (length === "") return ""; 1182 if (length === MML.SIZE.NORMAL) return 1; 1183 if (length === MML.SIZE.BIG) return 2; 1184 if (length === MML.SIZE.SMALL) return .71; 1185 if (this.MATHSPACE[length]) return this.MATHSPACE[length]; 1186 var match = length.match(/^\s*([-+]?(?:\.\d+|\d+(?:\.\d*)?))?(pt|em|ex|mu|px|pc|in|mm|cm|%)?/); 1187 var m = parseFloat(match[1]||"1"), unit = match[2]; 1188 if (size == null) size = 1; if (!scale) scale = 1; 1189 scale = 1 /this.em / scale; 1190 if (unit === "em") return m; 1191 if (unit === "ex") return m * this.TEX.x_height; 1192 if (unit === "%") return m / 100 * size; 1193 if (unit === "px") return m * scale; 1194 if (unit === "pt") return m / 10; // 10 pt to an em 1195 if (unit === "pc") return m * 1.2; // 12 pt to a pc 1196 scale *= this.pxPerInch; 1197 if (unit === "in") return m * scale; 1198 if (unit === "cm") return m * scale / 2.54; // 2.54 cm to an inch 1199 if (unit === "mm") return m * scale / 25.4; // 10 mm to a cm 1200 if (unit === "mu") return m / 18; // 18mu to an em for the scriptlevel 1201 return m*size; // relative to given size (or 1em as default) 1202 }, 1203 thickness2em: function (length,scale) { 1204 var thick = CHTML.TEX.rule_thickness/(scale||1); 1205 if (length === MML.LINETHICKNESS.MEDIUM) return thick; 1206 if (length === MML.LINETHICKNESS.THIN) return .67*thick; 1207 if (length === MML.LINETHICKNESS.THICK) return 1.67*thick; 1208 return this.length2em(length,thick,scale); 1209 }, 1210 1211 Em: function (m) { 1212 if (Math.abs(m) < .001) return "0"; 1213 return (m.toFixed(3).replace(/\.?0+$/,""))+"em"; 1214 }, 1215 EmRounded: function (m) { 1216 m = (Math.round(m*CHTML.em)+.05)/CHTML.em; 1217 if (Math.abs(m) < .0006) {return "0em"} 1218 return m.toFixed(3).replace(/\.?0+$/,"") + "em"; 1219 }, 1220 unEm: function (m) { 1221 return parseFloat(m); 1222 }, 1223 Px: function (m,M) { 1224 m *= this.em; 1225 if (M && m < M) m = M; 1226 if (Math.abs(m) < .1) return "0"; 1227 return m.toFixed(1).replace(/\.0$/,"")+"px"; 1228 }, 1229 1230 Percent: function (m) { 1231 return (100*m).toFixed(1).replace(/\.?0+$/,"") + "%"; 1232 }, 1233 1234 Transform: function (node,trans,origin) { 1235 var style = node.style; 1236 style.transform = style.WebkitTransform = style.MozTransform = style["-ms-transform"] = trans; 1237 if (origin) 1238 style.transformOrigin = style.WebkitTransformOrigin = 1239 style.MozTransformOrigin = style["-ms-transform-origin"] = origin; 1240 }, 1241 1242 /********************************************************/ 1243 1244 arrayEntry: function (a,i) {return a[Math.max(0,Math.min(i,a.length-1))]}, 1245 1246 // 1247 // Styles to be removed from style="..." attributes 1248 // 1249 removeStyles: ["fontSize","fontFamily","fontWeight","fontStyle","fontVariant","font"] 1250 1251 }); 1252 1253 /**********************************************************/ 1254 1255 CHTML.BBOX = MathJax.Object.Subclass({ 1256 Init: function (def) { 1257 for (var id in def) { 1258 if (def.hasOwnProperty(id)) this[id] = def[id]; 1259 } 1260 }, 1261 clean: function () { 1262 if (this.h === -BIGDIMEN) this.h = 0; 1263 if (this.d === -BIGDIMEN) this.d = 0; 1264 if (this.l === BIGDIMEN) this.l = 0; 1265 if (this.r === -BIGDIMEN) this.r = 0; 1266 if (this.t === -BIGDIMEN) this.t = 0; 1267 if (this.b === -BIGDIMEN) this.b = 0; 1268 if (this.D && this.d > 0) delete this.D; 1269 }, 1270 rescale: function (scale) { 1271 this.w *= scale; this.h *= scale; this.d *= scale; 1272 this.l *= scale; this.r *= scale; this.t *= scale; this.b *= scale; 1273 if (this.L) this.L *= scale; 1274 if (this.R) this.R *= scale; 1275 if (this.D) this.D *= scale; 1276 }, 1277 combine: function (cbox,x,y) { 1278 cbox.X = x; cbox.Y = y; // save for use with line breaking 1279 scale = cbox.rscale; 1280 if (x + scale*cbox.r > this.r) this.r = x + scale*cbox.r; 1281 if (x + scale*cbox.l < this.l) this.l = x + scale*cbox.l; 1282 if (x + scale*(cbox.w+(cbox.L||0)+(cbox.R||0)) > this.w) 1283 this.w = x + scale*(cbox.w + (cbox.L||0) + (cbox.R||0)); 1284 if (y + scale*cbox.h > this.h) this.h = y + scale*cbox.h; 1285 if (cbox.D && (this.D == null || scale*cbox.D - y > this.D) && scale*cbox.D > this.d) this.D = scale*cbox.D - y; 1286 else if (cbox.D == null && this.D) delete this.D; 1287 if (scale*cbox.d - y > this.d) this.d = scale*cbox.d - y; 1288 if (y + scale*cbox.t > this.t) this.t = y + scale*cbox.t; 1289 if (scale*cbox.b - y > this.b) this.b = scale*cbox.b - y; 1290 }, 1291 append: function (cbox) { 1292 scale = cbox.rscale; var x = this.w; 1293 if (x + scale*cbox.r > this.r) this.r = x + scale*cbox.r; 1294 if (x + scale*cbox.l < this.l) this.l = x + scale*cbox.l; 1295 this.w += scale*(cbox.w+(cbox.L||0)+(cbox.R||0)) ; 1296 if (scale*cbox.h > this.h) this.h = scale*cbox.h; 1297 if (cbox.D && (this.D == null || scale*cbox.D > this.D) && scale*cbox.D > this.d) this.D = scale*cbox.D; 1298 else if (cbox.D == null && this.D) delete this.D; 1299 if (scale*cbox.d > this.d) this.d = scale*cbox.d; 1300 if (scale*cbox.t > this.t) this.t = scale*cbox.t; 1301 if (scale*cbox.b > this.b) this.b = scale*cbox.b; 1302 }, 1303 updateFrom: function (cbox) { 1304 this.h = cbox.h; this.d = cbox.d; this.w = cbox.w; this.r = cbox.r; this.l = cbox.l; 1305 this.t = cbox.t; this.b = cbox.b; 1306 if (cbox.D) this.D = cbox.D; else delete this.D; 1307 }, 1308 adjust: function (m,x,X,M) { 1309 this[x] += CHTML.length2em(m,1,this.scale); 1310 if (M == null) { 1311 if (this[x] > this[X]) this[X] = this[x]; 1312 } else { 1313 if (this[X] < M) this[X] = M; 1314 } 1315 } 1316 },{ 1317 zero: function () { 1318 return CHTML.BBOX({h:0, d:0, w:0, l:0, r:0, t:0, b:0, scale:1, rscale:1}); 1319 }, 1320 empty: function (bbox) { 1321 if (!bbox) bbox = CHTML.BBOX.zero(); 1322 bbox.h = bbox.d = bbox.r = bbox.t = bbox.b = -BIGDIMEN; 1323 bbox.w = 0; bbox.l = BIGDIMEN; 1324 return bbox; 1325 }, 1326 // 1327 // CSS styles that affect BBOXes 1328 // 1329 styleAdjust: [ 1330 ["borderTopWidth","h","t"], 1331 ["borderRightWidth","w","r"], 1332 ["borderBottomWidth","d","b"], 1333 ["borderLeftWidth","w","l",0], 1334 ["paddingTop","h","t"], 1335 ["paddingRight","w","r"], 1336 ["paddingBottom","d","b"], 1337 ["paddingLeft","w","l",0], 1338 ] 1339 }); 1340 1341 /**********************************************************/ 1342 1343 MathJax.Hub.Register.StartupHook("mml Jax Ready",function () { 1344 MML = MathJax.ElementJax.mml; 1345 1346 /********************************************************/ 1347 1348 MML.mbase.Augment({ 1349 toCommonHTML: function (node,options) { 1350 return this.CHTMLdefaultNode(node,options); 1351 }, 1352 CHTMLmultiline: function () {MML.mbase.CHTMLautoloadFile("multiline")}, 1353 1354 CHTMLdefaultNode: function (node,options) { 1355 if (!options) options = {}; 1356 node = this.CHTMLcreateNode(node); this.CHTML = CHTML.BBOX.empty(); 1357 this.CHTMLhandleStyle(node); 1358 this.CHTMLhandleScale(node); 1359 if (this.isToken) this.CHTMLgetVariant(); 1360 var m = Math.max((options.minChildren||0),this.data.length); 1361 for (var i = 0; i < m; i++) this.CHTMLaddChild(node,i,options); 1362 if (!options.noBBox) this.CHTML.clean(); 1363 this.CHTMLhandleSpace(node); 1364 this.CHTMLhandleBBox(node); 1365 this.CHTMLhandleColor(node); 1366 return node; 1367 }, 1368 CHTMLaddChild: function (node,i,options) { 1369 var child = this.data[i], cnode; 1370 if (child) { 1371 var type = options.childNodes; 1372 if (type) { 1373 if (type instanceof Array) type = type[i]||"span"; 1374 node = CHTML.addElement(node,type); 1375 } 1376 cnode = child.toCommonHTML(node,options.childOptions); 1377 if (type && child.CHTML.rscale !== 1) { 1378 // move scale factor to outer container (which seems to be more accurate) 1379 node.style.fontSize = node.firstChild.style.fontSize; 1380 node.firstChild.style.fontSize = ""; 1381 } 1382 if (!options.noBBox) { 1383 var bbox = this.CHTML, cbox = child.CHTML; 1384 bbox.append(cbox); 1385 if (cbox.ic) {bbox.ic = cbox.ic} else {delete bbox.ic} 1386 if (cbox.skew) bbox.skew = cbox.skew; 1387 if (cbox.pwidth) bbox.pwidth = cbox.pwidth; 1388 } 1389 } else if (options.forceChild) {cnode = CHTML.addElement(node,"mjx-box")} 1390 return cnode; 1391 }, 1392 1393 CHTMLchildNode: function (node,i) { 1394 node = node.childNodes[i]; 1395 if (node.nodeName.toLowerCase() === "a") node = node.firstChild; 1396 return node; 1397 }, 1398 CHTMLcoreNode: function (node) { 1399 return this.CHTMLchildNode(node,this.CoreIndex()); 1400 }, 1401 1402 CHTMLstretchChildV: function (i,H,D) { 1403 var data = this.data[i]; 1404 if (data) { 1405 var bbox = this.CHTML, dbox = data.CHTML; 1406 if (dbox.stretch || (dbox.stretch == null && data.CHTMLcanStretch("Vertical",H,D))) { 1407 var w = dbox.w; 1408 dbox = data.CHTMLstretchV(H,D); 1409 bbox.w += dbox.w - w; 1410 if (bbox.w > bbox.r) bbox.r = bbox.w; 1411 if (dbox.h > bbox.h) bbox.h = dbox.h; 1412 if (dbox.d > bbox.d) bbox.d = dbox.d; 1413 if (dbox.t > bbox.t) bbox.t = dbox.t; 1414 if (dbox.b > bbox.b) bbox.b = dbox.b; 1415 } 1416 } 1417 }, 1418 CHTMLstretchChildH: function (i,W,node) { 1419 var data = this.data[i]; 1420 if (data) { 1421 var bbox = this.CHTML, dbox = data.CHTML; 1422 if (dbox.stretch || (dbox.stretch == null && data.CHTMLcanStretch("Horizontal",W))) { 1423 var w = dbox.w; 1424 dbox = data.CHTMLstretchH(this.CHTMLchildNode(node,i),W); 1425 bbox.w += dbox.w - w; 1426 if (bbox.w > bbox.r) bbox.r = bbox.w; 1427 if (dbox.h > bbox.h) bbox.h = dbox.h; 1428 if (dbox.d > bbox.d) bbox.d = dbox.d; 1429 if (dbox.t > bbox.t) bbox.t = dbox.t; 1430 if (dbox.b > bbox.b) bbox.b = dbox.b; 1431 } 1432 } 1433 }, 1434 1435 CHTMLcanStretch: function (direction,H,D) { 1436 var stretch = false; 1437 if (this.isEmbellished()) { 1438 var core = this.Core(); 1439 if (core && core !== this) stretch = core.CHTMLcanStretch(direction,H,D); 1440 } 1441 this.CHTML.stretch = stretch; 1442 return stretch; 1443 }, 1444 CHTMLstretchV: function (h,d) { 1445 this.CHTML.updateFrom(this.Core().CHTMLstretchV(h,d)); 1446 return this.CHTML; 1447 }, 1448 CHTMLstretchH: function (node,w) { 1449 this.CHTML.updateFrom(this.CHTMLstretchCoreH(node,w)); 1450 return this.CHTML; 1451 }, 1452 CHTMLstretchCoreH: function (node,w) { 1453 return this.Core().CHTMLstretchH(this.CHTMLcoreNode(node),w); 1454 }, 1455 1456 CHTMLcreateNode: function (node) { 1457 if (!this.CHTML) this.CHTML = {}; 1458 this.CHTML = CHTML.BBOX.zero(); 1459 if (this.href) node = CHTML.addElement(node,"a",{href:this.href, isMathJax:true}); 1460 if (!this.CHTMLnodeID) this.CHTMLnodeID = CHTML.GetID(); 1461 var id = (this.id || "MJXc-Node-"+this.CHTMLnodeID)+CHTML.idPostfix; 1462 return this.CHTMLhandleAttributes(CHTML.addElement(node,"mjx-"+this.type,{id:id})); 1463 }, 1464 CHTMLnodeElement: function () { 1465 if (!this.CHTMLnodeID) {return null} 1466 return document.getElementById((this.id||"MJXc-Node-"+this.CHTMLnodeID)+CHTML.idPostfix); 1467 }, 1468 1469 CHTMLlength2em: function (length,size) { 1470 return CHTML.length2em(length,size,this.CHTML.scale); 1471 }, 1472 1473 CHTMLhandleAttributes: function (node) { 1474 if (this["class"]) { 1475 if (node.className) node.className += " "+this["class"]; 1476 else node.className = this["class"]; 1477 } 1478 // 1479 // Copy RDFa, aria, and other tags from the MathML to the CHTML 1480 // output nodes. Don't copy those in the MML.nocopyAttributes list, 1481 // the ignoreMMLattributes configuration list, or anything that 1482 // already exists as a property of the node (e.g., no "onlick", etc.) 1483 // If a name in the ignoreMMLattributes object is set to false, then 1484 // the attribute WILL be copied. 1485 // 1486 if (this.attrNames) { 1487 var copy = this.attrNames, skip = MML.nocopyAttributes, ignore = HUB.config.ignoreMMLattributes; 1488 var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults); 1489 for (var i = 0, m = copy.length; i < m; i++) { 1490 var id = copy[i]; 1491 if (ignore[id] == false || (!skip[id] && !ignore[id] && 1492 defaults[id] == null && typeof(node[id]) === "undefined")) { 1493 node.setAttribute(id,this.attr[id]) 1494 } 1495 } 1496 } 1497 return node; 1498 }, 1499 1500 CHTMLhandleScale: function (node) { 1501 var scale = 1, parent = this.parent, pscale = (parent ? parent.CHTML.scale : 1); 1502 var values = this.getValues("scriptlevel","fontsize"); 1503 values.mathsize = this.Get("mathsize",null,!this.isToken); 1504 if (values.scriptlevel !== 0) { 1505 if (values.scriptlevel > 2) values.scriptlevel = 2; 1506 scale = Math.pow(this.Get("scriptsizemultiplier"),values.scriptlevel); 1507 values.scriptminsize = CHTML.length2em(this.Get("scriptminsize"),.8,1); 1508 if (scale < values.scriptminsize) scale = values.scriptminsize; 1509 } 1510 if (this.removedStyles && this.removedStyles.fontSize && !values.fontsize) 1511 values.fontsize = this.removedStyles.fontSize; 1512 if (values.fontsize && !this.mathsize) values.mathsize = values.fontsize; 1513 if (values.mathsize !== 1) scale *= CHTML.length2em(values.mathsize,1,1); 1514 this.CHTML.scale = scale; pscale = this.CHTML.rscale = scale/pscale; 1515 if (Math.abs(pscale-1) < .001) pscale = 1; 1516 if (node && pscale !== 1) node.style.fontSize = CHTML.Percent(pscale); 1517 return scale; 1518 }, 1519 1520 CHTMLhandleStyle: function (node) { 1521 if (!this.style) return; 1522 var style = node.style; 1523 style.cssText = this.style; this.removedStyles = {}; 1524 for (var i = 0, m = CHTML.removeStyles.length; i < m; i++) { 1525 var id = CHTML.removeStyles[i]; 1526 if (style[id]) { 1527 this.removedStyles[id] = style[id]; 1528 style[id] = ""; 1529 } 1530 } 1531 }, 1532 1533 CHTMLhandleBBox: function (node) { 1534 var BBOX = this.CHTML, style = node.style; 1535 if (this.data.length === 1 && (this.data[0].CHTML||{}).pwidth) { 1536 BBOX.pwidth = this.data[0].CHTML.pwidth; 1537 BBOX.mwidth = this.data[0].CHTML.mwidth; 1538 style.width = "100%"; 1539 } else if (BBOX.pwidth) { 1540 BBOX.mwidth = CHTML.Em(BBOX.w); 1541 style.width = "100%"; 1542 } else if (BBOX.w < 0) { 1543 style.width = "0px"; 1544 style.marginRight = CHTML.Em(BBOX.w); 1545 } 1546 if (!this.style) return; 1547 // ### FIXME: adjust for width, height, vertical-align? 1548 for (var i = 0, m = CHTML.BBOX.styleAdjust.length; i < m; i++) { 1549 var data = CHTML.BBOX.styleAdjust[i]; 1550 if (data && style[data[0]]) BBOX.adjust(style[data[0]],data[1],data[2],data[3]); 1551 } 1552 }, 1553 1554 CHTMLhandleColor: function (node) { 1555 if (this.mathcolor) {node.style.color = this.mathcolor} 1556 else if (this.color) {node.style.color = this.color} 1557 if (this.mathbackground) {node.style.backgroundColor = this.mathbackground} 1558 else if (this.background) {node.style.backgroundColor = this.background} 1559 }, 1560 1561 CHTMLhandleSpace: function (node) { 1562 if (!this.useMMLspacing) { 1563 var space = this.texSpacing(); 1564 if (space !== "") { 1565 this.CHTML.L = this.CHTMLlength2em(space); 1566 node.className += " "+CHTML.SPACECLASS[space]; 1567 } 1568 } 1569 }, 1570 1571 CHTMLhandleText: function (node,text,variant) { 1572 if (node.firstChild && !this.CHTML) this.CHTML = CHTML.BBOX.empty(); 1573 this.CHTML = CHTML.handleText(node,text,variant,this.CHTML); 1574 }, 1575 1576 CHTMLgetVariant: function () { 1577 var values = this.getValues("mathvariant","fontfamily","fontweight","fontstyle"), style; 1578 values.hasVariant = this.Get("mathvariant",true); // null if not explicitly specified 1579 if (this.removedStyles) { 1580 style = this.removedStyles; 1581 if (style.fontFamily) values.family = style.fontFamily; 1582 if (style.fontWeight) values.weight = style.fontWeight; 1583 if (style.fontStyle) values.style = style.fontStyle; 1584 } 1585 if (!values.hasVariant) { 1586 if (values.fontfamily) values.family = values.fontfamily; 1587 if (values.fontweight) values.weight = values.fontweight; 1588 if (values.fontstyle) values.style = values.fontstyle; 1589 } 1590 if (values.weight && values.weight.match(/^\d+$/)) 1591 values.weight = (parseInt(values.weight) > 600 ? "bold" : "normal"); 1592 var variant = values.mathvariant; if (this.variantForm) variant = "-TeX-variant"; 1593 if (values.family && !values.hasVariant) { 1594 if (!values.weight && values.mathvariant.match(/bold/)) values.weight = "bold"; 1595 if (!values.style && values.mathvariant.match(/italic/)) values.style = "italic"; 1596 this.CHTMLvariant = {fonts:[], noRemap:true, cache:{}, style: { 1597 "font-family":values.family, "font-weight":values.weight||"normal", "font-style":values.style||"normal" 1598 }}; 1599 return; 1600 } 1601 if (values.weight === "bold") { 1602 variant = { 1603 normal:MML.VARIANT.BOLD, italic:MML.VARIANT.BOLDITALIC, 1604 fraktur:MML.VARIANT.BOLDFRAKTUR, script:MML.VARIANT.BOLDSCRIPT, 1605 "sans-serif":MML.VARIANT.BOLDSANSSERIF, 1606 "sans-serif-italic":MML.VARIANT.SANSSERIFBOLDITALIC 1607 }[variant]||variant; 1608 } else if (values.weight === "normal") { 1609 variant = { 1610 bold:MML.VARIANT.normal, "bold-italic":MML.VARIANT.ITALIC, 1611 "bold-fraktur":MML.VARIANT.FRAKTUR, "bold-script":MML.VARIANT.SCRIPT, 1612 "bold-sans-serif":MML.VARIANT.SANSSERIF, 1613 "sans-serif-bold-italic":MML.VARIANT.SANSSERIFITALIC 1614 }[variant]||variant; 1615 } 1616 if (values.style === "italic") { 1617 variant = { 1618 normal:MML.VARIANT.ITALIC, bold:MML.VARIANT.BOLDITALIC, 1619 "sans-serif":MML.VARIANT.SANSSERIFITALIC, 1620 "bold-sans-serif":MML.VARIANT.SANSSERIFBOLDITALIC 1621 }[variant]||variant; 1622 } else if (values.style === "normal") { 1623 variant = { 1624 italic:MML.VARIANT.NORMAL, "bold-italic":MML.VARIANT.BOLD, 1625 "sans-serif-italic":MML.VARIANT.SANSSERIF, 1626 "sans-serif-bold-italic":MML.VARIANT.BOLDSANSSERIF 1627 }[variant]||variant; 1628 } 1629 this.CHTMLvariant = CHTML.FONTDATA.VARIANT[variant] || 1630 CHTML.FONTDATA.VARIANT[MML.VARIANT.NORMAL]; 1631 }, 1632 1633 CHTMLbboxFor: function (n) { 1634 if (this.data[n] && this.data[n].CHTML) return this.data[n].CHTML; 1635 return CHTML.BBOX.zero(); 1636 }, 1637 // 1638 // Debugging function to see if internal BBox matches actual bbox 1639 // 1640 CHTMLdrawBBox: function (node,bbox) { 1641 if (!bbox) bbox = this.CHTML; 1642 var box = CHTML.Element("mjx-box", 1643 {style:{opacity:.25,"margin-left":CHTML.Em(-(bbox.w+(bbox.R||0)))}},[ 1644 ["mjx-box",{style:{ 1645 height:CHTML.Em(bbox.h),width:CHTML.Em(bbox.w), 1646 "background-color":"red" 1647 }}], 1648 ["mjx-box",{style:{ 1649 height:CHTML.Em(bbox.d),width:CHTML.Em(bbox.w), 1650 "margin-left":CHTML.Em(-bbox.w),"vertical-align":CHTML.Em(-bbox.d), 1651 "background-color":"green" 1652 }}] 1653 ]); 1654 if (node.nextSibling) {node.parentNode.insertBefore(box,node.nextSibling)} 1655 else {node.parentNode.appendChild(box)} 1656 }, 1657 1658 CHTMLnotEmpty: function (mml) { 1659 while (mml && mml.data.length < 2 && (mml.type === "mrow" || mml.type === "texatom")) 1660 mml = mml.data[0]; 1661 return !!mml; 1662 } 1663 1664 },{ 1665 // 1666 // Autoload files based on node type or file name 1667 // 1668 CHTMLautoload: function () { 1669 var file = CHTML.autoloadDir+"/"+this.type+".js"; 1670 HUB.RestartAfter(AJAX.Require(file)); 1671 }, 1672 CHTMLautoloadFile: function (name) { 1673 var file = CHTML.autoloadDir+"/"+name+".js"; 1674 HUB.RestartAfter(AJAX.Require(file)); 1675 }, 1676 // 1677 // For use with embellished operators 1678 // 1679 CHTMLstretchV: function (h,d) { 1680 this.Core().CHTMLstretchV(h,d); 1681 this.toCommonHTML(this.CHTMLnodeElement(),true); 1682 return this.CHTML; 1683 }, 1684 CHTMLstretchH: function (node,w) { 1685 this.CHTMLstretchCoreH(node,w); 1686 this.toCommonHTML(node,true); 1687 return this.CHTML; 1688 } 1689 }); 1690 1691 /********************************************************/ 1692 1693 MML.chars.Augment({ 1694 toCommonHTML: function (node,options) { 1695 if (options == null) options = {}; 1696 var text = this.toString(); 1697 if (options.remap) text = options.remap(text,options.remapchars); 1698 this.CHTMLhandleText(node,text,options.variant||this.parent.CHTMLvariant); 1699 } 1700 }); 1701 MML.entity.Augment({ 1702 toCommonHTML: function (node,options) { 1703 if (options == null) options = {}; 1704 var text = this.toString(); 1705 if (options.remapchars) text = options.remap(text,options.remapchars); 1706 this.CHTMLhandleText(node,text,options.variant||this.parent.CHTMLvariant); 1707 } 1708 }); 1709 1710 /********************************************************/ 1711 1712 MML.math.Augment({ 1713 toCommonHTML: function (node) { 1714 node = this.CHTMLdefaultNode(node); 1715 if (this.CHTML.w < 0) { 1716 node.parentNode.style.width = "0px"; 1717 node.parentNode.style.marginRight = CHTML.Em(this.CHTML.w); 1718 } 1719 var alttext = this.Get("alttext"); 1720 if (alttext && !node.getAttribute("aria-label")) node.setAttribute("aria-label",alttext); 1721 if (!node.getAttribute("role")) node.setAttribute("role","math"); 1722 if (this.CHTML.pwidth) { 1723 node.parentNode.style.width = this.CHTML.pwidth; 1724 node.parentNode.style.minWidth = this.CHTML.mwidth||CHTML.Em(this.CHTML.w); 1725 } else if (!this.isMultiline && this.Get("display") === "block") { 1726 var values = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift"); 1727 if (values.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) values.indentalign = values.indentalignfirst; 1728 if (values.indentalign === MML.INDENTALIGN.AUTO) values.indentalign = CONFIG.displayAlign; 1729 if (values.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) values.indentshift = values.indentshiftfirst; 1730 if (values.indentshift === "auto") values.indentshift = "0"; 1731 var shift = this.CHTMLlength2em(values.indentshift,CHTML.cwidth); 1732 if (CONFIG.displayIndent !== "0") { 1733 var indent = this.CHTMLlength2em(CONFIG.displayIndent,CHTML.cwidth); 1734 shift += (values.indentalign === MML.INDENTALIGN.RIGHT ? -indent : indent); 1735 } 1736 var styles = node.parentNode.parentNode.style; 1737 styles.textAlign = values.indentalign; 1738 // ### FIXME: make percentage widths respond to changes in container 1739 if (shift) { 1740 shift *= CHTML.em/CHTML.outerEm; 1741 HUB.Insert(styles,({ 1742 left: {marginLeft: CHTML.Em(shift)}, 1743 right: {marginRight: CHTML.Em(-shift)}, 1744 center: {marginLeft: CHTML.Em(shift), marginRight: CHTML.Em(-shift)} 1745 })[values.indentalign]); 1746 } 1747 } 1748 return node; 1749 } 1750 }); 1751 1752 /********************************************************/ 1753 1754 MML.mi.Augment({ 1755 toCommonHTML: function (node) { 1756 node = this.CHTMLdefaultNode(node); 1757 var bbox = this.CHTML, text = this.data.join(""); 1758 if (bbox.skew != null && text.length !== 1) delete bbox.skew; 1759 if (bbox.r > bbox.w && text.length === 1 && !this.CHTMLvariant.noIC) { 1760 bbox.ic = bbox.r - bbox.w; bbox.w = bbox.r; 1761 node.lastChild.style.paddingRight = CHTML.Em(bbox.ic); 1762 } 1763 return node; 1764 } 1765 }); 1766 1767 /********************************************************/ 1768 1769 MML.mn.Augment({ 1770 toCommonHTML: function (node) { 1771 node = this.CHTMLdefaultNode(node); 1772 var bbox = this.CHTML, text = this.data.join(""); 1773 if (bbox.skew != null && text.length !== 1) delete bbox.skew; 1774 if (bbox.r > bbox.w && text.length === 1 && !this.CHTMLvariant.noIC) { 1775 bbox.ic = bbox.r - bbox.w; bbox.w = bbox.r; 1776 node.lastChild.style.paddingRight = CHTML.Em(bbox.ic); 1777 } 1778 return node; 1779 } 1780 }); 1781 1782 /********************************************************/ 1783 1784 MML.mo.Augment({ 1785 toCommonHTML: function (node) { 1786 node = this.CHTMLcreateNode(node); 1787 this.CHTMLhandleStyle(node); 1788 this.CHTMLhandleScale(node); 1789 this.CHTMLgetVariant(); 1790 CHTML.BBOX.empty(this.CHTML); 1791 1792 var values = this.getValues("displaystyle","largeop"); 1793 values.variant = this.CHTMLvariant; 1794 values.text = this.data.join(""); 1795 if (values.text == "") { 1796 if (this.fence) node.style.width = CHTML.Em(CHTML.TEX.nulldelimiterspace); 1797 } else { 1798 this.CHTMLadjustAccent(values); 1799 this.CHTMLadjustVariant(values); 1800 1801 for (var i = 0, m = this.data.length; i < m; i++) { 1802 this.CHTMLaddChild(node,i,{childOptions:{ 1803 variant: values.mathvariant, 1804 remap: this.remap, 1805 remapchars: values.remapchars 1806 }}); 1807 } 1808 if (values.text.length !== 1) delete this.CHTML.skew; 1809 else if (this.CHTML.w === 0 && this.CHTML.l < 0) this.CHTMLfixCombiningChar(node); 1810 if (values.largeop) this.CHTMLcenterOp(node); 1811 } 1812 1813 this.CHTML.clean(); 1814 this.CHTMLhandleBBox(node); 1815 this.CHTMLhandleSpace(node); 1816 this.CHTMLhandleColor(node); 1817 1818 return node; 1819 }, 1820 CHTMLhandleSpace: function (node) { 1821 if (this.useMMLspacing) { 1822 var values = this.getValues("scriptlevel","lspace","rspace"); 1823 values.lspace = Math.max(0,this.CHTMLlength2em(values.lspace)); 1824 values.rspace = Math.max(0,this.CHTMLlength2em(values.rspace)); 1825 if (values.scriptlevel > 0) { 1826 if (!this.hasValue("lspace")) values.lspace = .15; 1827 if (!this.hasValue("rspace")) values.rspace = .15; 1828 } 1829 var core = this, parent = this.Parent(); 1830 while (parent && parent.isEmbellished() && parent.Core() === core) 1831 {core = parent; parent = parent.Parent(); node = core.CHTMLnodeElement()} 1832 if (values.lspace) node.style.paddingLeft = CHTML.Em(values.lspace); 1833 if (values.rspace) node.style.paddingRight = CHTML.Em(values.rspace); 1834 this.CHTML.L = values.lspace; this.CHTML.R = values.rspace; 1835 } else { 1836 this.SUPER(arguments).CHTMLhandleSpace.apply(this,arguments); 1837 } 1838 }, 1839 CHTMLadjustAccent: function (data) { 1840 var parent = this.CoreParent(); data.parent = parent; 1841 if (data.text.length === 1 && parent && parent.isa(MML.munderover) && 1842 this.CoreText(parent.data[parent.base]).length === 1) { 1843 var over = parent.data[parent.over], under = parent.data[parent.under]; 1844 if (over && this === over.CoreMO() && parent.Get("accent")) { 1845 data.remapchars = CHTML.FONTDATA.REMAPACCENT; 1846 } else if (under && this === under.CoreMO() && parent.Get("accentunder")) { 1847 data.remapchars = CHTML.FONTDATA.REMAPACCENTUNDER; 1848 } 1849 } 1850 }, 1851 CHTMLadjustVariant: function (data) { 1852 var parent = data.parent, 1853 isScript = (parent && parent.isa(MML.msubsup) && this !== parent.data[parent.base]); 1854 if (data.largeop) data.mathvariant = (data.displaystyle ? "-largeOp" : "-smallOp"); 1855 if (isScript) { 1856 data.remapchars = this.remapChars; 1857 if (data.text.match(/['`"\u00B4\u2032-\u2037\u2057]/)) 1858 data.mathvariant = "-TeX-variant"; // ### FIXME: handle other fonts 1859 } 1860 }, 1861 CHTMLfixCombiningChar: function (node) { 1862 // 1863 // IE doesn't display combining chararacters unless they combine with 1864 // something, so put them over a space and remove the space's width 1865 // 1866 node = node.firstChild; 1867 var space = CHTML.Element("mjx-span",{style:{width:".25em","margin-left":"-.25em"}}); 1868 node.insertBefore(space,node.firstChild); 1869 }, 1870 CHTMLcenterOp: function (node) { 1871 var bbox = this.CHTML; 1872 var p = (bbox.h - bbox.d)/2 - CHTML.TEX.axis_height; 1873 if (Math.abs(p) > .001) node.style.verticalAlign = CHTML.Em(-p); 1874 bbox.h -= p; bbox.d += p; 1875 if (bbox.r > bbox.w) { 1876 bbox.ic = bbox.r - bbox.w; bbox.w = bbox.r; 1877 node.style.paddingRight = CHTML.Em(bbox.ic); 1878 } 1879 }, 1880 CHTMLcanStretch: function (direction,H,D) { 1881 if (!this.Get("stretchy")) return false; 1882 var c = this.data.join(""); if (c.length !== 1) return false; 1883 var values = {text: c}; 1884 this.CHTMLadjustAccent(values); 1885 if (values.remapchars) c = values.remapchars[c]||c; 1886 c = CHTML.FONTDATA.DELIMITERS[c.charCodeAt(0)]; 1887 var stretch = (c && c.dir === direction.substr(0,1)); 1888 if (stretch) { 1889 stretch = (this.CHTML.h !== H || this.CHTML.d !== D || 1890 !!this.Get("minsize",true) || !!this.Get("maxsize",true)); 1891 if (stretch) this.CHTML.stretch = true; 1892 } 1893 return stretch; 1894 }, 1895 CHTMLstretchV: function (h,d) { 1896 var node = this.CHTMLnodeElement(), bbox = this.CHTML; 1897 var values = this.getValues("symmetric","maxsize","minsize"); 1898 // 1899 // Determine the height needed 1900 // 1901 var H, a = CHTML.TEX.axis_height; 1902 if (values.symmetric) {H = 2*Math.max(h-a,d+a)} else {H = h + d} 1903 values.maxsize = this.CHTMLlength2em(values.maxsize,bbox.h+bbox.d); 1904 values.minsize = this.CHTMLlength2em(values.minsize,bbox.h+bbox.d); 1905 H = Math.max(values.minsize,Math.min(values.maxsize,H)); 1906 // 1907 // If we are not already stretched to this height 1908 // 1909 if (H !== bbox.sH) { 1910 // 1911 // Get a delimiter of the proper height and save the height 1912 // 1913 if (H != values.minsize) 1914 {H = [Math.max(H*CHTML.TEX.delimiterfactor/1000,H-CHTML.TEX.delimitershortfall),H]} 1915 while (node.firstChild) node.removeChild(node.firstChild); 1916 this.CHTML = bbox = CHTML.createDelimiter(node,this.data.join("").charCodeAt(0),H,bbox); 1917 bbox.sH = (H instanceof Array ? H[1] : H); 1918 // 1919 // Reposition as needed 1920 // 1921 if (values.symmetric) {H = (bbox.h + bbox.d)/2 + a} 1922 else {H = (bbox.h + bbox.d) * h/(h + d)} 1923 H -= bbox.h; 1924 if (Math.abs(H) > .05) { 1925 node.style.verticalAlign = CHTML.Em(H); 1926 bbox.h += H; bbox.d -= H; bbox.t += H; bbox.b -= H; 1927 } 1928 } 1929 return this.CHTML; 1930 }, 1931 CHTMLstretchH: function (node,W) { 1932 var bbox = this.CHTML; 1933 var values = this.getValues("maxsize","minsize","mathvariant","fontweight"); 1934 if ((values.fontweight === "bold" || (this.removedStyles||{}).fontWeight === "bold" || 1935 parseInt(values.fontweight) >= 600) && !this.Get("mathvariant",true)) 1936 values.mathvariant = MML.VARIANT.BOLD; 1937 values.maxsize = this.CHTMLlength2em(values.maxsize,bbox.w); 1938 values.minsize = this.CHTMLlength2em(values.minsize,bbox.w); 1939 W = Math.max(values.minsize,Math.min(values.maxsize,W)); 1940 if (W !== bbox.sW) { 1941 while (node.firstChild) node.removeChild(node.firstChild); 1942 this.CHTML = bbox = CHTML.createDelimiter(node,this.data.join("").charCodeAt(0),W,bbox,values.mathvariant); 1943 bbox.sW = W; 1944 } 1945 return this.CHTML; 1946 } 1947 1948 }); 1949 1950 /********************************************************/ 1951 1952 MML.mtext.Augment({ 1953 CHTMLgetVariant: function () { 1954 if (CHTML.config.mtextFontInherit || this.Parent().type === "merror") { 1955 var scale = (CHTML.config.scale/100)/CHTML.scale; 1956 var variant = {cache:{}, fonts:[], className:"MJXc-font-inherit", rscale:scale, 1957 style:{"font-size":CHTML.Percent(scale)}}; 1958 var name = this.Get("mathvariant"); 1959 if (name.match(/bold/)) variant.style["font-weight"] = "bold"; 1960 if (name.match(/italic|-tex-mathit/)) variant.style["font-style"] = "italic"; 1961 if (name === "monospace") variant.className += " MJXc-monospace-font"; 1962 if (name === "double-struck") variant.className += " MJXc-double-struck-font"; 1963 if (name.match(/fraktur/)) variant.className += " MJXc-fraktur-font"; 1964 if (name.match(/sans-serif/)) variant.className += " MJXc-sans-serif-font"; 1965 if (name.match(/script/)) variant.className += " MJXc-script-font"; 1966 this.CHTMLvariant = variant; 1967 } else { 1968 this.SUPER(arguments).CHTMLgetVariant.call(this); 1969 } 1970 } 1971 }); 1972 1973 /********************************************************/ 1974 1975 MML.merror.Augment({ 1976 toCommonHTML: function (node) { 1977 node = this.CHTMLdefaultNode(node); 1978 var bbox = this.CHTML; 1979 // 1980 // Adjust for font-size: 90% 1981 // 1982 bbox.rescale(.9); 1983 // 1984 // Adjust for padding and border 1985 // 1986 bbox.h += 3/CHTML.em; if (bbox.h > bbox.t) bbox.t = bbox.h; 1987 bbox.d += 3/CHTML.em; if (bbox.d > bbox.b) bbox.b = bbox.d; 1988 bbox.w += 8/CHTML.em; bbox.r = bbox.w; bbox.l = 0; 1989 return node; 1990 } 1991 }); 1992 1993 /********************************************************/ 1994 1995 MML.mspace.Augment({ 1996 toCommonHTML: function (node) { 1997 node = this.CHTMLcreateNode(node); 1998 this.CHTMLhandleStyle(node); 1999 this.CHTMLhandleScale(node); 2000 var values = this.getValues("height","depth","width"); 2001 var w = this.CHTMLlength2em(values.width), 2002 h = this.CHTMLlength2em(values.height), 2003 d = this.CHTMLlength2em(values.depth); 2004 var bbox = this.CHTML; 2005 bbox.w = bbox.r = w; bbox.h = bbox.t = h; bbox.d = bbox.b = d; bbox.l = 0; 2006 if (w < 0) {node.style.marginRight = CHTML.Em(w); w = 0} 2007 node.style.width = CHTML.Em(w); 2008 node.style.height = CHTML.Em(Math.max(0,h+d)); 2009 if (d) node.style.verticalAlign = CHTML.Em(-d); 2010 this.CHTMLhandleBBox(node); 2011 this.CHTMLhandleColor(node); 2012 return node; 2013 } 2014 }); 2015 2016 /********************************************************/ 2017 2018 MML.mpadded.Augment({ 2019 toCommonHTML: function (node,stretch) { 2020 var child; 2021 if (stretch) { 2022 node = node.firstChild; child = node.firstChild; 2023 } else { 2024 node = this.CHTMLdefaultNode(node,{childNodes:"mjx-box", forceChild:true}); 2025 child = node.firstChild; node = CHTML.addElement(node,"mjx-block"); 2026 node.appendChild(child); CHTML.addElement(node,"mjx-strut"); // force proper alignment of short heights 2027 } 2028 var cbox = this.CHTMLbboxFor(0); 2029 var values = this.getValues("width","height","depth","lspace","voffset"); 2030 var x = 0, y = 0, w = cbox.w, h = cbox.h, d = cbox.d; 2031 child.style.width = 0; child.style.margin = CHTML.Em(-h)+" 0 "+CHTML.Em(-d); 2032 if (values.width !== "") w = this.CHTMLdimen(values.width,"w",w,0); 2033 if (values.height !== "") h = this.CHTMLdimen(values.height,"h",h,0); 2034 if (values.depth !== "") d = this.CHTMLdimen(values.depth,"d",d,0); 2035 if (values.voffset !== "") { 2036 y = this.CHTMLdimen(values.voffset); 2037 if (y) { 2038 child.style.position = "relative"; 2039 child.style.top = CHTML.Em(-y); 2040 } 2041 } 2042 if (values.lspace !== "") { 2043 x = this.CHTMLdimen(values.lspace); 2044 if (x) { 2045 child.style.position = "relative"; 2046 child.style.left = CHTML.Em(x); 2047 } 2048 } 2049 node.style.width = 0; 2050 node.style.marginTop = CHTML.Em(h-STRUTHEIGHT); 2051 node.style.padding = "0 "+CHTML.Em(w)+" "+CHTML.Em(d)+" 0"; 2052 var bbox = CHTML.BBOX({w:w, h:h, d:d, l:0, r:w, t:h, b:d, 2053 scale:this.CHTML.scale, rscale:this.CHTML.rscale}); 2054 bbox.combine(cbox,x,y); 2055 bbox.w = w; bbox.h = h; bbox.d = d; 2056 this.CHTML = bbox; 2057 return node.parentNode; 2058 }, 2059 CHTMLstretchV: MML.mbase.CHTMLstretchV, 2060 CHTMLstretchH: MML.mbase.CHTMLstretchH, 2061 CHTMLdimen: function (length,d,D,m) { 2062 if (m == null) {m = -BIGDIMEN} 2063 length = String(length); 2064 var match = length.match(/width|height|depth/); 2065 var size = (match ? this.CHTML[match[0].charAt(0)] : (d ? this.CHTML[d] : 0)); 2066 var dimen = (this.CHTMLlength2em(length,size)||0); 2067 if (length.match(/^[-+]/) && D != null) dimen += D; 2068 if (m != null) dimen = Math.max(m,dimen); 2069 return dimen; 2070 } 2071 }); 2072 2073 /********************************************************/ 2074 2075 MML.munderover.Augment({ 2076 toCommonHTML: function (node,stretch) { 2077 var values = this.getValues("displaystyle","accent","accentunder","align"); 2078 var base = this.data[this.base]; 2079 if (!values.displaystyle && base != null && 2080 (base.movablelimits || base.CoreMO().Get("movablelimits"))) 2081 return MML.msubsup.prototype.toCommonHTML.call(this,node,stretch); 2082 // 2083 // Get the nodes for base and limits 2084 // 2085 var under, over, nodes = []; 2086 if (stretch) { 2087 if (this.data[this.base]) base = CHTML.getNode(node,"mjx-op"); 2088 if (this.data[this.under]) under = CHTML.getNode(node,"mjx-under"); 2089 if (this.data[this.over]) over = CHTML.getNode(node,"mjx-over"); 2090 nodes[0] = base; nodes[1] = under||over; nodes[2] = over; 2091 } else { 2092 var types = ["mjx-op","mjx-under","mjx-over"]; 2093 if (this.over === 1) types[1] = types[2]; 2094 node = this.CHTMLdefaultNode(node,{ 2095 childNodes:types, noBBox:true, forceChild:true, minChildren: 2 2096 }); 2097 nodes[0] = base = node.removeChild(node.firstChild); 2098 nodes[1] = under = over = node.removeChild(node.firstChild); 2099 if (node.firstChild) nodes[2] = over = node.removeChild(node.firstChild); 2100 } 2101 // 2102 // Get the bounding boxes and the maximum width 2103 // 2104 var boxes = [], W = this.CHTMLgetBBoxes(boxes,nodes,values); 2105 var bbox = boxes[this.base], BBOX = this.CHTML; 2106 BBOX.w = W; BBOX.h = bbox.h; BBOX.d = bbox.d; // modified below 2107 // 2108 // Add over- and under-scripts 2109 // 2110 var stack = base, delta = 0; 2111 if (bbox.ic) {delta = 1.3*bbox.ic + .05} // make faked IC be closer to expeted results 2112 if (this.data[this.over]) stack = this.CHTMLaddOverscript(over,boxes,values,delta,base,stretch); 2113 if (this.data[this.under]) this.CHTMLaddUnderscript(under,boxes,values,delta,node,stack,stretch); 2114 else if (!stretch) node.appendChild(stack); 2115 // 2116 // Handle horizontal positions 2117 // 2118 this.CHTMLplaceBoxes(base,under,over,values,boxes); 2119 return node; 2120 }, 2121 // 2122 // Get the bounding boxes for the children, stretch 2123 // any stretchable elements, and compute the maximum width 2124 // 2125 CHTMLgetBBoxes: function (bbox,nodes,values) { 2126 var i, m = this.data.length, scale, 2127 w = -BIGDIMEN, // maximum width of non-stretchy items 2128 W = w; // maximum width of all items 2129 // 2130 // Get the maximum width 2131 // 2132 for (i = 0; i < m; i++) { 2133 bbox[i] = this.CHTMLbboxFor(i); bbox[i].x = bbox[i].y = 0; 2134 if (this.data[i]) bbox[i].stretch = this.data[i].CHTMLcanStretch("Horizontal"); 2135 scale = (i === this.base ? 1 : bbox[i].rscale); 2136 if (i !== this.base) {delete bbox[i].L; delete bbox[i].R} // these are overriden by CSS 2137 W = Math.max(W,scale*(bbox[i].w + (bbox[i].L||0) + (bbox[i].R||0))); 2138 if (!bbox[i].stretch && W > w) w = W; 2139 } 2140 if (w === -BIGDIMEN) w = W; 2141 // 2142 // Stretch those parts that need it 2143 // 2144 for (i = 0; i < m; i++) { 2145 if (bbox[i].stretch) { 2146 scale = (i === this.base ? 1 : bbox[i].rscale); 2147 bbox[i] = this.data[i].CHTMLstretchH(nodes[i].firstChild,w/scale); 2148 bbox[i].x = bbox[i].y = 0; 2149 W = Math.max(W,scale*(bbox[i].w + (bbox[i].L||0) + (bbox[i].R||0))); 2150 } 2151 } 2152 if (!bbox[this.base]) bbox[this.base] = CHTML.BBOX.empty(); 2153 return W; 2154 }, 2155 // 2156 // Add an overscript 2157 // 2158 CHTMLaddOverscript: function (over,boxes,values,delta,base,stretch) { 2159 var BBOX = this.CHTML; 2160 var z1, z2, z3 = CHTML.TEX.big_op_spacing5, k; 2161 var obox = boxes[this.over], bbox = boxes[this.base], scale = obox.rscale; 2162 // 2163 // Put the base and script into a stack 2164 // 2165 if (!stretch) { 2166 var stack = CHTML.Element("mjx-stack"); 2167 stack.appendChild(over); stack.appendChild(base); 2168 } 2169 if (obox.D) obox.d = obox.D; 2170 if (obox.d < 0) { 2171 // 2172 // For negative depths, set the height and align to top 2173 // in order to avoid extra baseline space 2174 // 2175 over.firstChild.style.verticalAlign = "top"; 2176 over.style.height = CHTML.Em(obox.h+obox.d); 2177 } 2178 // 2179 // Determine the spacing 2180 // 2181 obox.x = 0; 2182 if (values.accent) { 2183 if (obox.w < .001) obox.x += (obox.r - obox.l)/2; // center combining accents 2184 k = CHTML.TEX.rule_thickness; z3 = 0; 2185 if (bbox.skew) { 2186 obox.x += scale*bbox.skew; BBOX.skew = scale*bbox.skew; 2187 if (obox.x+scale*obox.w > BBOX.w) BBOX.skew += (BBOX.w - (obox.x+scale*obox.w))/2; 2188 } 2189 } else { 2190 z1 = CHTML.TEX.big_op_spacing1; 2191 z2 = CHTML.TEX.big_op_spacing3; 2192 k = Math.max(z1,z2-Math.max(0,scale*obox.d)); 2193 } 2194 obox.x += delta/2; obox.y = BBOX.h + k + z3 + scale*obox.d; 2195 // 2196 // Position the overscript 2197 // 2198 if (k) over.style.paddingBottom = CHTML.Em(k/scale); 2199 if (z3) over.style.paddingTop = CHTML.Em(z3/scale); 2200 return stack; 2201 }, 2202 // 2203 // Add an underscript 2204 // 2205 CHTMLaddUnderscript: function (under,boxes,values,delta,node,stack,stretch) { 2206 var BBOX = this.CHTML; 2207 var z1, z2, z3 = CHTML.TEX.big_op_spacing5, k; 2208 var ubox = boxes[this.under], scale = ubox.rscale; 2209 // 2210 // Create a table for the underscript 2211 // 2212 if (!stretch) { 2213 CHTML.addElement(node,"mjx-itable",{},[ 2214 ["mjx-row",{},[["mjx-cell"]]], 2215 ["mjx-row"] 2216 ]); 2217 node.firstChild.firstChild.firstChild.appendChild(stack); 2218 node.firstChild.lastChild.appendChild(under); 2219 } 2220 if (ubox.D) ubox.d = ubox.D; 2221 if (ubox.d < 0) { 2222 // 2223 // For negative depths, set the height and align to top 2224 // in order to avoid extra baseline space 2225 // 2226 under.firstChild.style.verticalAlign = "top"; 2227 node.firstChild.style.marginBottom = CHTML.Em(ubox.d); 2228 } 2229 // 2230 // determine the spacing 2231 // 2232 if (values.accentunder) { 2233 k = 2*CHTML.TEX.rule_thickness; z3 = 0; 2234 } else { 2235 z1 = CHTML.TEX.big_op_spacing2; 2236 z2 = CHTML.TEX.big_op_spacing4; 2237 k = Math.max(z1,z2-scale*ubox.h); 2238 } 2239 ubox.x = -delta/2; ubox.y = -(BBOX.d + k + z3 + scale*ubox.h); 2240 // 2241 // Position the underscript 2242 // 2243 if (k) under.style.paddingTop = CHTML.Em(k/scale); 2244 if (z3) under.style.paddingBottom = CHTML.Em(z3/scale); 2245 }, 2246 // 2247 // Center boxes horizontally, taking offsets into account 2248 // 2249 CHTMLplaceBoxes: function (base,under,over,values,boxes) { 2250 var W = this.CHTML.w, i, m = boxes.length, scale; 2251 var BBOX = CHTML.BBOX.zero(); 2252 BBOX.scale = this.CHTML.scale; BBOX.rscale = this.CHTML.rscale; 2253 boxes[this.base].x = boxes[this.base].y = 0; var dx = BIGDIMEN; 2254 for (i = 0; i < m; i++) { 2255 scale = (i === this.base ? 1 : boxes[i].rscale); 2256 var w = scale*(boxes[i].w + (boxes[i].L||0) + (boxes[i].R||0)); 2257 boxes[i].x += {left:0, center:(W-w)/2, right:W-w}[values.align]; 2258 if (boxes[i].x < dx) dx = boxes[i].x; 2259 } 2260 for (i = 0; i < m; i++) { 2261 if (this.data[i]) { 2262 scale = (i === this.base ? 1 : boxes[i].rscale); 2263 if (boxes[i].x - dx) { 2264 var node = (i === this.base ? base : i === this.over ? over : under); 2265 node.style.paddingLeft = CHTML.Em((boxes[i].x-dx)/scale); 2266 } 2267 BBOX.combine(boxes[i],boxes[i].x-dx,boxes[i].y); 2268 } 2269 } 2270 this.CHTML = BBOX; 2271 }, 2272 CHTMLstretchV: MML.mbase.CHTMLstretchV, 2273 CHTMLstretchH: MML.mbase.CHTMLstretchH, 2274 CHTMLchildNode: function (node,i) { 2275 var types = ["mjx-op","mjx-under","mjx-over"]; 2276 if (this.over === 1) types[1] = types[2]; 2277 return CHTML.getNode(node,types[i]); 2278 } 2279 }); 2280 2281 /********************************************************/ 2282 2283 MML.msubsup.Augment({ 2284 toCommonHTML: function (node,stretch) { 2285 var values = this.getValues( 2286 "displaystyle","subscriptshift","superscriptshift","texprimestyle" 2287 ); 2288 // 2289 // Get the nodes for base and limits 2290 // 2291 var base, sub, sup; 2292 if (stretch) { 2293 if (this.data[this.base]) base = CHTML.getNode(node,"mjx-base"); 2294 if (this.data[this.sub]) sub = CHTML.getNode(node,"mjx-sub"); 2295 if (this.data[this.sup]) sup = CHTML.getNode(node,"mjx-sup"); 2296 stack = CHTML.getNode(node,"mjx-stack"); 2297 } else { 2298 var types = ["mjx-base","mjx-sub","mjx-sup"]; 2299 if (this.sup === 1) types[1] = types[2]; 2300 node = this.CHTMLdefaultNode(node,{ 2301 childNodes:types, noBBox:true, forceChild:true, minChildren: 3 2302 }); 2303 base = node.childNodes[this.base]; 2304 sub = node.childNodes[this.sub]; sup = node.childNodes[this.sup]; 2305 if (!this.CHTMLnotEmpty(this.data[this.sub])) {node.removeChild(sub); sub = null} 2306 if (!this.CHTMLnotEmpty(this.data[this.sup])) {node.removeChild(sup); sup = null} 2307 if (node.childNodes.length === 3) { 2308 var stack = CHTML.addElement(node,"mjx-stack"); 2309 stack.appendChild(sup); stack.appendChild(sub); 2310 } 2311 } 2312 // 2313 // Get the bounding boxes and maximum width of scripts 2314 // 2315 var boxes = [], BBOX = CHTML.BBOX.empty(this.CHTML); 2316 for (var i = 0, m = this.data.length; i < m; i++) boxes[i] = this.CHTMLbboxFor(i); 2317 var bbox = boxes[this.base] || CHTML.BBOX.empty(), 2318 sbox = boxes[this.sub], Sbox = boxes[this.sup]; 2319 var sscale = (sub ? sbox.rscale : 1), Sscale = (sup ? Sbox.rscale : 1); 2320 BBOX.combine(bbox,0,0); 2321 // 2322 // Get initial values for parameters 2323 // 2324 var ex = CHTML.TEX.x_height, s = CHTML.TEX.scriptspace; 2325 var q = CHTML.TEX.sup_drop * Sscale, r = CHTML.TEX.sub_drop * sscale; 2326 var u = bbox.h - q, v = bbox.d + r, delta = 0, p; 2327 if (bbox.ic) { 2328 BBOX.w -= bbox.ic; // remove IC (added by mo and mi) 2329 base.style.marginRight = CHTML.Em(-bbox.ic); 2330 delta = 1.3*bbox.ic + .05; // make faked IC be closer to expeted results 2331 } 2332 var bmml = this.data[this.base]; 2333 if (bmml) { 2334 if ((bmml.type === "mrow" || bmml.type === "mstyle") && bmml.data.length === 1) bmml = bmml.data[0]; 2335 if (bmml.type === "mi" || bmml.type === "mo") { 2336 if (bmml.data.join("").length === 1 && bbox.rscale === 1 && !bbox.sH && 2337 !bmml.Get("largeop")) {u = v = 0} 2338 } 2339 } 2340 values.subscriptshift = (values.subscriptshift === "" ? 0 : this.CHTMLlength2em(values.subscriptshift)); 2341 values.superscriptshift = (values.superscriptshift === "" ? 0 : this.CHTMLlength2em(values.superscriptshift)); 2342 // 2343 // Add the super- and subscripts 2344 // 2345 var x = BBOX.w; if (sub) sbox.w += s; if (sup) Sbox.w += s; 2346 if (!sup) { 2347 if (sub) { 2348 v = Math.max(v,CHTML.TEX.sub1,sscale*sbox.h-(4/5)*ex,values.subscriptshift); 2349 sub.style.verticalAlign = CHTML.Em(-v/sscale); 2350 sub.style.paddingRight = CHTML.Em(s/sscale); 2351 BBOX.combine(sbox,x,-v); 2352 } 2353 } else { 2354 if (!sub) { 2355 p = CHTML.TEX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))]; 2356 u = Math.max(u,p,Sscale*Sbox.d+(1/4)*ex,values.superscriptshift); 2357 sup.style.verticalAlign = CHTML.Em(u/Sscale); 2358 sup.style.paddingLeft = CHTML.Em(delta/Sscale); 2359 sup.style.paddingRight = CHTML.Em(s/Sscale); 2360 BBOX.combine(Sbox,x+delta,u); 2361 } else { 2362 v = Math.max(v,CHTML.TEX.sub2); 2363 var t = CHTML.TEX.rule_thickness; 2364 if ((u - Sscale*Sbox.d) - (sscale*sbox.h - v) < 3*t) { 2365 v = 3*t - u + Sscale*Sbox.d + sscale*sbox.h; 2366 q = (4/5)*ex - (u - Sscale*Sbox.d); 2367 if (q > 0) {u += q; v -= q} 2368 } 2369 u = Math.max(u,values.superscriptshift); 2370 v = Math.max(v,values.subscriptshift); 2371 sub.style.paddingRight = CHTML.Em(s/sscale); 2372 sup.style.paddingBottom = CHTML.Em(u/Sscale+v/sscale-Sbox.d-sbox.h/sscale*Sscale); 2373 sup.style.paddingLeft = CHTML.Em(delta/Sscale); 2374 sup.style.paddingRight = CHTML.Em(s/Sscale); 2375 stack.style.verticalAlign = CHTML.Em(-v); 2376 BBOX.combine(Sbox,x+delta,u); 2377 BBOX.combine(sbox,x,-v); 2378 } 2379 } 2380 BBOX.clean(); 2381 return node; 2382 }, 2383 CHTMLstretchV: MML.mbase.CHTMLstretchV, 2384 CHTMLstretchH: MML.mbase.CHTMLstretchH, 2385 CHTMLchildNode: function (node,i) { 2386 var types = ["mjx-base","mjx-sub","mjx-sup"]; 2387 if (this.over === 1) types[1] = types[2]; 2388 return CHTML.getNode(node,types[i]); 2389 } 2390 }); 2391 2392 /********************************************************/ 2393 2394 MML.mfrac.Augment({ 2395 toCommonHTML: function (node) { 2396 node = this.CHTMLdefaultNode(node,{ 2397 childNodes:["mjx-numerator","mjx-denominator"], 2398 forceChild:true, noBBox:true, minChildren:2 2399 }); 2400 var values = this.getValues("linethickness","displaystyle", 2401 "numalign","denomalign","bevelled"); 2402 var isDisplay = values.displaystyle; 2403 // 2404 // Create the table for the fraction and set the alignment 2405 // 2406 var num = node.firstChild, denom = node.lastChild; 2407 var frac = CHTML.addElement(node,"mjx-box"); 2408 frac.appendChild(num); frac.appendChild(denom); node.appendChild(frac); 2409 if (values.numalign !== "center") num.style.textAlign = values.numalign; 2410 if (values.denomalign !== "center") denom.style.textAlign = values.denomalign; 2411 // 2412 // Get the bounding boxes for the parts, and determine the placement 2413 // of the numerator and denominator 2414 // 2415 var nbox = this.CHTMLbboxFor(0), dbox = this.CHTMLbboxFor(1), 2416 BBOX = CHTML.BBOX.empty(this.CHTML), nscale = nbox.rscale, dscale = dbox.rscale; 2417 values.linethickness = Math.max(0,CHTML.thickness2em(values.linethickness||"0",BBOX.scale)); 2418 var mt = CHTML.TEX.min_rule_thickness/CHTML.em, a = CHTML.TEX.axis_height; 2419 var t = values.linethickness, p,q, u,v; 2420 if (values.bevelled) { 2421 frac.className += " MJXc-bevelled"; 2422 var delta = (isDisplay ? .4 : .15); 2423 var H = Math.max(nscale*(nbox.h+nbox.d),dscale*(dbox.h+dbox.d)) + 2*delta; 2424 var bevel = CHTML.Element("mjx-bevel"); frac.insertBefore(bevel,denom); 2425 var bbox = CHTML.createDelimiter(bevel,0x2F,H); 2426 u = nscale*(nbox.d-nbox.h)/2+a+delta; 2427 v = dscale*(dbox.d-dbox.h)/2+a-delta; 2428 if (u) num.style.verticalAlign = CHTML.Em(u/nscale); 2429 if (v) denom.style.verticalAlign = CHTML.Em(v/dscale); 2430 bevel.style.marginLeft = bevel.style.marginRight = CHTML.Em(-delta/2); 2431 BBOX.combine(nbox,0,u); 2432 BBOX.combine(bbox,nscale*nbox.w-delta/2,0); 2433 BBOX.combine(dbox,nscale*nbox.w+bbox.w-delta,v); 2434 BBOX.clean(); 2435 } else { 2436 frac.className += " MJXc-stacked"; 2437 if (isDisplay) {u = CHTML.TEX.num1; v = CHTML.TEX.denom1} 2438 else {u = (t === 0 ? CHTML.TEX.num3 : CHTML.TEX.num2); v = CHTML.TEX.denom2} 2439 if (t === 0) { // \atop 2440 p = Math.max((isDisplay ? 7 : 3) * CHTML.TEX.rule_thickness, 2*mt); // force to at least 2 px 2441 q = (u - nbox.d*nscale) - (dbox.h*dscale - v); 2442 if (q < p) {u += (p - q)/2; v += (p - q)/2} 2443 } else { // \over 2444 p = Math.max((isDisplay ? 2 : 0) * mt + t, t/2 + 1.5*mt); 2445 t = Math.max(t,mt); 2446 q = (u - nbox.d*nscale) - (a + t/2); if (q < p) u += (p - q); 2447 q = (a - t/2) - (dbox.h*dscale - v); if (q < p) v += (p - q); 2448 nbox.L = nbox.R = dbox.L = dbox.R = .1; // account for padding in BBOX width 2449 var rule = CHTML.addElement(frac,"mjx-line",{style: { 2450 "border-bottom":CHTML.Px(t*BBOX.scale,1)+" solid", top: CHTML.Em(-t/2-a) 2451 }}); 2452 } 2453 // 2454 // Determine the new bounding box and place the parts 2455 // 2456 BBOX.combine(nbox,0,u); 2457 BBOX.combine(dbox,0,-v); 2458 BBOX.clean(); 2459 // 2460 // Force elements to the correct width 2461 // 2462 frac.style.width = CHTML.Em(BBOX.w); 2463 num.style.width = CHTML.Em(BBOX.w/nscale); 2464 denom.style.width = CHTML.Em(BBOX.w/dscale); 2465 if (rule) rule.style.width = frac.style.width; 2466 // 2467 // Place the numerator and denominator in relation to the baseline 2468 // 2469 num.style.top = CHTML.Em(-BBOX.h/nscale); 2470 denom.style.bottom = CHTML.Em(-BBOX.d/dscale); 2471 // 2472 // Force the size of the surrounding box, since everything is absolutely positioned 2473 // 2474 CHTML.addElement(node,"mjx-vsize",{style: { 2475 height: CHTML.Em(BBOX.h+BBOX.d), verticalAlign: CHTML.Em(-BBOX.d) 2476 }}); 2477 } 2478 // 2479 // Add nulldelimiterspace around the fraction 2480 // (TeXBook pg 150 and Appendix G rule 15e) 2481 // 2482 if (!this.texWithDelims && !this.useMMLspacing) { 2483 var space = CHTML.TEX.nulldelimiterspace; 2484 frac.style.padding = "0 "+CHTML.Em(space); 2485 BBOX.l += space; BBOX.r += space; BBOX.w += 2*space; 2486 } 2487 // 2488 // Return the completed fraction 2489 // 2490 return node; 2491 }, 2492 CHTMLcanStretch: function (direction) {return false} 2493 }); 2494 2495 /********************************************************/ 2496 2497 MML.msqrt.Augment({ 2498 toCommonHTML: function (node) { 2499 node = this.CHTMLdefaultNode(node,{ 2500 childNodes:["mjx-box","mjx-root"], forceChild:true, noBBox:true 2501 }); 2502 var base = node.firstChild || CHTML.Element("mjx-box"); 2503 var sqrt = CHTML.addElement(node,"mjx-box"); sqrt.appendChild(base); 2504 var bbox = this.CHTMLbboxFor(0), BBOX = CHTML.BBOX.empty(this.CHTML); 2505 var t = CHTML.TEX.rule_thickness, T = CHTML.TEX.surd_height, p = t, q, H; 2506 if (this.Get("displaystyle")) p = CHTML.TEX.x_height; 2507 q = t + p/4; 2508 H = bbox.h + bbox.d + q + t; 2509 var surd = CHTML.Element("mjx-surd"); sqrt.insertBefore(surd,base); 2510 var sbox = CHTML.createDelimiter(surd,0x221A,[H-.04,H]); 2511 if (sbox.h + sbox.d > H) q = ((sbox.h+sbox.d) - (H-t))/2; 2512 H = bbox.h + q + t; 2513 var x = this.CHTMLaddRoot(node,sbox,sbox.h+sbox.d-H); 2514 base.style.paddingTop = CHTML.Em(q); 2515 base.style.borderTop = CHTML.Px(T*bbox.scale,1)+" solid"; 2516 sqrt.style.paddingTop = CHTML.Em(2*t-T); // use wider line, but don't affect height 2517 bbox.h += q + 2*t; 2518 BBOX.combine(sbox,x,H-sbox.h); 2519 BBOX.combine(bbox,x+sbox.w,0); 2520 BBOX.clean(); 2521 return node; 2522 }, 2523 CHTMLaddRoot: function () {return 0} 2524 }); 2525 2526 /********************************************************/ 2527 2528 MML.mroot.Augment({ 2529 toCommonHTML: MML.msqrt.prototype.toCommonHTML, 2530 CHTMLaddRoot: function (sqrt,sbox,d) { 2531 if (!this.data[1]) return; 2532 var BBOX = this.CHTML, bbox = this.data[1].CHTML, root = sqrt.firstChild; 2533 var scale = bbox.rscale; 2534 var h = this.CHTMLrootHeight(bbox,sbox,scale)-d; 2535 var w = Math.min(bbox.w,bbox.r); // remove extra right-hand padding, if any 2536 var dx = Math.max(w,sbox.offset/scale); 2537 if (h) root.style.verticalAlign = CHTML.Em(h/scale); 2538 if (dx > w) root.firstChild.style.paddingLeft = CHTML.Em(dx-w); 2539 dx -= sbox.offset/scale; 2540 root.style.width = CHTML.Em(dx); 2541 BBOX.combine(bbox,0,h); 2542 return dx*scale; 2543 }, 2544 CHTMLrootHeight: function (bbox,sbox,scale) { 2545 return .45*(sbox.h+sbox.d-.9)+sbox.offset + Math.max(0,bbox.d-.075); 2546 } 2547 }); 2548 2549 /********************************************************/ 2550 2551 MML.mfenced.Augment({ 2552 toCommonHTML: function (node) { 2553 node = this.CHTMLcreateNode(node); 2554 this.CHTMLhandleStyle(node); 2555 this.CHTMLhandleScale(node); 2556 // 2557 // Make row of open, data, sep, ... data, close 2558 // 2559 this.CHTMLaddChild(node,"open",{}); 2560 for (var i = 0, m = this.data.length; i < m; i++) { 2561 this.CHTMLaddChild(node,"sep"+i,{}); 2562 this.CHTMLaddChild(node,i,{}); 2563 } 2564 this.CHTMLaddChild(node,"close",{}); 2565 // 2566 // Check for stretching the elements 2567 // 2568 var H = this.CHTML.h, D = this.CHTML.d; 2569 this.CHTMLstretchChildV("open",H,D); 2570 for (i = 0, m = this.data.length; i < m; i++) { 2571 this.CHTMLstretchChildV("sep"+i,H,D); 2572 this.CHTMLstretchChildV(i,H,D); 2573 } 2574 this.CHTMLstretchChildV("close",H,D); 2575 this.CHTMLhandleSpace(node); 2576 this.CHTMLhandleBBox(node); 2577 this.CHTMLhandleColor(node); 2578 return node; 2579 } 2580 }); 2581 2582 /********************************************************/ 2583 2584 MML.mrow.Augment({ 2585 toCommonHTML: function (node) { 2586 node = this.CHTMLdefaultNode(node); 2587 var bbox = this.CHTML, H = bbox.h, D = bbox.d, hasNegative; 2588 for (var i = 0, m = this.data.length; i < m; i++) { 2589 this.CHTMLstretchChildV(i,H,D); 2590 if (this.data[i] && this.data[i].CHTML && this.data[i].CHTML.w < 0) hasNegative = true; 2591 } 2592 if (this.CHTMLlineBreaks()) { 2593 this.CHTMLmultiline(node); 2594 } else { 2595 if (hasNegative && bbox.w) node.style.width = CHTML.Em(Math.max(0,bbox.w)); 2596 if (bbox.w < 0) node.style.marginRight = CHTML.Em(bbox.w); 2597 } 2598 return node; 2599 }, 2600 CHTMLlineBreaks: function () { 2601 if (!this.parent.linebreakContainer) return false; 2602 return (LINEBREAKS.automatic && this.CHTML.w > CHTML.linebreakWidth) || this.hasNewline(); 2603 }, 2604 CHTMLstretchV: function (h,d) { 2605 this.CHTMLstretchChildV(this.CoreIndex(),h,d); 2606 return this.CHTML; 2607 }, 2608 CHTMLstretchH: function (node,w) { 2609 this.CHTMLstretchChildH(this.CoreIndex(),w,node); 2610 return this.CHTML; 2611 } 2612 }); 2613 2614 /********************************************************/ 2615 2616 MML.mstyle.Augment({ 2617 toCommonHTML: function (node) { 2618 node = this.CHTMLdefaultNode(node); 2619 if (this.scriptlevel && this.data[0]) this.CHTML.rescale(this.data[0].CHTML.rscale); 2620 return node; 2621 } 2622 }); 2623 2624 /********************************************************/ 2625 2626 MML.TeXAtom.Augment({ 2627 toCommonHTML: function (node,stretch) { 2628 if (!stretch) node = this.CHTMLdefaultNode(node); 2629 if (this.texClass === MML.TEXCLASS.VCENTER) { 2630 var a = CHTML.TEX.axis_height, BBOX = this.CHTML; 2631 var v = a-(BBOX.h+BBOX.d)/2+BBOX.d; 2632 if (Math.abs(v) > .001) { 2633 node.style.verticalAlign = CHTML.Em(v); 2634 BBOX.h += v; BBOX.t += v; BBOX.d -= v; BBOX.b -= v; 2635 } 2636 } 2637 return node; 2638 }, 2639 CHTMLstretchV: function (h,d) { 2640 this.CHTML.updateFrom(this.Core().CHTMLstretchV(h,d)); 2641 this.toCommonHTML(this.CHTMLnodeElement(),true); 2642 return this.CHTML; 2643 }, 2644 CHTMLstretchH: function (node,w) { 2645 this.CHTML.updateFrom(this.CHTMLstretchCoreH(node,w)); 2646 this.toCommonHTML(node,true); 2647 return this.CHTML; 2648 } 2649 }); 2650 2651 /********************************************************/ 2652 2653 MML.semantics.Augment({ 2654 toCommonHTML: function (node) { 2655 node = this.CHTMLcreateNode(node); 2656 if (this.data[0]) { 2657 this.data[0].toCommonHTML(node); 2658 this.CHTML.updateFrom(this.data[0].CHTML); 2659 } 2660 return node; 2661 } 2662 }); 2663 MML.annotation.Augment({toCommonHTML: function(node) {return this.CHTMLcreateNode(node)}}); 2664 MML["annotation-xml"].Augment({toCommonHTML: MML.mbase.CHTMLautoload}); 2665 2666 /********************************************************/ 2667 2668 MML.ms.Augment({toCommonHTML: MML.mbase.CHTMLautoload}); 2669 MML.mglyph.Augment({toCommonHTML: MML.mbase.CHTMLautoload}); 2670 MML.menclose.Augment({toCommonHTML: MML.mbase.CHTMLautoload}); 2671 MML.maction.Augment({toCommonHTML: MML.mbase.CHTMLautoload}); 2672 MML.mmultiscripts.Augment({toCommonHTML: MML.mbase.CHTMLautoload}); 2673 MML.mtable.Augment({toCommonHTML: MML.mbase.CHTMLautoload}); 2674 2675 /********************************************************/ 2676 2677 // 2678 // Loading isn't complete until the element jax is modified, 2679 // but can't call loadComplete within the callback for "mml Jax Ready" 2680 // (it would call CommonHTML's Require routine, asking for the mml jax again) 2681 // so wait until after the mml jax has finished processing. 2682 // 2683 // We also need to wait for the onload handler to run, since the loadComplete 2684 // will call Config and Startup, which need to modify the body. 2685 // 2686 MathJax.Hub.Register.StartupHook("onLoad",function () { 2687 setTimeout(MathJax.Callback(["loadComplete",CHTML,"jax.js"]),0); 2688 }); 2689 }); 2690 2691 MathJax.Hub.Register.StartupHook("End Cookie", function () { 2692 if (HUB.config.menuSettings.zoom !== "None") 2693 {AJAX.Require("[MathJax]/extensions/MathZoom.js")} 2694 }); 2695 2696 })(MathJax.Ajax,MathJax.Hub,MathJax.HTML,MathJax.OutputJax.CommonHTML);