jax.js 55 KB

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