jax.js 54 KB

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