jax.js 44 KB

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