jax.js (55631B)
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/NativeMML/jax.js 7 * 8 * Implements the NativeMML OutputJax that displays mathematics 9 * using a browser's native MathML capabilities (if any). 10 * 11 * --------------------------------------------------------------------- 12 * 13 * Copyright (c) 2010-2015 The MathJax Consortium 14 * 15 * Licensed under the Apache License, Version 2.0 (the "License"); 16 * you may not use this file except in compliance with the License. 17 * You may obtain a copy of the License at 18 * 19 * http://www.apache.org/licenses/LICENSE-2.0 20 * 21 * Unless required by applicable law or agreed to in writing, software 22 * distributed under the License is distributed on an "AS IS" BASIS, 23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 * See the License for the specific language governing permissions and 25 * limitations under the License. 26 */ 27 28 (function (nMML,HUB,AJAX,HTML) { 29 var MML, isMSIE = HUB.Browser.isMSIE; 30 31 var EVENT, TOUCH, HOVER, ZOOM; // filled in later 32 33 HUB.Register.StartupHook("MathZoom Ready",function () {ZOOM = MathJax.Extension.MathZoom}); 34 35 var NOPADDING = function (side,obj) { 36 var span = HTML.Element("span"); side = "padding"+side; 37 if (obj) { 38 span.style.cssText = (obj.getAttribute("style")||""); 39 if (span.style.padding === "" && (span.style[side]||"") === "") { 40 span.style[side] = "0px"; obj.setAttribute("style",span.style.cssText) 41 } 42 } 43 }; 44 45 var CELLSPACING = function (obj,rowSpacing,columnSpacing) { 46 // 47 // Webkit default padding on mtd cells is simply 48 // 49 // mtd {padding: 0.5ex;} 50 // 51 // Gecko default padding on mtd cells is 52 // 53 // mtd {padding-right: 0.4em; 54 // padding-left: 0.4em; 55 // padding-bottom: 0.5ex; 56 // padding-top: 0.5ex;} 57 // mtr:first-child > mtd {padding-top: 0ex;} 58 // mtr:last-child > mtd {padding-bottom: 0ex;} 59 // mtd:first-child {padding-left: 0em;} 60 // mtd:last-child {padding-right: 0em;} 61 // 62 // that is the columnspacing/rowspacing is split into two adjacent cells, 63 // and the periphery of boundary cells is set to zero. 64 // 65 // Here, we will set the left/top padding of each cell to 66 // rowSpacing/columnSpacing (or 0px for the leftmost/topmost cells) and 67 // reset the right/bottom padding to zero. 68 // 69 if (obj) { 70 var span = HTML.Element("span"); 71 span.style.cssText = (obj.getAttribute("style")||""); 72 if (span.style.padding === "") { 73 var padding = { paddingLeft: columnSpacing, paddingTop: rowSpacing, 74 paddingRight: "0px", paddingBottom: "0px" }; 75 for (var side in padding) {if (padding.hasOwnProperty(side)) { 76 if ((span.style[side]||"") === "") {span.style[side] = padding[side];} 77 }} 78 } 79 obj.setAttribute("style",span.style.cssText); 80 } 81 }; 82 83 nMML.Augment({ 84 // 85 // User can configure styles 86 // 87 config: { 88 styles: { 89 ".MathJax_MathML": { 90 "font-style": "normal", 91 "font-weight": "normal", 92 "line-height": "normal", 93 "font-size": "100%", 94 "font-size-adjust":"none", 95 "text-indent": 0, 96 "text-align": "left", 97 "text-transform": "none", 98 "letter-spacing": "normal", 99 "word-spacing": "normal", 100 "word-wrap": "normal", 101 "white-space": "nowrap", 102 "float": "none", 103 "direction": "ltr", 104 "max-width": "none", "max-height": "none", 105 "min-width": 0, "min-height": 0, 106 border: 0, padding: 0, margin: 0 107 }, 108 109 "span.MathJax_MathML": { 110 display: "inline!important" 111 }, 112 113 "div.MathJax_MathML": { 114 display: "block!important" 115 }, 116 117 ".MathJax_mmlExBox": { 118 display:"block!important", overflow:"hidden", 119 height:"1px", width:"60ex", 120 "min-height": 0, "max-height":"none", 121 padding:0, border: 0, margin: 0 122 } 123 } 124 }, 125 handlesVariants: false, // true if native support for mathvariants 126 settings: HUB.config.menuSettings, 127 ex: 1, scale: 1, // filled in later 128 adjustWidths: [], // array of elements to have their widths adjusted 129 130 Config: function () { 131 this.SUPER(arguments).Config.call(this); 132 if (this.settings.scale) {this.config.scale = this.settings.scale} 133 // 134 // Insert styling to take account of displayAlign and displayIndent 135 // 136 if (HUB.config.displayAlign !== "center") { 137 var align = HUB.config.displayAlign, indent = HUB.config.displayIndent; 138 var def = {"text-align": align+"!important"}; def["margin-"+align] = indent+"!important"; 139 HUB.Insert(this.config.styles,{ 140 "div.MathJax_MathML": def, 141 "div.MathJax_MathML math": {"text-align": align}, 142 "div.MathJax_MathContainer > span": {"text-align": align+"!important"} 143 }); 144 } 145 if (!this.require) {this.require = []} 146 this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js"); 147 }, 148 Startup: function () { 149 // Set up event handling 150 EVENT = MathJax.Extension.MathEvents.Event; 151 TOUCH = MathJax.Extension.MathEvents.Touch; 152 HOVER = MathJax.Extension.MathEvents.Hover; 153 this.ContextMenu = EVENT.ContextMenu; 154 this.Mousedown = EVENT.AltContextMenu; 155 this.Mouseover = HOVER.Mouseover; 156 this.Mouseout = HOVER.Mouseout; 157 this.Mousemove = HOVER.Mousemove; 158 159 if (!HUB.Browser.hasMathPlayer) { 160 // Used in preTranslate to get scaling factors 161 this.EmExSpan = HTML.Element("span", 162 {style:{position:"absolute","font-size-adjust":"none"}}, 163 [ 164 ["div",{className:"MathJax_mmlExBox"}], 165 ["span",{className:"MathJax_MathML"}] 166 ] 167 ); 168 MML.math(MML.mspace().With({width:"60ex"})).toNativeMML(this.EmExSpan.lastChild); 169 } 170 171 // Set up styles 172 return AJAX.Styles(this.config.styles); 173 }, 174 // 175 // Set up MathPlayer for IE on the first time through. 176 // Get the ex and em sizes. 177 // 178 InitializeMML: function () { 179 this.initialized = true; 180 if (HUB.Browser.hasMathPlayer) { 181 try { 182 // 183 // Insert data needed to use MathPlayer for MathML output 184 // 185 if (!HUB.Browser.mpNamespace) { 186 var mathplayer = document.createElement("object"); 187 mathplayer.id = "mathplayer"; mathplayer.classid = "clsid:32F66A20-7614-11D4-BD11-00104BD3F987"; 188 document.getElementsByTagName("head")[0].appendChild(mathplayer); 189 document.namespaces.add("m","http://www.w3.org/1998/Math/MathML"); 190 HUB.Browser.mpNamespace = true; 191 } 192 if (!HUB.Browser.mpImported) { 193 document.namespaces.m.doImport("#mathplayer"); 194 HUB.Browser.mpImported = true; 195 } 196 } catch (err) { 197 // 198 // If that fails, give an alert about security settings 199 // 200 if (!this.config.noMathPlayerWarning) { 201 alert(MathJax.Localization._(["MathML", "MathPlayer"], 202 "MathJax was not able to set up MathPlayer.\n\n"+ 203 "If MathPlayer is not installed, you need to install it first.\n"+ 204 "Otherwise, your security settings may be preventing ActiveX \n"+ 205 "controls from running. Use the Internet Options item under\n"+ 206 "the Tools menu and select the Security tab, then press the\n"+ 207 "Custom Level button. Check that the settings for\n"+ 208 "'Run ActiveX Controls', and 'Binary and script behaviors'\n"+ 209 "are enabled.\n\n"+ 210 "Currently you will see error messages rather than\n"+ 211 "typeset mathematics.")); 212 } 213 } 214 } else { 215 // 216 // Get the default sizes (need styles in place to do this) 217 // 218 document.body.appendChild(this.EmExSpan); 219 this.defaultEx = this.EmExSpan.firstChild.offsetWidth/60; 220 this.defaultMEx = this.EmExSpan.lastChild.offsetWidth/60; 221 document.body.removeChild(this.EmExSpan); 222 } 223 }, 224 225 preTranslate: function (state) { 226 var scripts = state.jax[this.id], i, m = scripts.length, 227 script, prev, span, test, math, jax, ex, mex, scale; 228 for (i = 0; i < m; i++) { 229 script = scripts[i]; if (!script.parentNode) continue; 230 if (!this.initialized) {this.InitializeMML()} 231 // 232 // Remove any existing output 233 // 234 prev = script.previousSibling; 235 if (prev && prev.className === "MathJax_MathML") {prev.parentNode.removeChild(prev)} 236 // 237 // Add the MathJax span 238 // 239 jax = script.MathJax.elementJax; if (!jax) continue; 240 math = jax.root; jax.NativeMML = {}; 241 var type = (math.Get("display") === "block" ? "div" : "span"); 242 span = HTML.Element(type,{ 243 className: "MathJax_MathML", id:jax.inputID+"-Frame" 244 },[["span",{ 245 className:"MathJax_MathContainer", isMathJax: true, jaxID:this.id, 246 style:{position:"relative", display:"inline-block", "white-space":"nowrap"} 247 }, [["span",{isMathJax:true, style:{display:"inline-block"}}]] // for Firefox hover and zoom 248 ]]); 249 script.parentNode.insertBefore(span,script); 250 // 251 // Add the test span for determining scales 252 // 253 if (!isMSIE) {script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script)} 254 } 255 // 256 // Determine the scaling factors for each script 257 // (this only requires one reflow rather than a reflow for each equation) 258 // 259 for (i = 0; i < m; i++) { 260 script = scripts[i]; if (!script.parentNode) continue; 261 jax = script.MathJax.elementJax; if (!jax) continue; 262 if (!isMSIE) { 263 test = script.previousSibling; 264 ex = test.firstChild.offsetWidth/60; 265 mex = test.lastChild.offsetWidth/60; 266 if (ex === 0 || ex === "NaN") {ex = this.defaultEx; mex = this.defaultMEx} 267 scale = (this.config.matchFontHeight && mex > 1 ? ex/mex : 1); 268 scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale) * this.config.scale); 269 jax.NativeMML.ex = ex; jax.NativeMML.mex = mex; 270 } else {scale = 100} 271 jax.NativeMML.fontSize = scale+"%"; 272 jax.NativeMML.scale = scale/100; 273 } 274 // 275 // Remove the test spans used for determining scales 276 // 277 if (!isMSIE) { 278 for (i = 0; i < m; i++) { 279 script = scripts[i]; 280 if (script.parentNode && script.MathJax.elementJax) { 281 script.parentNode.removeChild(script.previousSibling); 282 } 283 } 284 } 285 }, 286 287 // 288 // Add a SPAN to use as a container, and render the math into it 289 // 290 Translate: function (script) { 291 if (!script.parentNode) return; 292 // 293 // Get the jax and the container and set the size 294 // 295 var jax = script.MathJax.elementJax, math = jax.root; 296 var span = document.getElementById(jax.inputID+"-Frame"); if (!span) return; 297 var container = span.firstChild, mspan = container.firstChild; 298 this.ex = jax.NativeMML.ex || this.defaultEx; 299 this.scale = jax.NativeMML.scale || 1; 300 if (this.scale !== 1) {span.style.fontSize = jax.NativeMML.fontSize} 301 // 302 // Convert to MathML (if restarted, remove any partial math) 303 // 304 try {math.toNativeMML(mspan,jax)} catch (err) { 305 if (err.restart) {while (mspan.firstChild) {mspan.removeChild(mspan.firstChild)}} 306 throw err; 307 } 308 // 309 // Add event handlers 310 // 311 if (isMSIE) { 312 if (container.addEventListener) { 313 for (var id in this.MSIE9events) {if (this.MSIE9events.hasOwnProperty(id)) { 314 container.addEventListener(id,this.MSIE9event,true); 315 }} 316 } else { 317 var config = (this.config.showMathMenuMSIE != null ? this : HUB).config; 318 if (config.showMathMenuMSIE && !this.settings.mpContext && !this.settings.mpMouse) 319 {this.MSIEoverlay(container)} else 320 {container.style.position = ""; mspan.firstChild.onmousedown = this.MSIEaltMenu} 321 } 322 } else { 323 container.oncontextmenu = EVENT.Menu; 324 container.onmouseover = EVENT.Mouseover; 325 container.onmouseout = EVENT.Mouseout; 326 container.onmousedown = EVENT.Mousedown; 327 container.onclick = EVENT.Click; 328 container.ondblclick = EVENT.DblClick; 329 // Added for keyboard accessible menu. 330 container.onkeydown = EVENT.Keydown; 331 container.tabIndex = HUB.getTabOrder(jax); 332 if (HUB.Browser.noContextMenu) { 333 container.ontouchstart = TOUCH.start; 334 container.ontouchend = TOUCH.end; 335 } 336 } 337 }, 338 339 postTranslate: function (state) { 340 if (this.forceReflow) { 341 // 342 // Firefox messes up some mtable's when they are dynamically created 343 // but gets them right on a reflow, so force reflow by toggling a stylesheet 344 // 345 var sheet = (document.styleSheets||[])[0]||{}; 346 sheet.disabled = true; sheet.disabled = false; 347 } 348 }, 349 350 // 351 // Remove MathML preceeding the script 352 // 353 Remove: function (jax) { 354 var span = jax.SourceElement(); if (!span) return; 355 span = span.previousSibling; if (!span) return; 356 if (span.className.match(/MathJax_MathML/)) {span.parentNode.removeChild(span)} 357 }, 358 // 359 // The namespace to use for MML 360 // 361 MMLnamespace: "http://www.w3.org/1998/Math/MathML", 362 363 isFullWidth: function (node) { 364 if (!node) return; 365 var width = node.getAttribute("width") || 366 (String(node.getAttribute("style")).match(/(?:^| )width: *([^; ]*)/)||[])[1]; 367 if (width) return !!width.match(/%/); 368 if (node.nodeName.match(/^(semantics|math|mstyle)$/)) { 369 width = this.isFullWidth(node.firstChild); 370 } else if (node.nodeName.toLowerCase() === "mrow") { 371 for (var i = 0, m = node.childNodes.length; i < m && !width; i++) 372 width = this.isFullWidth(node.childNodes[i]); 373 } 374 if (width) { 375 var style = "width:100%; "+(node.getAttribute("style")||""); 376 node.setAttribute("style",style.replace(/ +$/,"")); 377 } 378 return width; 379 }, 380 381 // 382 // For MSIE, we must overlay the MathPlayer object to trap the events 383 // (since they can't be cancelled when the events are on the <math> tag 384 // itself). The events we DON'T want are transferred to the math element, 385 // and the others are handled directly. 386 // 387 MSIEoverlay: function (span) { 388 var math = span.firstChild; 389 if (math.nodeName.toLowerCase() === "span") {math = math.firstChild} 390 var bbox = this.getHoverBBox(null,math,{}); 391 HTML.addElement(span,"span",{ 392 style:{display:"inline-block", width:0, height:0, position:"relative"} 393 },[["span",{isMathJax: true, className: "MathJax_MathPlayer_Overlay", 394 style:{ 395 display:"inline-block", position:"absolute", 396 left:HOVER.Px(-bbox.w), top:HOVER.Px(-bbox.h-(bbox.y||0)-1), 397 width:HOVER.Px(bbox.w), height:HOVER.Px(bbox.h+bbox.d), cursor:"pointer", 398 "background-color":"white", filter:"alpha(opacity=0)" 399 } 400 }]]); 401 HUB.Insert(span,{ 402 msieMath: math, 403 onmousedown: this.MSIEevent, oncontextmenu: this.MSIEevent, onclick: this.MSIEevent, 404 onmouseup: this.MSIEevent, onmousemove: this.MSIEevent, ondblclick: this.MSIEevent, 405 onmouseover: this.MSIEevent, onmouseout: this.MSIEevent 406 }); 407 }, 408 MSIEevents: { 409 mousedown:"Mousedown", contextmenu:"ContextMenu", click:"Click", 410 mouseup:"Mouseup", mousemove:"Mousemove", dblclick: "DblClick", 411 mouseover:"Mouseover", mouseout:"Mouseout" 412 }, 413 MSIEevent: function () { 414 var event = window.event; 415 var type = nMML.MSIEevents[event.type]; 416 if (nMML[type] && nMML[type](event,this) === false) {return false} 417 if (ZOOM && ZOOM.HandleEvent(event,type,this) === false) {return false} 418 if (event.srcElement.className === "MathJax_MathPlayer_Overlay" && this.msieMath.fireEvent) { 419 // 420 // For now, ignore all other events. This will disable MathPlayer's zoom 421 // feature, but also its <maction> support. 422 // 423 if (type === "ContextMenu" || type === "Mouseover" || type === "Mouseout") 424 {this.msieMath.fireEvent("on"+event.type,event)} 425 } 426 return EVENT.False(event); 427 }, 428 MSIEaltMenu: function () { 429 var container = this.parentNode.parentNode; 430 while (!container.jaxID) {container = container.parentNode} 431 EVENT.AltContextMenu(window.event,container); 432 }, 433 434 MSIE9events: { 435 contextmenu:"Menu", click:"Click", dblclick: "DblClick", 436 mouseup:"False", mouseover:"Mouseover", mouseout:"Mouseout" 437 }, 438 MSIE9event: function (event) { 439 if (event.type === "contextmenu" && nMML.settings.mpContext) {return true} 440 if (event.type === "mouseup" && nMML.settings.mpMouse) {return true} 441 if (event.type === "click" && nMML.settings.mpContext) 442 {return EVENT.AltContextMenu(event,this)} 443 var type = nMML.MSIE9events[event.type]; 444 return EVENT[type].call(this,event); 445 }, 446 447 getJaxFromMath: function (math) { 448 math = math.parentNode; 449 do {math = math.nextSibling} while (math && math.nodeName.toLowerCase() !== "script"); 450 return HUB.getJaxFor(math); 451 }, 452 getHoverSpan: function (jax,math) {return math.firstChild}, 453 getHoverBBox: function (jax,span,math) {return EVENT.getBBox(span.parentNode)}, 454 455 Zoom: function (jax,span,math,Mw,Mh) { 456 jax.root.toNativeMML(span); 457 if (this.msieIE8HeightBug) {span.style.position = "absolute"} 458 if (nMML.widthBug) {span.style.width = span.parentNode.style.width = ""} 459 if (span.parentNode.style.width.match(/%$/)) 460 {span.parentNode.style.minWidth = Math.ceil(3*Mh/4)+"px"} // for full-width tables 461 var mW = math.offsetWidth || math.scrollWidth, 462 mH = math.offsetHeight || math.scrollHeight; 463 var zW = span.offsetWidth, zH = span.offsetHeight; 464 if (nMML.widthBug || span.style.width.match(/%/)) { 465 // 466 // FF doesn't get width of <math> right, so get it from <mrow> 467 // 468 var W = span.firstChild.firstChild.scrollWidth; 469 if (W > zW) {zW = W; span.parentNode.style.width = span.style.minWidth = zW + "px";} 470 } 471 if (this.msieIE8HeightBug) {span.style.position = ""} 472 return {Y:-EVENT.getBBox(span.parentNode).h, mW:mW, mH:mH, zW:zW, zH:zH} 473 }, 474 475 NAMEDSPACE: { 476 negativeveryverythinmathspace: "-.0556em", 477 negativeverythinmathspace: "-.1111em", 478 negativethinmathspace: "-.1667em", 479 negativemediummathspace: "-.2222em", 480 negativethickmathspace: "-.2778em", 481 negativeverythickmathspace: "-.3333em", 482 negativeveryverythickmathspace: "-.3889em", 483 veryverythinmathspace: ".0556em", 484 verythinmathspace: ".1111em", 485 thinmathspace: ".1667em", 486 mediummathspace: ".2222em", 487 thickmathspace: ".2778em", 488 verythickmathspace: ".3333em", 489 veryverythickmathspace: ".3889em" 490 } 491 }); 492 493 HUB.Register.StartupHook("mml Jax Ready",function () { 494 495 MML = MathJax.ElementJax.mml; 496 497 MML.mbase.Augment({ 498 // 499 // Add a MathML tag of the correct type, and set its attributes 500 // then populate it with its children and append it to the parent 501 // 502 toNativeMML: function (parent) { 503 var tag = this.NativeMMLelement(this.type); 504 this.NativeMMLattributes(tag); 505 for (var i = 0, m = this.data.length; i < m; i++) { 506 if (this.data[i]) {this.data[i].toNativeMML(tag)} 507 else {tag.appendChild(this.NativeMMLelement("mrow"))} 508 } 509 parent.appendChild(tag); 510 }, 511 // 512 // Look for attributes that are different from the defaults 513 // and set those in the tag's attribute list 514 // 515 NativeMMLattributes: function (tag) { 516 var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults); 517 var names = (this.attrNames||MML.copyAttributeNames), 518 skip = MML.skipAttributes, copy = MML.copyAttributes; 519 if (!this.attrNames) { 520 for (var id in defaults) {if (!skip[id] && !copy[id] && defaults.hasOwnProperty(id)) { 521 if (this[id] != null && this[id] !== defaults[id]) 522 tag.setAttribute(id,this.NativeMMLattribute(this[id])); 523 }} 524 } 525 for (var i = 0, m = names.length; i < m; i++) { 526 if (copy[names[i]] === 1 && !defaults.hasOwnProperty(names[i])) continue; 527 var value = (this.attr||{})[names[i]]; if (value == null) {value = this[names[i]]} 528 if (value != null) {tag.setAttribute(names[i],this.NativeMMLattribute(value))} 529 } 530 this.NativeMMLclass(tag); 531 }, 532 NativeMMLclass: function (tag) { 533 var CLASS = []; if (this["class"]) {CLASS.push(this["class"])} 534 if (this.isa(MML.TeXAtom)) { 535 var TEXCLASS = ["ORD","OP","BIN","REL","OPEN","CLOSE","PUNCT","INNER","VCENTER"][this.texClass]; 536 if (TEXCLASS) { 537 CLASS.push("MJX-TeXAtom-"+TEXCLASS) 538 if (TEXCLASS === "OP" && !this.movablelimits) CLASS.push("MJX-fixedlimits"); 539 } 540 } 541 if (this.mathvariant && this.NativeMMLvariants[this.mathvariant]) 542 {CLASS.push("MJX"+this.mathvariant)} 543 if (this.variantForm) {CLASS.push("MJX-variant")} 544 if (CLASS.length) {tag.setAttribute("class",CLASS.join(" "))} 545 }, 546 NativeMMLattribute: function (value) { 547 value = String(value); 548 if (nMML.NAMEDSPACE[value]) {value = nMML.NAMEDSPACE[value]} // MP doesn't do negative spaces 549 else if (value.match(/^\s*(([-+])?(\d+(\.\d*)?|\.\d+))\s*mu\s*$/)) 550 {value = (RegExp.$2||"")+((1/18)*RegExp.$3).toFixed(3).replace(/\.?0+$/,"")+"em"} // FIXME: should take scriptlevel into account 551 else if (this.NativeMMLvariants[value]) {value = this.NativeMMLvariants[value]} 552 return value; 553 }, 554 NativeMMLvariants: { 555 "-tex-caligraphic": MML.VARIANT.SCRIPT, 556 "-tex-caligraphic-bold": MML.VARIANT.BOLDSCRIPT, 557 "-tex-oldstyle": MML.VARIANT.NORMAL, 558 "-tex-oldstyle-bold": MML.VARIANT.BOLD, 559 "-tex-mathit": MML.VARIANT.ITALIC 560 }, 561 // 562 // Create a MathML element 563 // 564 NativeMMLelement: function (type) { 565 var math = ( HUB.Browser.mpNamespace ? document.createElement("m:"+type) : 566 (document.createElementNS ? document.createElementNS(nMML.MMLnamespace,type) : 567 document.createElement(type))); 568 math.isMathJax = true; 569 return math; 570 } 571 }); 572 573 MML.mrow.Augment({ 574 // 575 // Make inferred rows not include an mrow tag 576 // 577 toNativeMML: function (parent) { 578 var i, m; 579 if (this.inferred && this.parent.inferRow) { 580 for (i = 0, m = this.data.length; i < m; i++) { 581 if (this.data[i]) {this.data[i].toNativeMML(parent)} 582 else {parent.appendChild(this.NativeMMLelement("mrow"))} 583 } 584 } else if (nMML.stretchyMoBug && (this.open || this.close)) { 585 // 586 // This element contains opening and/or closing fences. Opera is not 587 // able to stretch <mo> operators, so let's use an <mfenced> element 588 // instead. 589 // 590 var mfenced = this.NativeMMLelement("mfenced"); 591 this.NativeMMLattributes(mfenced); 592 i = 0, m = this.data.length; 593 if (this.open) { mfenced.setAttribute("open", this.open); i++; } 594 if (this.close) { mfenced.setAttribute("close", this.close); m--; } 595 var tag = mfenced; 596 if (m - i + 1 > 1) { 597 // 598 // If there are several children, put them in an <mrow> 599 // 600 tag = this.NativeMMLelement("mrow"); 601 parent.appendChild(mfenced); 602 parent = mfenced; 603 } 604 for (; i < m; i++) { 605 if (this.data[i]) {this.data[i].toNativeMML(tag)} 606 else {tag.appendChild(this.NativeMMLelement("mrow"))} 607 } 608 parent.appendChild(tag); 609 } else { 610 this.SUPER(arguments).toNativeMML.call(this,parent); 611 } 612 } 613 }); 614 615 MML.msubsup.Augment({ 616 // 617 // Use proper version of msub, msup, or msubsup, depending on 618 // which items are present 619 // 620 toNativeMML: function (parent) { 621 var type = this.type; 622 if (this.data[this.sup] == null) {type = "msub"} 623 if (this.data[this.sub] == null) {type = "msup"} 624 var tag = this.NativeMMLelement(type); 625 this.NativeMMLattributes(tag); 626 if (this.data[0]) {delete this.data[0].inferred} 627 for (var i = 0, m = this.data.length; i < m; i++) 628 {if (this.data[i]) {this.data[i].toNativeMML(tag)}} 629 parent.appendChild(tag); 630 } 631 }); 632 633 MML.munderover.Augment({ 634 // 635 // Use proper version of munder, mover, or munderover, depending on 636 // which items are present. Handle movablelimits on TeXAtom base. 637 // 638 toNativeMML: function (parent) { 639 var type = this.type; 640 var base = this.data[this.base]; 641 if (base && base.isa(MML.TeXAtom) && base.movablelimits && !base.Get("displaystyle")) { 642 type = "msubsup"; 643 if (this.data[this.under] == null) {type = "msup"} 644 if (this.data[this.over] == null) {type = "msub"} 645 } else { 646 if (this.data[this.under] == null) {type = "mover"} 647 if (this.data[this.over] == null) {type = "munder"} 648 } 649 var tag = this.NativeMMLelement(type); 650 this.NativeMMLattributes(tag); 651 if (this.data[0]) {delete this.data[0].inferred} 652 for (var i = 0, m = this.data.length; i < m; i++) 653 {if (this.data[i]) {this.data[i].toNativeMML(tag)}} 654 parent.appendChild(tag); 655 } 656 }); 657 658 if (!isMSIE) { 659 var SPLIT = HUB.SplitList; 660 MML.mtable.Augment({ 661 toNativeMML: function (parent) { 662 var i, m; 663 if (nMML.tableSpacingBug) { 664 // 665 // Parse the rowspacing/columnspacing. For convenience, we convert 666 // them to a left/top padding value that will be applied to each 667 // cell. The leftmost/topmost cells will use "0px". 668 // 669 var values = this.getValues("rowspacing", "columnspacing"); 670 this.nMMLtopPadding = SPLIT("0px "+values.rowspacing); 671 this.nMMLleftPadding = SPLIT("0px "+values.columnspacing); 672 // 673 // Transmit the top padding to each row. 674 // If this.parent.nMML.topPadding does not contain enough value, 675 // repeat the last one. 676 // 677 var tp = this.nMMLtopPadding, M = tp.length; 678 for (i = 0, m = this.data.length; i < m; i++) { 679 if (this.data[i]) 680 {this.data[i].nMMLtopPadding = tp[i < M ? i : M-1]} 681 } 682 } 683 if (nMML.tableLabelBug) { 684 // 685 // Look for labeled rows so we know how to handle them 686 // 687 for (i = 0, m = this.data.length; i < m; i++) { 688 if (this.data[i] && this.data[i].isa(MML.mlabeledtr)) { 689 var align = HUB.config.displayAlign.charAt(0), 690 side = this.Get("side").charAt(0); 691 this.nMMLhasLabels = true; 692 this.nMMLlaMatch = (align === side); 693 this.nMMLforceWidth = 694 (align === "c" || !!((this.width||"").match("%"))); 695 break; 696 } 697 } 698 } 699 // 700 // Firefox < 13 doesn't handle width, so put it in styles instead 701 // 702 if (this.width && this.ffTableWidthBug) { 703 var styles = (this.style||"").replace(/;\s*$/,"").split(";"); 704 if (styles[0] === "") {styles.shift()} 705 styles.push("width:"+this.width); 706 this.style = styles.join(";"); 707 } 708 this.SUPER(arguments).toNativeMML.call(this,parent); 709 // 710 if (this.nMMLhasLabels) { 711 var mtable = parent.firstChild; 712 // 713 // Add column attributes on the left when extra columns where inserted 714 // 715 if (this.nMMLforceWidth || side !== "r") { 716 var n = (align !== "l" ? 1 : 0) + (side === "l" ? 1 : 0); 717 if (n) { 718 var attr = {columnalign:"left", columnwidth:"auto", 719 columnspacing:"0px", columnlines:"none"}; 720 for (var id in attr) {if (attr.hasOwnProperty(id) && this[id]) { 721 var cols = [attr[id],attr[id]].slice(2-n).join(" ")+" "; 722 mtable.setAttribute(id,cols+mtable.getAttribute(id)); 723 }} 724 } 725 } 726 // 727 // Force the table width to 100% when needed 728 // 729 if (this.nMMLforceWidth || !this.nMMLlaMatch) 730 {mtable.setAttribute("width","100%")} 731 } 732 } 733 }); 734 MML.mtr.Augment({ 735 toNativeMML: function (parent) { 736 this.SUPER(arguments).toNativeMML.call(this,parent); 737 var mtr = parent.lastChild; 738 if (nMML.tableSpacingBug) { 739 // 740 // Set the row/column spacing. If this.parent.nMMLleftPadding does 741 // not contain enough value, repeat the last one. 742 // 743 var lp = this.parent.nMMLleftPadding, M = lp.length; 744 for (var mtd = mtr.firstChild, i = 0; mtd; mtd = mtd.nextSibling, i++) { 745 CELLSPACING(mtd,this.nMMLtopPadding,lp[i < M ? i : M-1]); 746 } 747 } 748 749 if (nMML.tableLabelBug) { 750 var forceWidth = this.parent.nMMLforceWidth, 751 side = this.parent.Get("side").charAt(0), 752 align = HUB.config.displayAlign.charAt(0); 753 754 if (this.parent.nMMLhasLabels && mtr.firstChild) { 755 // 756 // If we add a label or padding column on the left of mlabeledtr, 757 // mirror that here and remove padding from first table mtd 758 // so the spacing is consistent with unlabeled equations 759 // 760 if (forceWidth || side !== "r") { 761 NOPADDING("Left",mtr.firstChild); 762 if (align !== "l") { 763 mtr.insertBefore(this.NativeMMLelement("mtd"),mtr.firstChild) 764 .setAttribute("style","padding:0"); 765 } 766 if (side === "l") { 767 mtr.insertBefore(this.NativeMMLelement("mtd"),mtr.firstChild) 768 .setAttribute("style","padding:0"); 769 } 770 } 771 // 772 // If columns were added on the right, remove mtd padding 773 // so that spacing is consistent with unlabled equations 774 // 775 if (forceWidth || side !== "l") {NOPADDING("Right",mtr.lastChild)} 776 } 777 } 778 } 779 }); 780 MML.mlabeledtr.Augment({ 781 toNativeMML: function (parent) { 782 var mtr = this.NativeMMLelement("mtr"); 783 this.NativeMMLattributes(mtr); 784 // 785 // Add row data 786 // 787 for (var i = 1, m = this.data.length; i < m; i++) { 788 if (this.data[i]) {this.data[i].toNativeMML(mtr)} 789 else {mtr.appendChild(this.NativeMMLelement("mtd"))} 790 } 791 792 if (nMML.tableSpacingBug) { 793 // 794 // Set the row/column spacing. If this.parent.nMMLleftPadding does 795 // not contain enough value, repeat the last one. 796 // 797 var lp = this.parent.nMMLleftPadding, M = lp.length; i = 0; 798 for (var mtd = mtr.firstChild; mtd; mtd = mtd.nextSibling, i++) { 799 CELLSPACING(mtd,this.nMMLtopPadding,lp[i < M ? i : M-1]); 800 } 801 } 802 803 if (nMML.tableLabelBug && this.data[0]) { 804 var side = this.parent.Get("side").charAt(0), 805 align = HUB.config.displayAlign.charAt(0), 806 indent = HUB.config.displayIndent; 807 // 808 // Create label and either set the column width (if label is on the 809 // same side as the alignment), or use mpadded to hide the label 810 // width 811 // 812 this.data[0].toNativeMML(mtr); 813 var label = mtr.lastChild, pad = label; 814 if (side === align) { 815 label.setAttribute("style","width:"+indent); 816 label.setAttribute("columnalign",HUB.config.displayAlign); 817 } else { 818 pad = this.NativeMMLelement("mpadded"); 819 pad.setAttribute("style","width:0"); 820 pad.setAttribute("width","0px"); 821 pad.appendChild(label.firstChild); 822 label.appendChild(pad); 823 } 824 NOPADDING("",label); mtr.removeChild(label); 825 // 826 // Get spacing to use for separation of label from main table 827 // 828 var width = 100, forceWidth = this.parent.nMMLforceWidth; 829 if ((this.parent.width||"").match(/%/)) { 830 width -= parseFloat(this.parent.width) 831 }; 832 var w = width; 833 // 834 // Add spacing (and possibly label) at the left if needed 835 // 836 if (forceWidth || side !== "r") { 837 NOPADDING("Left",mtr.firstChild); 838 if (align !== "l") { 839 if (align === "c") {w /= 2}; width -= w; 840 mtr.insertBefore(this.NativeMMLelement("mtd"),mtr.firstChild) 841 .setAttribute("style","padding:0;width:"+w+"%"); 842 } 843 if (side === "l") {mtr.insertBefore(label,mtr.firstChild)} 844 } 845 // 846 // Add spacing (and possibly label) at the right if needed 847 // 848 if (forceWidth || side !== "l") { 849 NOPADDING("Right",mtr.lastChild); 850 if (align !== "r") { 851 mtr.appendChild(this.NativeMMLelement("mtd")) 852 .setAttribute("style","padding:0;width:"+width+"%"); 853 } 854 if (side === "r") { 855 if (side !== align) {pad.setAttribute("lspace","-1width")} 856 mtr.appendChild(label); 857 } 858 } 859 } 860 // 861 // Add row to table 862 // 863 parent.appendChild(mtr); 864 } 865 }); 866 867 MML.mtd.Augment({ 868 toNativeMML: function (parent) { 869 var tag = parent.appendChild(this.NativeMMLelement(this.type)); 870 this.NativeMMLattributes(tag); 871 if (nMML.mtdWidthBug) { 872 nMML.adjustWidths.push(tag); 873 tag = tag.appendChild(this.NativeMMLelement("mrow")); 874 } 875 for (var i = 0, m = this.data.length; i < m; i++) { 876 if (this.data[i]) {this.data[i].toNativeMML(tag)} 877 else {tag.appendChild(this.NativeMMLelement("mrow"))} 878 } 879 } 880 }); 881 882 MML.mspace.Augment({ 883 toNativeMML: function (parent) { 884 this.SUPER(arguments).toNativeMML.call(this,parent); 885 if (nMML.spaceWidthBug && this.width) { 886 var mspace = parent.lastChild; 887 var width = mspace.getAttribute("width"); 888 var style = (mspace.getAttribute("style") || "").replace(/;?\s*/,"; "); 889 mspace.setAttribute("style",style+"width:"+width); 890 } 891 } 892 }); 893 894 var fontDir = AJAX.fileURL(MathJax.OutputJax.fontDir+"/HTML-CSS/TeX/otf"); 895 896 /* 897 * Add fix for mathvariant issues 898 */ 899 nMML.Augment({ 900 config: { 901 styles: { 902 '[class="MJX-tex-oldstyle"]': {"font-family":"MathJax_Caligraphic, MathJax_Caligraphic-WEB"}, 903 '[class="MJX-tex-oldstyle-bold"]': {"font-family":"MathJax_Caligraphic, MathJax_Caligraphic-WEB", "font-weight":"bold"}, 904 '[class="MJX-tex-caligraphic"]': {"font-family":"MathJax_Caligraphic, MathJax_Caligraphic-WEB"}, 905 '[class="MJX-tex-caligraphic-bold"]': {"font-family":"MathJax_Caligraphic, MathJax_Caligraphic-WEB", "font-weight":"bold"}, 906 907 '@font-face /*1*/': { 908 "font-family": "MathJax_Caligraphic-WEB", 909 "src": "url('"+fontDir+"/MathJax_Caligraphic-Regular.otf')" 910 }, 911 '@font-face /*2*/': { 912 "font-family": "MathJax_Caligraphic-WEB", "font-weight":"bold", 913 "src": "url('"+fontDir+"/MathJax_Caligraphic-Bold.otf')" 914 } 915 } 916 } 917 }); 918 if (!this.handlesVariants) { 919 nMML.Augment({ 920 config: { 921 styles: { 922 '[mathvariant="double-struck"]': {"font-family":"MathJax_AMS, MathJax_AMS-WEB"}, 923 '[mathvariant="script"]': {"font-family":"MathJax_Script, MathJax_Script-WEB"}, 924 '[mathvariant="fraktur"]': {"font-family":"MathJax_Fraktur, MathJax_Fraktur-WEB"}, 925 '[mathvariant="bold-script"]': {"font-family":"MathJax_Script, MathJax_Caligraphic-WEB", "font-weight":"bold"}, 926 '[mathvariant="bold-fraktur"]': {"font-family":"MathJax_Fraktur, MathJax_Fraktur-WEB", "font-weight":"bold"}, 927 '[mathvariant="monospace"]': {"font-family":"monospace"}, 928 '[mathvariant="sans-serif"]': {"font-family":"sans-serif"}, 929 '[mathvariant="bold-sans-serif"]': {"font-family":"sans-serif", "font-weight":"bold"}, 930 '[mathvariant="sans-serif-italic"]': {"font-family":"sans-serif", "font-style":"italic"}, 931 '[mathvariant="sans-serif-bold-italic"]': {"font-family":"sans-serif", "font-style":"italic", "font-weight":"bold"}, 932 933 '@font-face /*3*/': { 934 "font-family": "MathJax_AMS-WEB", 935 "src": "url('"+fontDir+"/MathJax_AMS-Regular.otf')" 936 }, 937 '@font-face /*4*/': { 938 "font-family": "MathJax_Script-WEB", 939 "src": "url('"+fontDir+"/MathJax_Script-Regular.otf')" 940 }, 941 '@font-face /*5*/': { 942 "font-family": "MathJax_Fraktur-WEB", 943 "src": "url('"+fontDir+"/MathJax_Fraktur-Regular.otf')" 944 }, 945 '@font-face /*6*/': { 946 "font-family": "MathJax_Fraktur-WEB", "font-weight":"bold", 947 "src": "url('"+fontDir+"/MathJax_Fraktur-Bold.otf')" 948 } 949 } 950 } 951 }); 952 } 953 } 954 955 MML.math.Augment({ 956 toNativeMML: function (parent,jax) { 957 var tag = this.NativeMMLelement(this.type), math = tag; 958 var annotate = (jax ? MathJax.InputJax[jax.inputJax].annotationEncoding : null); 959 var i, m; 960 nMML.adjustWidths = []; 961 // 962 // Some browsers don't seem to add the xmlns attribute, so do it by hand. 963 // 964 tag.setAttribute("xmlns",nMML.MMLnamespace); 965 this.NativeMMLattributes(tag); 966 // 967 // Use an extra <mrow> in FF so that we can get the correct width 968 // (the math element doesn't always have an accurate one, see below) 969 // 970 if (nMML.widthBug) {tag = tag.appendChild(this.NativeMMLelement("mrow"))} 971 // 972 // Addannotation if the input jax provides an annotation encoding 973 // 974 if (annotate) { 975 tag = tag.appendChild(this.NativeMMLelement("semantics")) 976 tag.appendChild(this.NativeMMLelement("mrow")); 977 var annotation = tag.appendChild(this.NativeMMLelement("annotation")); 978 annotation.appendChild(document.createTextNode(jax.originalText)); 979 annotation.setAttribute("encoding",annotate); 980 tag = tag.firstChild; // mrow 981 } 982 // 983 // Add the children 984 // 985 for (i = 0, m = this.data.length; i < m; i++) { 986 if (this.data[i]) {this.data[i].toNativeMML(tag)} 987 else {tag.appendChild(this.NativeMMLelement("mrow"))} 988 } 989 // 990 // Look for a top-level mtable and if it has labels 991 // Make sure the containers have 100% width, when needed. 992 // If the label is on the same side as alignment, 993 // override the margin set by the stylesheet. 994 // 995 var mtable = ((this.data[0]||{data:[]}).data[0]||{}); 996 if (mtable.nMMLhasLabels) { 997 if (mtable.nMMLforceWidth || !mtable.nMMLlaMatch) { 998 tag.setAttribute("style","width:100%") // mrow node 999 if (annotate) tag.parentNode.setAttribute("style","width:100%"); // semantics node 1000 }; 1001 if (mtable.nMMLlaMatch) { 1002 if (parent.parentNode.parentNode.nodeName.toLowerCase() === "div") { 1003 parent.parentNode.parentNode.style 1004 .setProperty("margin-"+HUB.config.displayAlign,"0px","important"); 1005 } 1006 } 1007 } 1008 // 1009 // Check if container must have width set to 100% 1010 // 1011 var fullWidth = nMML.isFullWidth(math); 1012 if (fullWidth) {parent.style.width = parent.parentNode.style.width = "100%"} 1013 // 1014 // Add the math to the page 1015 // 1016 parent.appendChild(math); 1017 // 1018 // Firefox can't seem to get the width of <math> elements right, so 1019 // use an <mrow> to get the actual width and set the style on the 1020 // parent element to match. Even if we set the <math> width properly, 1021 // it doesn't seem to propagate up to the <span> correctly. 1022 // 1023 if (nMML.widthBug &&!fullWidth) { 1024 // 1025 // Convert size to ex's so that it scales properly if the print media 1026 // has a different font size. 1027 // 1028 parent.style.width = (math.firstChild.scrollWidth/nMML.ex/nMML.scale).toFixed(3) + "ex"; 1029 // 1030 // Save size for later when we check if Web fonts have arrived 1031 // 1032 if (jax) {jax.NativeMML.scrollWidth = math.firstChild.scrollWidth} 1033 } 1034 if (nMML.adjustWidths.length) { 1035 // 1036 // Firefox gets the widths of <mtd> elements wrong, so run 1037 // through them (now that the math is part of the page) and 1038 // fix them up. Use ex's so that they print properly (see above). 1039 // 1040 var mtd = []; 1041 for (i = 0, m = nMML.adjustWidths.length; i < m; i++) { 1042 tag = nMML.adjustWidths[i]; 1043 var style = tag.getAttribute("style") || ""; 1044 if (!style.match(/(^|;)\s*min-width:/)) { 1045 var width = tag.firstChild.scrollWidth; 1046 mtd.push(width); 1047 width = (width/nMML.ex).toFixed(3)+"ex"; 1048 style = style.replace(/;?\s*$/,"; "); 1049 tag.setAttribute("style",style+"min-width:"+width); 1050 } 1051 } 1052 // 1053 // Save the lists so that we can check them later for web font downloads 1054 // 1055 if (!jax) {jax = HUB.getJaxFor(parent)} 1056 if (jax) {jax.NativeMML.mtds = mtd} 1057 math.MathJaxMtds = nMML.adjustWidths; 1058 nMML.adjustWidths = []; // clear it so we don't hold onto the DOM elements 1059 } 1060 } 1061 }); 1062 1063 MML.mfenced.Augment({ 1064 toNativeMML: function (parent) { 1065 if (!nMML.mfencedBug) { 1066 this.SUPER(arguments).toNativeMML.call(this,parent); 1067 return; 1068 } 1069 1070 // 1071 // Some browsers do not handle <mfenced> very well. The MathML spec 1072 // suggests this equivalent construction instead, so let's use it: 1073 // <mrow> open, child1, sep1, child2, ... sep(N-1), childN, close</mrow> 1074 // Opera is a bit special: it does not support stretchy <mo>, does not 1075 // parse mfenced@open/mfenced@close very well, does not support 1076 // mfenced@separators and only displays the first child of the <mfenced> 1077 // element... For this browser, we will use this construction: 1078 // <mfenced open="open" close="close"> 1079 // <mrow>child1, sep1, child2, sep2, ..., sep(N-1), childN</mrow> 1080 // </mfenced> 1081 // 1082 var isOpera = HUB.Browser.isOpera; 1083 var i, m, operator; 1084 1085 // 1086 // parse the open, close and separators attributes. 1087 // 1088 var values = this.getValues("open","close","separators"); 1089 values.open = values.open.replace(/^\s+/,"").replace(/\s+$/,""); 1090 values.close = values.close.replace(/^\s+/,"").replace(/\s+$/,""); 1091 values.separators = values.separators.replace(/\s+/g,"").split(""); 1092 if (values.separators.length == 0) { 1093 // 1094 // No separators specified, do not use separators at all. 1095 // 1096 values.separators = null; 1097 } else if (values.separators.length < this.data.length-1) { 1098 // 1099 // There are not enough separators, repeat the last one. 1100 // 1101 var s = values.separators[values.separators.length-1]; 1102 for (i = this.data.length-1-values.separators.length; i > 0; i--) 1103 {values.separators.push(s)} 1104 } 1105 1106 // 1107 // Create an <mrow> container and attach the attributes of the 1108 // <mfenced> element to it. Note: removeAttribute does not raise any 1109 // exception when the attributes is absent. 1110 // 1111 var tag = this.NativeMMLelement(isOpera ? this.type : "mrow"); 1112 this.NativeMMLattributes(tag); 1113 tag.removeAttribute("separators"); 1114 if (isOpera) { 1115 tag.setAttribute("open", values.open); 1116 tag.setAttribute("close", values.close); 1117 if (this.data.length > 1) { 1118 parent.appendChild(tag); parent = tag; 1119 tag = this.NativeMMLelement("mrow"); 1120 } 1121 } else { 1122 tag.removeAttribute("open"); 1123 tag.removeAttribute("close"); 1124 } 1125 1126 if (!isOpera) { 1127 // 1128 // Append the opening fence 1129 // 1130 operator = this.NativeMMLelement("mo"); 1131 operator.setAttribute("fence", "true"); 1132 operator.textContent = values.open; 1133 tag.appendChild(operator); 1134 } 1135 1136 // 1137 // Append the content of the <mfenced> 1138 // 1139 for (i = 0, m = this.data.length; i < m; i++) { 1140 if (values.separators && i > 0) { 1141 operator = this.NativeMMLelement("mo"); 1142 operator.setAttribute("separator", "true"); 1143 operator.textContent = values.separators[i-1]; 1144 tag.appendChild(operator); 1145 } 1146 if (this.data[i]) {this.data[i].toNativeMML(tag)} 1147 else {tag.appendChild(this.NativeMMLelement("mrow"))} 1148 } 1149 1150 if (!isOpera) { 1151 // 1152 // Append the closing fence 1153 // 1154 operator = this.NativeMMLelement("mo"); 1155 operator.setAttribute("fence", "true"); 1156 operator.textContent = values.close; 1157 tag.appendChild(operator); 1158 } 1159 1160 // finally, append the new element to the parent. 1161 parent.appendChild(tag); 1162 } 1163 }); 1164 1165 MML.TeXAtom.Augment({ 1166 // 1167 // Convert TeXatom to an mrow 1168 // 1169 toNativeMML: function (parent) { 1170 // FIXME: Handle spacing using mpadded? 1171 var tag = this.NativeMMLelement("mrow"); 1172 this.NativeMMLattributes(tag); 1173 this.data[0].toNativeMML(tag); 1174 parent.appendChild(tag); 1175 } 1176 }); 1177 1178 MML.chars.Augment({ 1179 // 1180 // Add a text node 1181 // 1182 toNativeMML: function (parent) { 1183 parent.appendChild(document.createTextNode(this.toString())); 1184 } 1185 }); 1186 1187 MML.entity.Augment({ 1188 // 1189 // Add a text node 1190 // 1191 toNativeMML: function (parent) { 1192 parent.appendChild(document.createTextNode(this.toString())); 1193 } 1194 }); 1195 1196 MML.xml.Augment({ 1197 // 1198 // Insert the XML verbatim 1199 // 1200 toNativeMML: function (parent) { 1201 for (var i = 0, m = this.data.length; i < m; i++) 1202 {parent.appendChild(this.data[i].cloneNode(true))} 1203 } 1204 }); 1205 1206 MML.mi.Augment({ 1207 toNativeMML: function (parent) { 1208 this.SUPER(arguments).toNativeMML.call(this,parent); 1209 if (nMML.miItalicBug) { 1210 if (this.Get("mathvariant") === MML.VARIANT.NORMAL) { 1211 // 1212 // When not explicitly specified, mathvariant is set to "italic" 1213 // with single char mi and to "normal" with multiple char mi. 1214 // Some browsers always set the default to "italic", so let's 1215 // attach an explicit mathvariant="normal" attribute. 1216 // 1217 var mi = parent.lastChild; 1218 mi.setAttribute("mathvariant",MML.VARIANT.NORMAL); 1219 } 1220 } 1221 } 1222 }); 1223 1224 MML.mo.Augment({ 1225 toNativeMML: function (parent) { 1226 this.SUPER(arguments).toNativeMML.call(this,parent); 1227 if (nMML.webkitMoSpacingBug) { 1228 // 1229 // WebKit does not support lspace/rspace values around operators 1230 // (neither explicit nor given by the operator dictionary) and uses 1231 // constant values instead. So let's modify the CSS properties here. 1232 // 1233 1234 var lspace = 0, rspace = 0, p = this.parent; 1235 if (p && p.type === "mrow" && (p.inferred || !p.isEmbellished())) { 1236 // 1237 // Retrieve the values of lspace/rspace and convert named spaces. 1238 // Other values (except unitless) will be parsed by the CSS engine. 1239 // 1240 var values = this.getValues("lspace", "rspace"); 1241 lspace = values.lspace, rspace = values.rspace; 1242 if (nMML.NAMEDSPACE[lspace]) {lspace = nMML.NAMEDSPACE[lspace]} 1243 if (nMML.NAMEDSPACE[rspace]) {rspace = nMML.NAMEDSPACE[rspace]} 1244 } 1245 1246 // 1247 // Now update -webkit-margin-start and -webkit-margin-end. 1248 // 1249 var mo = parent.lastChild; 1250 var span = HTML.Element("span"); 1251 span.style.cssText = (mo.getAttribute("style")||""); 1252 span.style.setProperty("-webkit-margin-start", lspace); 1253 span.style.setProperty("-webkit-margin-end", rspace); 1254 mo.setAttribute("style",span.style.cssText); 1255 } 1256 } 1257 }); 1258 1259 MML.mmultiscripts.Augment({ 1260 toNativeMML: function (parent) { 1261 // 1262 // Some browsers do not implement the mmultiscripts element. 1263 // Try to emulate the support using basic script elements. 1264 // 1265 if (!nMML.mmultiscriptsBug || this.data.length === 0) { 1266 this.SUPER(arguments).toNativeMML.call(this,parent); 1267 return; 1268 } 1269 1270 // 1271 // The children of the mmultiscripts will be wrapped in an mrow so that 1272 // attributes and properties set on the original mmultiscripts will 1273 // be reflected on this mrow element. 1274 // 1275 var tag = this.NativeMMLelement("mrow"); 1276 this.NativeMMLattributes(tag); 1277 1278 // 1279 // Create the base 1280 // 1281 if (this.data[0]) {this.data[0].toNativeMML(tag)} 1282 else {tag.appendChild(this.NativeMMLelement("mrow"))} 1283 var base = tag.removeChild(tag.lastChild); 1284 1285 // 1286 // Process the postscript pairs 1287 // 1288 var m = this.data.length, i, msubsup; 1289 for (i = 1; i < m; i+=2) { 1290 if (this.data[i].type === "mprescripts") break; 1291 1292 msubsup = this.NativeMMLelement("msubsup"); 1293 msubsup.appendChild(base); 1294 1295 // 1296 // append the subscript 1297 // 1298 if (this.data[i]) {this.data[i].toNativeMML(msubsup)} 1299 else {msubsup.appendChild(this.NativeMMLelement("mrow"))} 1300 1301 // 1302 // append the supscript 1303 // 1304 if (i+1 < m && this.data[i+1]) {this.data[i+1].toNativeMML(msubsup)} 1305 else {msubsup.appendChild(this.NativeMMLelement("mrow"))} 1306 1307 base = msubsup; 1308 } 1309 1310 tag.appendChild(base); 1311 1312 // 1313 // Process the prescript pairs 1314 // 1315 for (i++; i < m; i+=2) { 1316 msubsup = this.NativeMMLelement("msubsup"); 1317 msubsup.appendChild(this.NativeMMLelement("mrow")); 1318 1319 // 1320 // append the presubscript 1321 // 1322 if (this.data[i]) {this.data[i].toNativeMML(msubsup)} 1323 else {msubsup.appendChild(this.NativeMMLelement("mrow"))} 1324 1325 // 1326 // append the presupscript 1327 // 1328 if (i+1 < m && this.data[i+1]) {this.data[i+1].toNativeMML(msubsup)} 1329 else {msubsup.appendChild(this.NativeMMLelement("mrow"))} 1330 1331 tag.insertBefore(msubsup, base); 1332 } 1333 1334 parent.appendChild(tag); 1335 } 1336 }); 1337 1338 HUB.Register.StartupHook("TeX mathchoice Ready",function () { 1339 MML.TeXmathchoice.Augment({ 1340 // 1341 // Get the MathML for the selected choice 1342 // 1343 toNativeMML: function (parent) {this.Core().toNativeMML(parent)} 1344 }); 1345 }); 1346 1347 // 1348 // Loading isn't complete until the element jax is modified, 1349 // but can't call loadComplete within the callback for "mml Jax Ready" 1350 // (it would call NativeMML's Require routine, asking for the mml jax again) 1351 // so wait until after the mml jax has finished processing. 1352 // 1353 setTimeout(MathJax.Callback(["loadComplete",nMML,"jax.js"]),0); 1354 }); 1355 1356 1357 // 1358 // Determine browser characteristics 1359 // 1360 HUB.Browser.Select({ 1361 MSIE: function (browser) { 1362 var mode = (document.documentMode || 0); 1363 nMML.msieIE8HeightBug = (mode === 8); 1364 }, 1365 Opera: function (browser) { 1366 nMML.stretchyMoBug = true; 1367 nMML.tableLabelBug = true; 1368 nMML.mfencedBug = true; 1369 nMML.miBug = true; 1370 nMML.mmultiscriptsBug = true; 1371 }, 1372 Firefox: function (browser) { 1373 var is29 = browser.versionAtLeast("29.0"); 1374 nMML.ffTableWidthBug = !browser.versionAtLeast("13.0"); // <mtable width="xx"> not implemented 1375 nMML.forceReflow = !is29; // <mtable> with alignments set don't display properly without a reflow 1376 nMML.widthBug = !is29; // <math> elements don't always get the correct width 1377 nMML.mtdWidthBug = true; // <mtd> widths not properly determined 1378 nMML.handlesVariants = is29; // FF >=29 handles all math variants 1379 1380 // In Firefox < 20, the intrinsic width of <mspace> is not computed 1381 // correctly and thus the element is displayed incorrectly in <mtable>. 1382 nMML.spaceWidthBug = !browser.versionAtLeast("20.0"); 1383 1384 // mtable@rowspacing/mtable@columnspacing not supported. 1385 nMML.tableSpacingBug = !browser.versionAtLeast("33.0"); 1386 nMML.tableLabelBug = true; // mlabeledtr is not implemented. 1387 nMML.mfencedBug = true; // mfenced not displayed correctly 1388 }, 1389 Chrome: function (browser) { 1390 nMML.tableSpacingBug = true; 1391 nMML.tableLabelBug = true; 1392 nMML.mfencedBug = true; 1393 }, 1394 Safari: function (browser) { 1395 nMML.tableSpacingBug = true; 1396 nMML.tableLabelBug = true; 1397 nMML.mfencedBug = true; 1398 nMML.miItalicBug = true; 1399 nMML.webkitMoSpacingBug = true; 1400 nMML.spaceWidthBug = true; 1401 nMML.mmultiscriptsBug = true; 1402 } 1403 }); 1404 1405 1406 HUB.Register.StartupHook("End Cookie",function () { 1407 if (HUB.config.menuSettings.zoom !== "None") 1408 {AJAX.Require("[MathJax]/extensions/MathZoom.js")} 1409 }); 1410 1411 })(MathJax.OutputJax.NativeMML, MathJax.Hub, MathJax.Ajax, MathJax.HTML);