Subversion Repositories wimsdev

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. LaTeXMathML.js
  3. ==============
  4.  
  5. This file, in this form, is due to Douglas Woodall, June 2006.
  6. It contains JavaScript functions to convert (most simple) LaTeX
  7. math notation to Presentation MathML.  It was obtained by
  8. downloading the file ASCIIMathML.js from
  9.         http://www1.chapman.edu/~jipsen/mathml/asciimathdownload/
  10. and modifying it so that it carries out ONLY those conversions
  11. that would be carried out in LaTeX.  A description of the original
  12. file, with examples, can be found at
  13.         www1.chapman.edu/~jipsen/mathml/asciimath.html
  14.         ASCIIMathML: Math on the web for everyone
  15.  
  16. Here is the header notice from the original file:
  17.  
  18. ASCIIMathML.js
  19. ==============
  20. This file contains JavaScript functions to convert ASCII math notation
  21. to Presentation MathML. The conversion is done while the (X)HTML page
  22. loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet
  23. Explorer 6+MathPlayer (http://www.dessci.com/en/products/mathplayer/).
  24. Just add the next line to your (X)HTML page with this file in the same folder:
  25. <script type="text/javascript" src="ASCIIMathML.js"></script>
  26. This is a convenient and inexpensive solution for authoring MathML.
  27.  
  28. Version 1.4.7 Dec 15, 2005, (c) Peter Jipsen http://www.chapman.edu/~jipsen
  29. Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js
  30. For changes see http://www.chapman.edu/~jipsen/mathml/asciimathchanges.txt
  31. If you use it on a webpage, please send the URL to jipsen@chapman.edu
  32.  
  33. This program is free software; you can redistribute it and/or modify
  34. it under the terms of the GNU General Public License as published by
  35. the Free Software Foundation; either version 2 of the License, or (at
  36. your option) any later version.
  37.  
  38. This program is distributed in the hope that it will be useful,
  39. but WITHOUT ANY WARRANTY; without even the implied warranty of
  40. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  41. General Public License (at http://www.gnu.org/copyleft/gpl.html)
  42. for more details.
  43.  
  44. LaTeXMathML.js (ctd)
  45. ==============
  46.  
  47. The instructions for use are the same as for the original
  48. ASCIIMathML.js, except that of course the line you add to your
  49. file should be
  50. <script type="text/javascript" src="LaTeXMathML.js"></script>
  51. Or use absolute path names if the file is not in the same folder
  52. as your (X)HTML page.
  53. */
  54.  
  55. var checkForMathML = true;   // check if browser can display MathML
  56. var notifyIfNoMathML = true; // display note if no MathML capability
  57. var alertIfNoMathML = false;  // show alert box if no MathML capability
  58. // was "red":
  59. var mathcolor = "";          // change it to "" (to inherit) or any other color
  60. // was "serif":
  61. var mathfontfamily = "";      // change to "" to inherit (works in IE)
  62.                               // or another family (e.g. "arial")
  63. var showasciiformulaonhover = true; // helps students learn ASCIIMath
  64. /*
  65. // Commented out by DRW -- not now used -- see DELIMITERS (twice) near the end
  66. var displaystyle = false;     // puts limits above and below large operators
  67. var decimalsign = ".";        // change to "," if you like, beware of `(1,2)`!
  68. var AMdelimiter1 = "`", AMescape1 = "\\\\`"; // can use other characters
  69. var AMdelimiter2 = "$", AMescape2 = "\\\\\\$", AMdelimiter2regexp = "\\$";
  70. var doubleblankmathdelimiter = false; // if true,  x+1  is equal to `x+1`
  71.                                       // for IE this works only in <!--   -->
  72. //var separatetokens;// has been removed (email me if this is a problem)
  73. */
  74. var isIE = document.createElementNS==null;
  75.  
  76. if (document.getElementById==null)
  77.   alert("This webpage requires a recent browser such as\
  78. \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
  79.  
  80. // all further global variables start with "AM"
  81.  
  82. function AMcreateElementXHTML(t) {
  83.   if (isIE) return document.createElement(t);
  84.   else return document.createElementNS("http://www.w3.org/1999/xhtml",t);
  85. }
  86.  
  87. function AMnoMathMLNote() {
  88.   var nd = AMcreateElementXHTML("h3");
  89.   nd.setAttribute("align","center")
  90.   nd.appendChild(AMcreateElementXHTML("p"));
  91.   nd.appendChild(document.createTextNode("To view the "));
  92.   var an = AMcreateElementXHTML("a");
  93.   an.appendChild(document.createTextNode("LaTeXMathML"));
  94.   an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");
  95.   nd.appendChild(an);
  96.   nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));
  97.   an = AMcreateElementXHTML("a");
  98.   an.appendChild(document.createTextNode("MathPlayer"));
  99.   an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");
  100.   nd.appendChild(an);
  101.   nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));
  102.   nd.appendChild(AMcreateElementXHTML("p"));
  103.   return nd;
  104. }
  105.  
  106. function AMisMathMLavailable() {
  107.   if (navigator.appName.slice(0,8)=="Netscape")
  108.     if (navigator.appVersion.slice(0,1)>="5") return null;
  109.     else return AMnoMathMLNote();
  110.   else if (navigator.appName.slice(0,9)=="Microsoft")
  111.     try {
  112.         var ActiveX = new ActiveXObject("MathPlayer.Factory.1");
  113.         return null;
  114.     } catch (e) {
  115.         return AMnoMathMLNote();
  116.     }
  117.   else return AMnoMathMLNote();
  118. }
  119.  
  120. // character lists for Mozilla/Netscape fonts
  121. var AMcal = [0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];
  122. var AMfrk = [0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];
  123. var AMbbb = [0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];
  124.  
  125. var CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4,
  126.     RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8,
  127.     TEXT = 9, BIG = 10, LONG = 11, STRETCHY = 12, MATRIX = 13; // token types
  128.  
  129. var AMsqrt = {input:"\\sqrt",   tag:"msqrt", output:"sqrt",     ttype:UNARY},
  130.   AMroot = {input:"\\root",     tag:"mroot", output:"root",     ttype:BINARY},
  131.   AMfrac = {input:"\\frac",     tag:"mfrac", output:"/",        ttype:BINARY},
  132.   AMover = {input:"\\stackrel", tag:"mover", output:"stackrel", ttype:BINARY},
  133.   AMatop = {input:"\\atop",     tag:"mfrac", output:"",         ttype:INFIX},
  134.   AMchoose = {input:"\\choose", tag:"mfrac", output:"",         ttype:INFIX},
  135.   AMsub  = {input:"_",          tag:"msub",  output:"_",        ttype:INFIX},
  136.   AMsup  = {input:"^",          tag:"msup",  output:"^",        ttype:INFIX},
  137.   AMtext = {input:"\\mathrm",   tag:"mtext", output:"text",     ttype:TEXT},
  138.   AMmbox = {input:"\\mbox",     tag:"mtext", output:"mbox",     ttype:TEXT};
  139.  
  140. // Commented out by DRW to prevent 1/2 turning into a 2-line fraction
  141. // AMdiv   = {input:"/",         tag:"mfrac", output:"/",    ttype:INFIX},
  142. // Commented out by DRW so that " prints literally in equations
  143. // AMquote = {input:"\"",        tag:"mtext", output:"mbox", ttype:TEXT};
  144.  
  145. var AMsymbols = [
  146. //Greek letters
  147. {input:"\\alpha",       tag:"mi", output:"\u03B1", ttype:CONST},
  148. {input:"\\beta",        tag:"mi", output:"\u03B2", ttype:CONST},
  149. {input:"\\gamma",       tag:"mi", output:"\u03B3", ttype:CONST},
  150. {input:"\\delta",       tag:"mi", output:"\u03B4", ttype:CONST},
  151. {input:"\\epsilon",     tag:"mi", output:"\u03B5", ttype:CONST},
  152. {input:"\\varepsilon",  tag:"mi", output:"\u025B", ttype:CONST},
  153. {input:"\\zeta",        tag:"mi", output:"\u03B6", ttype:CONST},
  154. {input:"\\eta",         tag:"mi", output:"\u03B7", ttype:CONST},
  155. {input:"\\theta",       tag:"mi", output:"\u03B8", ttype:CONST},
  156. {input:"\\vartheta",    tag:"mi", output:"\u03D1", ttype:CONST},
  157. {input:"\\iota",        tag:"mi", output:"\u03B9", ttype:CONST},
  158. {input:"\\kappa",       tag:"mi", output:"\u03BA", ttype:CONST},
  159. {input:"\\lambda",      tag:"mi", output:"\u03BB", ttype:CONST},
  160. {input:"\\mu",          tag:"mi", output:"\u03BC", ttype:CONST},
  161. {input:"\\nu",          tag:"mi", output:"\u03BD", ttype:CONST},
  162. {input:"\\xi",          tag:"mi", output:"\u03BE", ttype:CONST},
  163. {input:"\\pi",          tag:"mi", output:"\u03C0", ttype:CONST},
  164. {input:"\\varpi",       tag:"mi", output:"\u03D6", ttype:CONST},
  165. {input:"\\rho",         tag:"mi", output:"\u03C1", ttype:CONST},
  166. {input:"\\varrho",      tag:"mi", output:"\u03F1", ttype:CONST},
  167. {input:"\\varsigma",    tag:"mi", output:"\u03C2", ttype:CONST},
  168. {input:"\\sigma",       tag:"mi", output:"\u03C3", ttype:CONST},
  169. {input:"\\tau",         tag:"mi", output:"\u03C4", ttype:CONST},
  170. {input:"\\upsilon",     tag:"mi", output:"\u03C5", ttype:CONST},
  171. {input:"\\phi",         tag:"mi", output:"\u03C6", ttype:CONST},
  172. {input:"\\varphi",      tag:"mi", output:"\u03D5", ttype:CONST},
  173. {input:"\\chi",         tag:"mi", output:"\u03C7", ttype:CONST},
  174. {input:"\\psi",         tag:"mi", output:"\u03C8", ttype:CONST},
  175. {input:"\\omega",       tag:"mi", output:"\u03C9", ttype:CONST},
  176. {input:"\\Gamma",       tag:"mo", output:"\u0393", ttype:CONST},
  177. {input:"\\Delta",       tag:"mo", output:"\u0394", ttype:CONST},
  178. {input:"\\Theta",       tag:"mo", output:"\u0398", ttype:CONST},
  179. {input:"\\Lambda",      tag:"mo", output:"\u039B", ttype:CONST},
  180. {input:"\\Xi",          tag:"mo", output:"\u039E", ttype:CONST},
  181. {input:"\\Pi",          tag:"mo", output:"\u03A0", ttype:CONST},
  182. {input:"\\Sigma",       tag:"mo", output:"\u03A3", ttype:CONST},
  183. {input:"\\Upsilon",     tag:"mo", output:"\u03A5", ttype:CONST},
  184. {input:"\\Phi",         tag:"mo", output:"\u03A6", ttype:CONST},
  185. {input:"\\Psi",         tag:"mo", output:"\u03A8", ttype:CONST},
  186. {input:"\\Omega",       tag:"mo", output:"\u03A9", ttype:CONST},
  187.  
  188. //fractions
  189. {input:"\\frac12",      tag:"mo", output:"\u00BD", ttype:CONST},
  190. {input:"\\frac14",      tag:"mo", output:"\u00BC", ttype:CONST},
  191. {input:"\\frac34",      tag:"mo", output:"\u00BE", ttype:CONST},
  192. {input:"\\frac13",      tag:"mo", output:"\u2153", ttype:CONST},
  193. {input:"\\frac23",      tag:"mo", output:"\u2154", ttype:CONST},
  194. {input:"\\frac15",      tag:"mo", output:"\u2155", ttype:CONST},
  195. {input:"\\frac25",      tag:"mo", output:"\u2156", ttype:CONST},
  196. {input:"\\frac35",      tag:"mo", output:"\u2157", ttype:CONST},
  197. {input:"\\frac45",      tag:"mo", output:"\u2158", ttype:CONST},
  198. {input:"\\frac16",      tag:"mo", output:"\u2159", ttype:CONST},
  199. {input:"\\frac56",      tag:"mo", output:"\u215A", ttype:CONST},
  200. {input:"\\frac18",      tag:"mo", output:"\u215B", ttype:CONST},
  201. {input:"\\frac38",      tag:"mo", output:"\u215C", ttype:CONST},
  202. {input:"\\frac58",      tag:"mo", output:"\u215D", ttype:CONST},
  203. {input:"\\frac78",      tag:"mo", output:"\u215E", ttype:CONST},
  204.  
  205. //binary operation symbols
  206. {input:"\\pm",          tag:"mo", output:"\u00B1", ttype:CONST},
  207. {input:"\\mp",          tag:"mo", output:"\u2213", ttype:CONST},
  208. {input:"\\triangleleft",tag:"mo", output:"\u22B2", ttype:CONST},
  209. {input:"\\triangleright",tag:"mo",output:"\u22B3", ttype:CONST},
  210. {input:"\\cdot",        tag:"mo", output:"\u22C5", ttype:CONST},
  211. {input:"\\star",        tag:"mo", output:"\u22C6", ttype:CONST},
  212. {input:"\\ast",         tag:"mo", output:"\u002A", ttype:CONST},
  213. {input:"\\times",       tag:"mo", output:"\u00D7", ttype:CONST},
  214. {input:"\\div",         tag:"mo", output:"\u00F7", ttype:CONST},
  215. {input:"\\circ",        tag:"mo", output:"\u2218", ttype:CONST},
  216. //{input:"\\bullet",      tag:"mo", output:"\u2219", ttype:CONST},
  217. {input:"\\bullet",      tag:"mo", output:"\u2022", ttype:CONST},
  218. {input:"\\oplus",       tag:"mo", output:"\u2295", ttype:CONST},
  219. {input:"\\ominus",      tag:"mo", output:"\u2296", ttype:CONST},
  220. {input:"\\otimes",      tag:"mo", output:"\u2297", ttype:CONST},
  221. {input:"\\bigcirc",     tag:"mo", output:"\u25CB", ttype:CONST},
  222. {input:"\\oslash",      tag:"mo", output:"\u2298", ttype:CONST},
  223. {input:"\\odot",        tag:"mo", output:"\u2299", ttype:CONST},
  224. {input:"\\land",        tag:"mo", output:"\u2227", ttype:CONST},
  225. {input:"\\wedge",       tag:"mo", output:"\u2227", ttype:CONST},
  226. {input:"\\lor",         tag:"mo", output:"\u2228", ttype:CONST},
  227. {input:"\\vee",         tag:"mo", output:"\u2228", ttype:CONST},
  228. {input:"\\cap",         tag:"mo", output:"\u2229", ttype:CONST},
  229. {input:"\\cup",         tag:"mo", output:"\u222A", ttype:CONST},
  230. {input:"\\sqcap",       tag:"mo", output:"\u2293", ttype:CONST},
  231. {input:"\\sqcup",       tag:"mo", output:"\u2294", ttype:CONST},
  232. {input:"\\uplus",       tag:"mo", output:"\u228E", ttype:CONST},
  233. {input:"\\amalg",       tag:"mo", output:"\u2210", ttype:CONST},
  234. {input:"\\bigtriangleup",tag:"mo",output:"\u25B3", ttype:CONST},
  235. {input:"\\bigtriangledown",tag:"mo",output:"\u25BD", ttype:CONST},
  236. {input:"\\dag",         tag:"mo", output:"\u2020", ttype:CONST},
  237. {input:"\\dagger",      tag:"mo", output:"\u2020", ttype:CONST},
  238. {input:"\\ddag",        tag:"mo", output:"\u2021", ttype:CONST},
  239. {input:"\\ddagger",     tag:"mo", output:"\u2021", ttype:CONST},
  240. {input:"\\lhd",         tag:"mo", output:"\u22B2", ttype:CONST},
  241. {input:"\\rhd",         tag:"mo", output:"\u22B3", ttype:CONST},
  242. {input:"\\unlhd",       tag:"mo", output:"\u22B4", ttype:CONST},
  243. {input:"\\unrhd",       tag:"mo", output:"\u22B5", ttype:CONST},
  244.  
  245.  
  246. //BIG Operators
  247. {input:"\\sum",         tag:"mo", output:"\u2211", ttype:UNDEROVER},
  248. {input:"\\prod",        tag:"mo", output:"\u220F", ttype:UNDEROVER},
  249. {input:"\\bigcap",      tag:"mo", output:"\u22C2", ttype:UNDEROVER},
  250. {input:"\\bigcup",      tag:"mo", output:"\u22C3", ttype:UNDEROVER},
  251. {input:"\\bigwedge",    tag:"mo", output:"\u22C0", ttype:UNDEROVER},
  252. {input:"\\bigvee",      tag:"mo", output:"\u22C1", ttype:UNDEROVER},
  253. {input:"\\bigsqcap",    tag:"mo", output:"\u2A05", ttype:UNDEROVER},
  254. {input:"\\bigsqcup",    tag:"mo", output:"\u2A06", ttype:UNDEROVER},
  255. {input:"\\coprod",      tag:"mo", output:"\u2210", ttype:UNDEROVER},
  256. {input:"\\bigoplus",    tag:"mo", output:"\u2A01", ttype:UNDEROVER},
  257. {input:"\\bigotimes",   tag:"mo", output:"\u2A02", ttype:UNDEROVER},
  258. {input:"\\bigodot",     tag:"mo", output:"\u2A00", ttype:UNDEROVER},
  259. {input:"\\biguplus",    tag:"mo", output:"\u2A04", ttype:UNDEROVER},
  260. {input:"\\int",         tag:"mo", output:"\u222B", ttype:CONST},
  261. {input:"\\oint",        tag:"mo", output:"\u222E", ttype:CONST},
  262.  
  263. //binary relation symbols
  264. {input:":=",            tag:"mo", output:":=",     ttype:CONST},
  265. {input:"\\lt",          tag:"mo", output:"<",      ttype:CONST},
  266. {input:"\\gt",          tag:"mo", output:">",      ttype:CONST},
  267. {input:"\\ne",          tag:"mo", output:"\u2260", ttype:CONST},
  268. {input:"\\neq",         tag:"mo", output:"\u2260", ttype:CONST},
  269. {input:"\\le",          tag:"mo", output:"\u2264", ttype:CONST},
  270. {input:"\\leq",         tag:"mo", output:"\u2264", ttype:CONST},
  271. {input:"\\leqslant",    tag:"mo", output:"\u2264", ttype:CONST},
  272. {input:"\\ge",          tag:"mo", output:"\u2265", ttype:CONST},
  273. {input:"\\geq",         tag:"mo", output:"\u2265", ttype:CONST},
  274. {input:"\\geqslant",    tag:"mo", output:"\u2265", ttype:CONST},
  275. {input:"\\equiv",       tag:"mo", output:"\u2261", ttype:CONST},
  276. {input:"\\ll",          tag:"mo", output:"\u226A", ttype:CONST},
  277. {input:"\\gg",          tag:"mo", output:"\u226B", ttype:CONST},
  278. {input:"\\doteq",       tag:"mo", output:"\u2250", ttype:CONST},
  279. {input:"\\prec",        tag:"mo", output:"\u227A", ttype:CONST},
  280. {input:"\\succ",        tag:"mo", output:"\u227B", ttype:CONST},
  281. {input:"\\preceq",      tag:"mo", output:"\u227C", ttype:CONST},
  282. {input:"\\succeq",      tag:"mo", output:"\u227D", ttype:CONST},
  283. {input:"\\subset",      tag:"mo", output:"\u2282", ttype:CONST},
  284. {input:"\\supset",      tag:"mo", output:"\u2283", ttype:CONST},
  285. {input:"\\subseteq",    tag:"mo", output:"\u2286", ttype:CONST},
  286. {input:"\\supseteq",    tag:"mo", output:"\u2287", ttype:CONST},
  287. {input:"\\sqsubset",    tag:"mo", output:"\u228F", ttype:CONST},
  288. {input:"\\sqsupset",    tag:"mo", output:"\u2290", ttype:CONST},
  289. {input:"\\sqsubseteq",  tag:"mo", output:"\u2291", ttype:CONST},
  290. {input:"\\sqsupseteq",  tag:"mo", output:"\u2292", ttype:CONST},
  291. {input:"\\sim",         tag:"mo", output:"\u223C", ttype:CONST},
  292. {input:"\\simeq",       tag:"mo", output:"\u2243", ttype:CONST},
  293. {input:"\\approx",      tag:"mo", output:"\u2248", ttype:CONST},
  294. {input:"\\cong",        tag:"mo", output:"\u2245", ttype:CONST},
  295. {input:"\\Join",        tag:"mo", output:"\u22C8", ttype:CONST},
  296. {input:"\\bowtie",      tag:"mo", output:"\u22C8", ttype:CONST},
  297. {input:"\\in",          tag:"mo", output:"\u2208", ttype:CONST},
  298. {input:"\\ni",          tag:"mo", output:"\u220B", ttype:CONST},
  299. {input:"\\owns",        tag:"mo", output:"\u220B", ttype:CONST},
  300. {input:"\\propto",      tag:"mo", output:"\u221D", ttype:CONST},
  301. {input:"\\vdash",       tag:"mo", output:"\u22A2", ttype:CONST},
  302. {input:"\\dashv",       tag:"mo", output:"\u22A3", ttype:CONST},
  303. {input:"\\models",      tag:"mo", output:"\u22A8", ttype:CONST},
  304. {input:"\\perp",        tag:"mo", output:"\u22A5", ttype:CONST},
  305. {input:"\\smile",       tag:"mo", output:"\u2323", ttype:CONST},
  306. {input:"\\frown",       tag:"mo", output:"\u2322", ttype:CONST},
  307. {input:"\\asymp",       tag:"mo", output:"\u224D", ttype:CONST},
  308. {input:"\\notin",       tag:"mo", output:"\u2209", ttype:CONST},
  309.  
  310. //matrices
  311. {input:"\\begin{eqnarray}",     output:"X",     ttype:MATRIX, invisible:true},
  312. {input:"\\begin{array}",        output:"X",     ttype:MATRIX, invisible:true},
  313. {input:"\\\\",                  output:"}&{",   ttype:DEFINITION},
  314. {input:"\\end{eqnarray}",       output:"}}",    ttype:DEFINITION},
  315. {input:"\\end{array}",          output:"}}",    ttype:DEFINITION},
  316.  
  317. //grouping and literal brackets -- ieval is for IE
  318. {input:"\\big",    tag:"mo", output:"X", atval:"1.2", ieval:"2.2", ttype:BIG},
  319. {input:"\\Big",    tag:"mo", output:"X", atval:"1.6", ieval:"2.6", ttype:BIG},
  320. {input:"\\bigg",   tag:"mo", output:"X", atval:"2.2", ieval:"3.2", ttype:BIG},
  321. {input:"\\Bigg",   tag:"mo", output:"X", atval:"2.9", ieval:"3.9", ttype:BIG},
  322. {input:"\\left",   tag:"mo", output:"X", ttype:LEFTBRACKET},
  323. {input:"\\right",  tag:"mo", output:"X", ttype:RIGHTBRACKET},
  324. {input:"{",        output:"{", ttype:LEFTBRACKET,  invisible:true},
  325. {input:"}",        output:"}", ttype:RIGHTBRACKET, invisible:true},
  326.  
  327. {input:"(",        tag:"mo", output:"(",      atval:"1", ttype:STRETCHY},
  328. {input:"[",        tag:"mo", output:"[",      atval:"1", ttype:STRETCHY},
  329. {input:"\\lbrack", tag:"mo", output:"[",      atval:"1", ttype:STRETCHY},
  330. {input:"\\{",      tag:"mo", output:"{",      atval:"1", ttype:STRETCHY},
  331. {input:"\\lbrace", tag:"mo", output:"{",      atval:"1", ttype:STRETCHY},
  332. {input:"\\langle", tag:"mo", output:"\u2329", atval:"1", ttype:STRETCHY},
  333. {input:"\\lfloor", tag:"mo", output:"\u230A", atval:"1", ttype:STRETCHY},
  334. {input:"\\lceil",  tag:"mo", output:"\u2308", atval:"1", ttype:STRETCHY},
  335.  
  336. // rtag:"mi" causes space to be inserted before a following sin, cos, etc.
  337. // (see function AMparseExpr() )
  338. {input:")",       tag:"mo",output:")",      rtag:"mi",atval:"1",ttype:STRETCHY},
  339. {input:"]",       tag:"mo",output:"]",      rtag:"mi",atval:"1",ttype:STRETCHY},
  340. {input:"\\rbrack",tag:"mo",output:"]",      rtag:"mi",atval:"1",ttype:STRETCHY},
  341. {input:"\\}",     tag:"mo",output:"}",      rtag:"mi",atval:"1",ttype:STRETCHY},
  342. {input:"\\rbrace",tag:"mo",output:"}",      rtag:"mi",atval:"1",ttype:STRETCHY},
  343. {input:"\\rangle",tag:"mo",output:"\u232A", rtag:"mi",atval:"1",ttype:STRETCHY},
  344. {input:"\\rfloor",tag:"mo",output:"\u230B", rtag:"mi",atval:"1",ttype:STRETCHY},
  345. {input:"\\rceil", tag:"mo",output:"\u2309", rtag:"mi",atval:"1",ttype:STRETCHY},
  346.  
  347. // "|", "\\|", "\\vert" and "\\Vert" modified later: lspace = rspace = 0em
  348. {input:"|",             tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
  349. {input:"\\|",           tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
  350. {input:"\\vert",        tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
  351. {input:"\\Vert",        tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
  352. {input:"\\mid",         tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
  353. {input:"\\parallel",    tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
  354. {input:"/",             tag:"mo", output:"/",   atval:"1.01", ttype:STRETCHY},
  355. {input:"\\backslash",   tag:"mo", output:"\u2216", atval:"1", ttype:STRETCHY},
  356. {input:"\\setminus",    tag:"mo", output:"\\",     ttype:CONST},
  357.  
  358. //miscellaneous symbols
  359. {input:"\\!",     tag:"mspace", atname:"width", atval:"-0.167em", ttype:SPACE},
  360. {input:"\\,",     tag:"mspace", atname:"width", atval:"0.167em", ttype:SPACE},
  361. {input:"\\>",     tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE},
  362. {input:"\\:",     tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE},
  363. {input:"\\;",     tag:"mspace", atname:"width", atval:"0.278em", ttype:SPACE},
  364. {input:"~",       tag:"mspace", atname:"width", atval:"0.333em", ttype:SPACE},
  365. {input:"\\quad",  tag:"mspace", atname:"width", atval:"1em", ttype:SPACE},
  366. {input:"\\qquad", tag:"mspace", atname:"width", atval:"2em", ttype:SPACE},
  367. //{input:"{}",            tag:"mo", output:"\u200B", ttype:CONST}, // zero-width
  368. {input:"\\prime",       tag:"mo", output:"\u2032", ttype:CONST},
  369. {input:"'",             tag:"mo", output:"\u02B9", ttype:CONST},
  370. {input:"''",            tag:"mo", output:"\u02BA", ttype:CONST},
  371. {input:"'''",           tag:"mo", output:"\u2034", ttype:CONST},
  372. {input:"''''",          tag:"mo", output:"\u2057", ttype:CONST},
  373. {input:"\\ldots",       tag:"mo", output:"\u2026", ttype:CONST},
  374. {input:"\\cdots",       tag:"mo", output:"\u22EF", ttype:CONST},
  375. {input:"\\vdots",       tag:"mo", output:"\u22EE", ttype:CONST},
  376. {input:"\\ddots",       tag:"mo", output:"\u22F1", ttype:CONST},
  377. {input:"\\forall",      tag:"mo", output:"\u2200", ttype:CONST},
  378. {input:"\\exists",      tag:"mo", output:"\u2203", ttype:CONST},
  379. {input:"\\Re",          tag:"mo", output:"\u211C", ttype:CONST},
  380. {input:"\\Im",          tag:"mo", output:"\u2111", ttype:CONST},
  381. {input:"\\aleph",       tag:"mo", output:"\u2135", ttype:CONST},
  382. {input:"\\hbar",        tag:"mo", output:"\u210F", ttype:CONST},
  383. {input:"\\ell",         tag:"mo", output:"\u2113", ttype:CONST},
  384. {input:"\\wp",          tag:"mo", output:"\u2118", ttype:CONST},
  385. {input:"\\emptyset",    tag:"mo", output:"\u2205", ttype:CONST},
  386. {input:"\\infty",       tag:"mo", output:"\u221E", ttype:CONST},
  387. {input:"\\surd",        tag:"mo", output:"\\sqrt{}", ttype:DEFINITION},
  388. {input:"\\partial",     tag:"mo", output:"\u2202", ttype:CONST},
  389. {input:"\\nabla",       tag:"mo", output:"\u2207", ttype:CONST},
  390. {input:"\\triangle",    tag:"mo", output:"\u25B3", ttype:CONST},
  391. {input:"\\therefore",   tag:"mo", output:"\u2234", ttype:CONST},
  392. {input:"\\angle",       tag:"mo", output:"\u2220", ttype:CONST},
  393. //{input:"\\\\ ",         tag:"mo", output:"\u00A0", ttype:CONST},
  394. {input:"\\diamond",     tag:"mo", output:"\u22C4", ttype:CONST},
  395. //{input:"\\Diamond",     tag:"mo", output:"\u25CA", ttype:CONST},
  396. {input:"\\Diamond",     tag:"mo", output:"\u25C7", ttype:CONST},
  397. {input:"\\neg",         tag:"mo", output:"\u00AC", ttype:CONST},
  398. {input:"\\lnot",        tag:"mo", output:"\u00AC", ttype:CONST},
  399. {input:"\\bot",         tag:"mo", output:"\u22A5", ttype:CONST},
  400. {input:"\\top",         tag:"mo", output:"\u22A4", ttype:CONST},
  401. {input:"\\square",      tag:"mo", output:"\u25AB", ttype:CONST},
  402. {input:"\\Box",         tag:"mo", output:"\u25A1", ttype:CONST},
  403. {input:"\\wr",          tag:"mo", output:"\u2240", ttype:CONST},
  404.  
  405. //standard functions
  406. //Note UNDEROVER *must* have tag:"mo" to work properly
  407. {input:"\\arccos", tag:"mi", output:"arccos", ttype:UNARY, func:true},
  408. {input:"\\arcsin", tag:"mi", output:"arcsin", ttype:UNARY, func:true},
  409. {input:"\\arctan", tag:"mi", output:"arctan", ttype:UNARY, func:true},
  410. {input:"\\arg",    tag:"mi", output:"arg",    ttype:UNARY, func:true},
  411. {input:"\\cos",    tag:"mi", output:"cos",    ttype:UNARY, func:true},
  412. {input:"\\cosh",   tag:"mi", output:"cosh",   ttype:UNARY, func:true},
  413. {input:"\\cot",    tag:"mi", output:"cot",    ttype:UNARY, func:true},
  414. {input:"\\coth",   tag:"mi", output:"coth",   ttype:UNARY, func:true},
  415. {input:"\\csc",    tag:"mi", output:"csc",    ttype:UNARY, func:true},
  416. {input:"\\deg",    tag:"mi", output:"deg",    ttype:UNARY, func:true},
  417. {input:"\\det",    tag:"mi", output:"det",    ttype:UNARY, func:true},
  418. {input:"\\dim",    tag:"mi", output:"dim",    ttype:UNARY, func:true}, //CONST?
  419. {input:"\\exp",    tag:"mi", output:"exp",    ttype:UNARY, func:true},
  420. {input:"\\gcd",    tag:"mi", output:"gcd",    ttype:UNARY, func:true}, //CONST?
  421. {input:"\\hom",    tag:"mi", output:"hom",    ttype:UNARY, func:true},
  422. {input:"\\inf",       tag:"mo", output:"inf",    ttype:UNDEROVER},
  423. {input:"\\ker",    tag:"mi", output:"ker",    ttype:UNARY, func:true},
  424. {input:"\\lg",     tag:"mi", output:"lg",     ttype:UNARY, func:true},
  425. {input:"\\lim",       tag:"mo", output:"lim",    ttype:UNDEROVER},
  426. {input:"\\liminf",    tag:"mo", output:"liminf", ttype:UNDEROVER},
  427. {input:"\\limsup",    tag:"mo", output:"limsup", ttype:UNDEROVER},
  428. {input:"\\ln",     tag:"mi", output:"ln",     ttype:UNARY, func:true},
  429. {input:"\\log",    tag:"mi", output:"log",    ttype:UNARY, func:true},
  430. {input:"\\max",       tag:"mo", output:"max",    ttype:UNDEROVER},
  431. {input:"\\min",       tag:"mo", output:"min",    ttype:UNDEROVER},
  432. {input:"\\Pr",     tag:"mi", output:"Pr",     ttype:UNARY, func:true},
  433. {input:"\\sec",    tag:"mi", output:"sec",    ttype:UNARY, func:true},
  434. {input:"\\sin",    tag:"mi", output:"sin",    ttype:UNARY, func:true},
  435. {input:"\\sinh",   tag:"mi", output:"sinh",   ttype:UNARY, func:true},
  436. {input:"\\sup",       tag:"mo", output:"sup",    ttype:UNDEROVER},
  437. {input:"\\tan",    tag:"mi", output:"tan",    ttype:UNARY, func:true},
  438. {input:"\\tanh",   tag:"mi", output:"tanh",   ttype:UNARY, func:true},
  439.  
  440. //arrows
  441. {input:"\\gets",                tag:"mo", output:"\u2190", ttype:CONST},
  442. {input:"\\leftarrow",           tag:"mo", output:"\u2190", ttype:CONST},
  443. {input:"\\to",                  tag:"mo", output:"\u2192", ttype:CONST},
  444. {input:"\\rightarrow",          tag:"mo", output:"\u2192", ttype:CONST},
  445. {input:"\\leftrightarrow",      tag:"mo", output:"\u2194", ttype:CONST},
  446. {input:"\\uparrow",             tag:"mo", output:"\u2191", ttype:CONST},
  447. {input:"\\downarrow",           tag:"mo", output:"\u2193", ttype:CONST},
  448. {input:"\\updownarrow",         tag:"mo", output:"\u2195", ttype:CONST},
  449. {input:"\\Leftarrow",           tag:"mo", output:"\u21D0", ttype:CONST},
  450. {input:"\\Rightarrow",          tag:"mo", output:"\u21D2", ttype:CONST},
  451. {input:"\\Leftrightarrow",      tag:"mo", output:"\u21D4", ttype:CONST},
  452. {input:"\\iff", tag:"mo", output:"~\\Longleftrightarrow~", ttype:DEFINITION},
  453. {input:"\\Uparrow",             tag:"mo", output:"\u21D1", ttype:CONST},
  454. {input:"\\Downarrow",           tag:"mo", output:"\u21D3", ttype:CONST},
  455. {input:"\\Updownarrow",         tag:"mo", output:"\u21D5", ttype:CONST},
  456. {input:"\\mapsto",              tag:"mo", output:"\u21A6", ttype:CONST},
  457. {input:"\\longleftarrow",       tag:"mo", output:"\u2190", ttype:LONG},
  458. {input:"\\longrightarrow",      tag:"mo", output:"\u2192", ttype:LONG},
  459. {input:"\\longleftrightarrow",  tag:"mo", output:"\u2194", ttype:LONG},
  460. {input:"\\Longleftarrow",       tag:"mo", output:"\u21D0", ttype:LONG},
  461. {input:"\\Longrightarrow",      tag:"mo", output:"\u21D2", ttype:LONG},
  462. {input:"\\Longleftrightarrow",  tag:"mo", output:"\u21D4", ttype:LONG},
  463. {input:"\\longmapsto",          tag:"mo", output:"\u21A6", ttype:CONST},
  464.                                                         // disaster if LONG
  465.  
  466. //commands with argument
  467. AMsqrt, AMroot, AMfrac, AMover, AMsub, AMsup, AMtext, AMmbox, AMatop, AMchoose,
  468. //AMdiv, AMquote,
  469.  
  470. //diacritical marks
  471. {input:"\\acute",       tag:"mover",  output:"\u00B4", ttype:UNARY, acc:true},
  472. //{input:"\\acute",       tag:"mover",  output:"\u0317", ttype:UNARY, acc:true},
  473. //{input:"\\acute",       tag:"mover",  output:"\u0301", ttype:UNARY, acc:true},
  474. //{input:"\\grave",       tag:"mover",  output:"\u0300", ttype:UNARY, acc:true},
  475. //{input:"\\grave",       tag:"mover",  output:"\u0316", ttype:UNARY, acc:true},
  476. {input:"\\grave",       tag:"mover",  output:"\u0060", ttype:UNARY, acc:true},
  477. {input:"\\breve",       tag:"mover",  output:"\u02D8", ttype:UNARY, acc:true},
  478. {input:"\\check",       tag:"mover",  output:"\u02C7", ttype:UNARY, acc:true},
  479. {input:"\\dot",         tag:"mover",  output:".",      ttype:UNARY, acc:true},
  480. {input:"\\ddot",        tag:"mover",  output:"..",     ttype:UNARY, acc:true},
  481. //{input:"\\ddot",        tag:"mover",  output:"\u00A8", ttype:UNARY, acc:true},
  482. {input:"\\mathring",    tag:"mover",  output:"\u00B0", ttype:UNARY, acc:true},
  483. {input:"\\vec",         tag:"mover",  output:"\u20D7", ttype:UNARY, acc:true},
  484. {input:"\\overrightarrow",tag:"mover",output:"\u20D7", ttype:UNARY, acc:true},
  485. {input:"\\overleftarrow",tag:"mover", output:"\u20D6", ttype:UNARY, acc:true},
  486. {input:"\\hat",         tag:"mover",  output:"\u005E", ttype:UNARY, acc:true},
  487. {input:"\\widehat",     tag:"mover",  output:"\u0302", ttype:UNARY, acc:true},
  488. {input:"\\tilde",       tag:"mover",  output:"~",      ttype:UNARY, acc:true},
  489. //{input:"\\tilde",       tag:"mover",  output:"\u0303", ttype:UNARY, acc:true},
  490. {input:"\\widetilde",   tag:"mover",  output:"\u02DC", ttype:UNARY, acc:true},
  491. {input:"\\bar",         tag:"mover",  output:"\u203E", ttype:UNARY, acc:true},
  492. {input:"\\overbrace",   tag:"mover",  output:"\u23B4", ttype:UNARY, acc:true},
  493. {input:"\\overline",    tag:"mover",  output:"\u00AF", ttype:UNARY, acc:true},
  494. {input:"\\underbrace",  tag:"munder", output:"\u23B5", ttype:UNARY, acc:true},
  495. {input:"\\underline",   tag:"munder", output:"\u00AF", ttype:UNARY, acc:true},
  496. //{input:"underline",   tag:"munder", output:"\u0332", ttype:UNARY, acc:true},
  497.  
  498. //typestyles and fonts
  499. {input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true", ttype:UNARY},
  500. {input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false", ttype:UNARY},
  501. {input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1", ttype:UNARY},
  502. {input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2", ttype:UNARY},
  503. {input:"\\textrm", tag:"mstyle", output:"\\mathrm", ttype: DEFINITION},
  504. {input:"\\mathbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY},
  505. {input:"\\textbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY},
  506. {input:"\\mathit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY},
  507. {input:"\\textit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY},
  508. {input:"\\mathtt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY},
  509. {input:"\\texttt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY},
  510. {input:"\\mathsf", tag:"mstyle", atname:"mathvariant", atval:"sans-serif", ttype:UNARY},
  511. {input:"\\mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", ttype:UNARY, codes:AMbbb},
  512. {input:"\\mathcal",tag:"mstyle", atname:"mathvariant", atval:"script", ttype:UNARY, codes:AMcal},
  513. {input:"\\mathfrak",tag:"mstyle",atname:"mathvariant", atval:"fraktur",ttype:UNARY, codes:AMfrk}
  514. ];
  515.  
  516. function compareNames(s1,s2) {
  517.   if (s1.input > s2.input) return 1
  518.   else return -1;
  519. }
  520.  
  521. var AMnames = []; //list of input symbols
  522.  
  523. function AMinitSymbols() {
  524.   AMsymbols.sort(compareNames);
  525.   for (i=0; i<AMsymbols.length; i++) AMnames[i] = AMsymbols[i].input;
  526. }
  527.  
  528. var AMmathml = "http://www.w3.org/1998/Math/MathML";
  529.  
  530. function AMcreateElementMathML(t) {
  531.   if (isIE) return document.createElement("m:"+t);
  532.   else return document.createElementNS(AMmathml,t);
  533. }
  534.  
  535. function AMcreateMmlNode(t,frag) {
  536. //  var node = AMcreateElementMathML(name);
  537.   if (isIE) var node = document.createElement("m:"+t);
  538.   else var node = document.createElementNS(AMmathml,t);
  539.   node.appendChild(frag);
  540.   return node;
  541. }
  542.  
  543. function newcommand(oldstr,newstr) {
  544.   AMsymbols = AMsymbols.concat([{input:oldstr, tag:"mo", output:newstr,
  545.                                  ttype:DEFINITION}]);
  546. }
  547.  
  548. function AMremoveCharsAndBlanks(str,n) {
  549. //remove n characters and any following blanks
  550.   var st;
  551.   st = str.slice(n);
  552.   for (var i=0; i<st.length && st.charCodeAt(i)<=32; i=i+1);
  553.   return st.slice(i);
  554. }
  555.  
  556. function AMposition(arr, str, n) {
  557. // return position >=n where str appears or would be inserted
  558. // assumes arr is sorted
  559.   if (n==0) {
  560.     var h,m;
  561.     n = -1;
  562.     h = arr.length;
  563.     while (n+1<h) {
  564.       m = (n+h) >> 1;
  565.       if (arr[m]<str) n = m; else h = m;
  566.     }
  567.     return h;
  568.   } else
  569.     for (var i=n; i<arr.length && arr[i]<str; i++);
  570.   return i; // i=arr.length || arr[i]>=str
  571. }
  572.  
  573. function AMgetSymbol(str) {
  574. //return maximal initial substring of str that appears in names
  575. //return null if there is none
  576.   var k = 0; //new pos
  577.   var j = 0; //old pos
  578.   var mk; //match pos
  579.   var st;
  580.   var tagst;
  581.   var match = "";
  582.   var more = true;
  583.   for (var i=1; i<=str.length && more; i++) {
  584.     st = str.slice(0,i); //initial substring of length i
  585.     j = k;
  586.     k = AMposition(AMnames, st, j);
  587.     if (k<AMnames.length && str.slice(0,AMnames[k].length)==AMnames[k]){
  588.       match = AMnames[k];
  589.       mk = k;
  590.       i = match.length;
  591.     }
  592.     more = k<AMnames.length && str.slice(0,AMnames[k].length)>=AMnames[k];
  593.   }
  594.   AMpreviousSymbol=AMcurrentSymbol;
  595.   if (match!=""){
  596.     AMcurrentSymbol=AMsymbols[mk].ttype;
  597.     return AMsymbols[mk];
  598.   }
  599.   AMcurrentSymbol=CONST;
  600.   k = 1;
  601.   st = str.slice(0,1); //take 1 character
  602.   if ("0"<=st && st<="9") tagst = "mn";
  603.   else tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi");
  604. /*
  605. // Commented out by DRW (not fully understood, but probably to do with
  606. // use of "/" as an INFIX version of "\\frac", which we don't want):
  607. //}
  608. //if (st=="-" && AMpreviousSymbol==INFIX) {
  609. //  AMcurrentSymbol = INFIX;  //trick "/" into recognizing "-" on second parse
  610. //  return {input:st, tag:tagst, output:st, ttype:UNARY, func:true};
  611. //}
  612. */
  613.   return {input:st, tag:tagst, output:st, ttype:CONST};
  614. }
  615.  
  616.  
  617. /*Parsing ASCII math expressions with the following grammar
  618. v ::= [A-Za-z] | greek letters | numbers | other constant symbols
  619. u ::= sqrt | text | bb | other unary symbols for font commands
  620. b ::= frac | root | stackrel    binary symbols
  621. l ::= { | \left                 left brackets
  622. r ::= } | \right                right brackets
  623. S ::= v | lEr | uS | bSS        Simple expression
  624. I ::= S_S | S^S | S_S^S | S     Intermediate expression
  625. E ::= IE | I/I                  Expression
  626. Each terminal symbol is translated into a corresponding mathml node.*/
  627.  
  628. var AMpreviousSymbol,AMcurrentSymbol;
  629.  
  630. function AMparseSexpr(str) { //parses str and returns [node,tailstr,(node)tag]
  631.   var symbol, node, result, result2, i, st,// rightvert = false,
  632.     newFrag = document.createDocumentFragment();
  633.   str = AMremoveCharsAndBlanks(str,0);
  634.   symbol = AMgetSymbol(str);             //either a token or a bracket or empty
  635.   if (symbol == null || symbol.ttype == RIGHTBRACKET)
  636.     return [null,str,null];
  637.   if (symbol.ttype == DEFINITION) {
  638.     str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);
  639.     symbol = AMgetSymbol(str);
  640.     if (symbol == null || symbol.ttype == RIGHTBRACKET)
  641.       return [null,str,null];
  642.   }
  643.   str = AMremoveCharsAndBlanks(str,symbol.input.length);
  644.   switch (symbol.ttype) {
  645.   case SPACE:
  646.     node = AMcreateElementMathML(symbol.tag);
  647.     node.setAttribute(symbol.atname,symbol.atval);
  648.     return [node,str,symbol.tag];
  649.   case UNDEROVER:
  650.     if (isIE) {
  651.       if (symbol.input.substr(0,4) == "\\big") {   // botch for missing symbols
  652.         str = "\\"+symbol.input.substr(4)+str;     // make \bigcup = \cup etc.
  653.         symbol = AMgetSymbol(str);
  654.         symbol.ttype = UNDEROVER;
  655.         str = AMremoveCharsAndBlanks(str,symbol.input.length);
  656.       }
  657.     }
  658.     return [AMcreateMmlNode(symbol.tag,
  659.                         document.createTextNode(symbol.output)),str,symbol.tag];
  660.   case CONST:
  661.     var output = symbol.output;
  662.     if (isIE) {
  663.       if (symbol.input == "'")
  664.         output = "\u2032";
  665.       else if (symbol.input == "''")
  666.         output = "\u2033";
  667.       else if (symbol.input == "'''")
  668.         output = "\u2033\u2032";
  669.       else if (symbol.input == "''''")
  670.         output = "\u2033\u2033";
  671.       else if (symbol.input == "\\square")
  672.         output = "\u25A1";      // same as \Box
  673.       else if (symbol.input.substr(0,5) == "\\frac") {
  674.                                                 // botch for missing fractions
  675.         var denom = symbol.input.substr(6,1);
  676.         if (denom == "5" || denom == "6") {
  677.           str = symbol.input.replace(/\\frac/,"\\frac ")+str;
  678.           return [node,str,symbol.tag];
  679.         }
  680.       }
  681.     }
  682.     node = AMcreateMmlNode(symbol.tag,document.createTextNode(output));
  683.     return [node,str,symbol.tag];
  684.   case LONG:  // added by DRW
  685.     node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
  686.     node.setAttribute("minsize","1.5");
  687.     node.setAttribute("maxsize","1.5");
  688.     node = AMcreateMmlNode("mover",node);
  689.     node.appendChild(AMcreateElementMathML("mspace"));
  690.     return [node,str,symbol.tag];
  691.   case STRETCHY:  // added by DRW
  692.     if (isIE && symbol.input == "\\backslash")
  693.         symbol.output = "\\";   // doesn't expand, but then nor does "\u2216"
  694.     node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
  695.     if (symbol.input == "|" || symbol.input == "\\vert" ||
  696.         symbol.input == "\\|" || symbol.input == "\\Vert") {
  697.           node.setAttribute("lspace","0em");
  698.           node.setAttribute("rspace","0em");
  699.     }
  700.     node.setAttribute("maxsize",symbol.atval);  // don't allow to stretch here
  701.     if (symbol.rtag != null)
  702.       return [node,str,symbol.rtag];
  703.     else
  704.       return [node,str,symbol.tag];
  705.   case BIG:  // added by DRW
  706.     var atval = symbol.atval;
  707.     if (isIE)
  708.       atval = symbol.ieval;
  709.     symbol = AMgetSymbol(str);
  710.     if (symbol == null)
  711.         return [null,str,null];
  712.     str = AMremoveCharsAndBlanks(str,symbol.input.length);
  713.     node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
  714.     if (isIE) {         // to get brackets to expand
  715.       var space = AMcreateElementMathML("mspace");
  716.       space.setAttribute("height",atval+"ex");
  717.       node = AMcreateMmlNode("mrow",node);
  718.       node.appendChild(space);
  719.     } else {            // ignored in IE
  720.       node.setAttribute("minsize",atval);
  721.       node.setAttribute("maxsize",atval);
  722.     }
  723.     return [node,str,symbol.tag];
  724.   case LEFTBRACKET:   //read (expr+)
  725.     if (symbol.input == "\\left") { // left what?
  726.       symbol = AMgetSymbol(str);
  727.       if (symbol != null) {
  728.         if (symbol.input == ".")
  729.           symbol.invisible = true;
  730.         str = AMremoveCharsAndBlanks(str,symbol.input.length);
  731.       }
  732.     }
  733.     result = AMparseExpr(str,true,false);
  734.     if (symbol==null ||
  735.         (typeof symbol.invisible == "boolean" && symbol.invisible))
  736.       node = AMcreateMmlNode("mrow",result[0]);
  737.     else {
  738.       node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
  739.       node = AMcreateMmlNode("mrow",node);
  740.       node.appendChild(result[0]);
  741.     }
  742.     return [node,result[1],result[2]];
  743.   case MATRIX:   //read (expr+)
  744.     if (symbol.input == "\\begin{array}") {
  745.       var mask = "";
  746.       symbol = AMgetSymbol(str);
  747.       str = AMremoveCharsAndBlanks(str,0);
  748.       if (symbol == null)
  749.         mask = "l";
  750.       else {
  751.         str = AMremoveCharsAndBlanks(str,symbol.input.length);
  752.         if (symbol.input != "{")
  753.           mask = "l";
  754.         else do {
  755.           symbol = AMgetSymbol(str);
  756.           if (symbol != null) {
  757.             str = AMremoveCharsAndBlanks(str,symbol.input.length);
  758.             if (symbol.input != "}")
  759.               mask = mask+symbol.input;
  760.           }
  761.         } while (symbol != null && symbol.input != "" && symbol.input != "}");
  762.       }
  763.       result = AMparseExpr("{"+str,true,true);
  764. //    if (result[0]==null) return [AMcreateMmlNode("mo",
  765. //                         document.createTextNode(symbol.input)),str];
  766.       node = AMcreateMmlNode("mtable",result[0]);
  767.       mask = mask.replace(/l/g,"left ");
  768.       mask = mask.replace(/r/g,"right ");
  769.       mask = mask.replace(/c/g,"center ");
  770.       node.setAttribute("columnalign",mask);
  771.       node.setAttribute("displaystyle","false");
  772.       if (isIE)
  773.         return [node,result[1],null];
  774. // trying to get a *little* bit of space around the array
  775. // (IE already includes it)
  776.       var lspace = AMcreateElementMathML("mspace");
  777.       lspace.setAttribute("width","0.167em");
  778.       var rspace = AMcreateElementMathML("mspace");
  779.       rspace.setAttribute("width","0.167em");
  780.       var node1 = AMcreateMmlNode("mrow",lspace);
  781.       node1.appendChild(node);
  782.       node1.appendChild(rspace);
  783.       return [node1,result[1],null];
  784.     } else {    // eqnarray
  785.       result = AMparseExpr("{"+str,true,true);
  786.       node = AMcreateMmlNode("mtable",result[0]);
  787.       if (isIE)
  788.         node.setAttribute("columnspacing","0.25em"); // best in practice?
  789.       else
  790.         node.setAttribute("columnspacing","0.167em"); // correct (but ignored?)
  791.       node.setAttribute("columnalign","right center left");
  792.       node.setAttribute("displaystyle","true");
  793.       node = AMcreateMmlNode("mrow",node);
  794.       return [node,result[1],null];
  795.     }
  796.   case TEXT:
  797.       if (str.charAt(0)=="{") i=str.indexOf("}");
  798.       else i = 0;
  799.       if (i==-1)
  800.                  i = str.length;
  801.       st = str.slice(1,i);
  802.       if (st.charAt(0) == " ") {
  803.         node = AMcreateElementMathML("mspace");
  804.         node.setAttribute("width","0.33em");    // was 1ex
  805.         newFrag.appendChild(node);
  806.       }
  807.       newFrag.appendChild(
  808.         AMcreateMmlNode(symbol.tag,document.createTextNode(st)));
  809.       if (st.charAt(st.length-1) == " ") {
  810.         node = AMcreateElementMathML("mspace");
  811.         node.setAttribute("width","0.33em");    // was 1ex
  812.         newFrag.appendChild(node);
  813.       }
  814.       str = AMremoveCharsAndBlanks(str,i+1);
  815.       return [AMcreateMmlNode("mrow",newFrag),str,null];
  816.   case UNARY:
  817.       result = AMparseSexpr(str);
  818.       if (result[0]==null) return [AMcreateMmlNode(symbol.tag,
  819.                              document.createTextNode(symbol.output)),str];
  820.       if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
  821.         st = str.charAt(0);
  822. //      if (st=="^" || st=="_" || st=="/" || st=="|" || st==",") {
  823.         if (st=="^" || st=="_" || st==",") {
  824.           return [AMcreateMmlNode(symbol.tag,
  825.                     document.createTextNode(symbol.output)),str,symbol.tag];
  826.         } else {
  827.           node = AMcreateMmlNode("mrow",
  828.            AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
  829.           if (isIE) {
  830.             var space = AMcreateElementMathML("mspace");
  831.             space.setAttribute("width","0.167em");
  832.             node.appendChild(space);
  833.           }
  834.           node.appendChild(result[0]);
  835.           return [node,result[1],symbol.tag];
  836.         }
  837.       }
  838.       if (symbol.input == "\\sqrt") {           // sqrt
  839.         if (isIE) {     // set minsize, for \surd
  840.           var space = AMcreateElementMathML("mspace");
  841.           space.setAttribute("height","1.2ex");
  842.           space.setAttribute("width","0em");    // probably no effect
  843.           node = AMcreateMmlNode(symbol.tag,result[0])
  844. //        node.setAttribute("minsize","1");     // ignored
  845. //        node = AMcreateMmlNode("mrow",node);  // hopefully unnecessary
  846.           node.appendChild(space);
  847.           return [node,result[1],symbol.tag];
  848.         } else
  849.           return [AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];
  850.       } else if (typeof symbol.acc == "boolean" && symbol.acc) {   // accent
  851.         node = AMcreateMmlNode(symbol.tag,result[0]);
  852.         var output = symbol.output;
  853.         if (isIE) {
  854.                 if (symbol.input == "\\hat")
  855.                         output = "\u0302";
  856.                 else if (symbol.input == "\\widehat")
  857.                         output = "\u005E";
  858.                 else if (symbol.input == "\\bar")
  859.                         output = "\u00AF";
  860.                 else if (symbol.input == "\\grave")
  861.                         output = "\u0300";
  862.                 else if (symbol.input == "\\tilde")
  863.                         output = "\u0303";
  864.         }
  865.         var node1 = AMcreateMmlNode("mo",document.createTextNode(output));
  866.         if (symbol.input == "\\vec" || symbol.input == "\\check")
  867.                                                 // don't allow to stretch
  868.             node1.setAttribute("maxsize","1.2");
  869.                  // why doesn't "1" work?  \vec nearly disappears in firefox
  870.         if (isIE && symbol.input == "\\bar")
  871.             node1.setAttribute("maxsize","0.5");
  872.         if (symbol.input == "\\underbrace" || symbol.input == "\\underline")
  873.           node1.setAttribute("accentunder","true");
  874.         else
  875.           node1.setAttribute("accent","true");
  876.         node.appendChild(node1);
  877.         if (symbol.input == "\\overbrace" || symbol.input == "\\underbrace")
  878.           node.ttype = UNDEROVER;
  879.         return [node,result[1],symbol.tag];
  880.       } else {                        // font change or displaystyle command
  881.         if (!isIE && typeof symbol.codes != "undefined") {
  882.           for (i=0; i<result[0].childNodes.length; i++)
  883.             if (result[0].childNodes[i].nodeName=="mi" || result[0].nodeName=="mi") {
  884.               st = (result[0].nodeName=="mi"?result[0].firstChild.nodeValue:
  885.                               result[0].childNodes[i].firstChild.nodeValue);
  886.               var newst = [];
  887.               for (var j=0; j<st.length; j++)
  888.                 if (st.charCodeAt(j)>64 && st.charCodeAt(j)<91) newst = newst +
  889.                   String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);
  890.                 else newst = newst + st.charAt(j);
  891.               if (result[0].nodeName=="mi")
  892.                 result[0]=AMcreateElementMathML("mo").
  893.                           appendChild(document.createTextNode(newst));
  894.               else result[0].replaceChild(AMcreateElementMathML("mo").
  895.           appendChild(document.createTextNode(newst)),result[0].childNodes[i]);
  896.             }
  897.         }
  898.         node = AMcreateMmlNode(symbol.tag,result[0]);
  899.         node.setAttribute(symbol.atname,symbol.atval);
  900.         if (symbol.input == "\\scriptstyle" ||
  901.             symbol.input == "\\scriptscriptstyle")
  902.                 node.setAttribute("displaystyle","false");
  903.         return [node,result[1],symbol.tag];
  904.       }
  905.   case BINARY:
  906.     result = AMparseSexpr(str);
  907.     if (result[0]==null) return [AMcreateMmlNode("mo",
  908.                            document.createTextNode(symbol.input)),str,null];
  909.     result2 = AMparseSexpr(result[1]);
  910.     if (result2[0]==null) return [AMcreateMmlNode("mo",
  911.                            document.createTextNode(symbol.input)),str,null];
  912.     if (symbol.input=="\\root" || symbol.input=="\\stackrel")
  913.       newFrag.appendChild(result2[0]);
  914.     newFrag.appendChild(result[0]);
  915.     if (symbol.input=="\\frac") newFrag.appendChild(result2[0]);
  916.     return [AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];
  917.   case INFIX:
  918.     str = AMremoveCharsAndBlanks(str,symbol.input.length);
  919.     return [AMcreateMmlNode("mo",document.createTextNode(symbol.output)),
  920.         str,symbol.tag];
  921.   default:
  922.     return [AMcreateMmlNode(symbol.tag,        //its a constant
  923.         document.createTextNode(symbol.output)),str,symbol.tag];
  924.   }
  925. }
  926.  
  927. function AMparseIexpr(str) {
  928.   var symbol, sym1, sym2, node, result, tag, underover;
  929.   str = AMremoveCharsAndBlanks(str,0);
  930.   sym1 = AMgetSymbol(str);
  931.   result = AMparseSexpr(str);
  932.   node = result[0];
  933.   str = result[1];
  934.   tag = result[2];
  935.   symbol = AMgetSymbol(str);
  936.   if (symbol.ttype == INFIX) {
  937.     str = AMremoveCharsAndBlanks(str,symbol.input.length);
  938.     result = AMparseSexpr(str);
  939.     if (result[0] == null) // show box in place of missing argument
  940.       result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1"));
  941.     str = result[1];
  942.     tag = result[2];
  943.     if (symbol.input == "_" || symbol.input == "^") {
  944.       sym2 = AMgetSymbol(str);
  945.       tag = null;       // no space between x^2 and a following sin, cos, etc.
  946. // This is for \underbrace and \overbrace
  947.       underover = ((sym1.ttype == UNDEROVER) || (node.ttype == UNDEROVER));
  948. //    underover = (sym1.ttype == UNDEROVER);
  949.       if (symbol.input == "_" && sym2.input == "^") {
  950.         str = AMremoveCharsAndBlanks(str,sym2.input.length);
  951.         var res2 = AMparseSexpr(str);
  952.         str = res2[1];
  953.         tag = res2[2];  // leave space between x_1^2 and a following sin etc.
  954.         node = AMcreateMmlNode((underover?"munderover":"msubsup"),node);
  955.         node.appendChild(result[0]);
  956.         node.appendChild(res2[0]);
  957.       } else if (symbol.input == "_") {
  958.         node = AMcreateMmlNode((underover?"munder":"msub"),node);
  959.         node.appendChild(result[0]);
  960.       } else {
  961.         node = AMcreateMmlNode((underover?"mover":"msup"),node);
  962.         node.appendChild(result[0]);
  963.       }
  964.       node = AMcreateMmlNode("mrow",node); // so sum does not stretch
  965.     } else {
  966.       node = AMcreateMmlNode(symbol.tag,node);
  967.       if (symbol.input == "\\atop" || symbol.input == "\\choose")
  968.         node.setAttribute("linethickness","0ex");
  969.       node.appendChild(result[0]);
  970.       if (symbol.input == "\\choose")
  971.         node = AMcreateMmlNode("mfenced",node);
  972.     }
  973.   }
  974.   return [node,str,tag];
  975. }
  976.  
  977. function AMparseExpr(str,rightbracket,matrix) {
  978.   var symbol, node, result, i, tag,
  979.   newFrag = document.createDocumentFragment();
  980.   do {
  981.     str = AMremoveCharsAndBlanks(str,0);
  982.     result = AMparseIexpr(str);
  983.     node = result[0];
  984.     str = result[1];
  985.     tag = result[2];
  986.     symbol = AMgetSymbol(str);
  987.     if (node!=undefined) {
  988.       if ((tag == "mn" || tag == "mi") && symbol!=null &&
  989.         typeof symbol.func == "boolean" && symbol.func) {
  990.                         // Add space before \sin in 2\sin x or x\sin x
  991.           var space = AMcreateElementMathML("mspace");
  992.           space.setAttribute("width","0.167em");
  993.           node = AMcreateMmlNode("mrow",node);
  994.           node.appendChild(space);
  995.       }
  996.       newFrag.appendChild(node);
  997.     }
  998.   } while ((symbol.ttype != RIGHTBRACKET)
  999.         && symbol!=null && symbol.output!="");
  1000.   tag = null;
  1001.   if (symbol.ttype == RIGHTBRACKET) {
  1002.     if (symbol.input == "\\right") { // right what?
  1003.       str = AMremoveCharsAndBlanks(str,symbol.input.length);
  1004.       symbol = AMgetSymbol(str);
  1005.       if (symbol != null && symbol.input == ".")
  1006.         symbol.invisible = true;
  1007.       if (symbol != null)
  1008.         tag = symbol.rtag;
  1009.     }
  1010.     if (symbol!=null)
  1011.       str = AMremoveCharsAndBlanks(str,symbol.input.length); // ready to return
  1012.     var len = newFrag.childNodes.length;
  1013.     if (matrix &&
  1014.       len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 &&
  1015.       newFrag.childNodes[len-2].nodeName == "mo" &&
  1016.       newFrag.childNodes[len-2].firstChild.nodeValue == "&") { //matrix
  1017.         var pos = []; // positions of ampersands
  1018.         var m = newFrag.childNodes.length;
  1019.         for (i=0; matrix && i<m; i=i+2) {
  1020.           pos[i] = [];
  1021.           node = newFrag.childNodes[i];
  1022.           for (var j=0; j<node.childNodes.length; j++)
  1023.             if (node.childNodes[j].firstChild.nodeValue=="&")
  1024.               pos[i][pos[i].length]=j;
  1025.         }
  1026.         var row, frag, n, k, table = document.createDocumentFragment();
  1027.         for (i=0; i<m; i=i+2) {
  1028.           row = document.createDocumentFragment();
  1029.           frag = document.createDocumentFragment();
  1030.           node = newFrag.firstChild; // <mrow> -&-&...&-&- </mrow>
  1031.           n = node.childNodes.length;
  1032.           k = 0;
  1033.           for (j=0; j<n; j++) {
  1034.             if (typeof pos[i][k] != "undefined" && j==pos[i][k]){
  1035.               node.removeChild(node.firstChild); //remove &
  1036.               row.appendChild(AMcreateMmlNode("mtd",frag));
  1037.               k++;
  1038.             } else frag.appendChild(node.firstChild);
  1039.           }
  1040.           row.appendChild(AMcreateMmlNode("mtd",frag));
  1041.           if (newFrag.childNodes.length>2) {
  1042.             newFrag.removeChild(newFrag.firstChild); //remove <mrow> </mrow>
  1043.             newFrag.removeChild(newFrag.firstChild); //remove <mo>&</mo>
  1044.           }
  1045.           table.appendChild(AMcreateMmlNode("mtr",row));
  1046.         }
  1047.         return [table,str];
  1048.     }
  1049.     if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
  1050.       node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
  1051.       newFrag.appendChild(node);
  1052.     }
  1053.   }
  1054.   return [newFrag,str,tag];
  1055. }
  1056.  
  1057. function AMparseMath(str) {
  1058.   var result, node = AMcreateElementMathML("mstyle");
  1059.   if (mathcolor != "") node.setAttribute("mathcolor",mathcolor);
  1060.   if (mathfontfamily != "") node.setAttribute("fontfamily",mathfontfamily);
  1061.   node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);
  1062.   node = AMcreateMmlNode("math",node);
  1063.   if (showasciiformulaonhover)                      //fixed by djhsu so newline
  1064.     node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko
  1065.   if (mathfontfamily != "" && (isIE || mathfontfamily != "serif")) {
  1066.     var fnode = AMcreateElementXHTML("font");
  1067.     fnode.setAttribute("face",mathfontfamily);
  1068.     fnode.appendChild(node);
  1069.     return fnode;
  1070.   }
  1071.   return node;
  1072. }
  1073.  
  1074. function AMstrarr2docFrag(arr, linebreaks) {
  1075.   var newFrag=document.createDocumentFragment();
  1076.   var expr = false;
  1077.   for (var i=0; i<arr.length; i++) {
  1078.     if (expr) newFrag.appendChild(AMparseMath(arr[i]));
  1079.     else {
  1080.       var arri = (linebreaks ? arr[i].split("\n\n") : [arr[i]]);
  1081.       newFrag.appendChild(AMcreateElementXHTML("span").
  1082.       appendChild(document.createTextNode(arri[0])));
  1083.       for (var j=1; j<arri.length; j++) {
  1084.         newFrag.appendChild(AMcreateElementXHTML("p"));
  1085.         newFrag.appendChild(AMcreateElementXHTML("span").
  1086.         appendChild(document.createTextNode(arri[j])));
  1087.       }
  1088.     }
  1089.     expr = !expr;
  1090.   }
  1091.   return newFrag;
  1092. }
  1093.  
  1094. function AMprocessNodeR(n, linebreaks) {
  1095.   var mtch, str, arr, frg, i;
  1096.   if (n.childNodes.length == 0) {
  1097.    if ((n.nodeType!=8 || linebreaks) &&
  1098.     n.parentNode.nodeName!="form" && n.parentNode.nodeName!="FORM" &&
  1099.     n.parentNode.nodeName!="textarea" && n.parentNode.nodeName!="TEXTAREA" &&
  1100.     n.parentNode.nodeName!="pre" && n.parentNode.nodeName!="PRE") {
  1101.     str = n.nodeValue;
  1102.     if (!(str == null)) {
  1103.       str = str.replace(/\r\n\r\n/g,"\n\n");
  1104.       str = str.replace(/\x20+/g," ");
  1105.       str = str.replace(/\s*\r\n/g," ");
  1106. // DELIMITERS:
  1107.       mtch = (str.indexOf("\$")==-1 ? false : true);
  1108.       str = str.replace(/([^\\])\$/g,"$1 \$");
  1109.       str = str.replace(/^\$/," \$");   // in case \$ at start of string
  1110.       arr = str.split(" \$");
  1111.       for (i=0; i<arr.length; i++)
  1112.         arr[i]=arr[i].replace(/\\\$/g,"\$");
  1113.       if (arr.length>1 || mtch) {
  1114.         if (checkForMathML) {
  1115.           checkForMathML = false;
  1116.           var nd = AMisMathMLavailable();
  1117.           AMnoMathML = nd != null;
  1118.           if (AMnoMathML && notifyIfNoMathML)
  1119.             if (alertIfNoMathML)
  1120.               alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\n\
  1121.                or Firefox/Mozilla/Netscape");
  1122.             else AMbody.insertBefore(nd,AMbody.childNodes[0]);
  1123.         }
  1124.         if (!AMnoMathML) {
  1125.           frg = AMstrarr2docFrag(arr,n.nodeType==8);
  1126.           var len = frg.childNodes.length;
  1127.           n.parentNode.replaceChild(frg,n);
  1128.           return len-1;
  1129.         } else return 0;
  1130.       }
  1131.     }
  1132.    } else return 0;
  1133.   } else if (n.nodeName!="math") {
  1134.     for (i=0; i<n.childNodes.length; i++)
  1135.       i += AMprocessNodeR(n.childNodes[i], linebreaks);
  1136.   }
  1137.   return 0;
  1138. }
  1139.  
  1140. function AMprocessNode(n, linebreaks, spanclassAM) {
  1141.   var frag,st;
  1142.   if (spanclassAM!=null) {
  1143.     frag = document.getElementsByTagName("span")
  1144.     for (var i=0;i<frag.length;i++)
  1145.       if (frag[i].className == "AM")
  1146.         AMprocessNodeR(frag[i],linebreaks);
  1147.   } else {
  1148.     try {
  1149.       st = n.innerHTML;
  1150.     } catch(err) {}
  1151. // DELIMITERS:
  1152.     if (st==null || st.indexOf("\$")!=-1)
  1153.       AMprocessNodeR(n,linebreaks);
  1154.   }
  1155.   if (isIE) { //needed to match size and font of formula to surrounding text
  1156.     frag = document.getElementsByTagName('math');
  1157.     for (var i=0;i<frag.length;i++) frag[i].update()
  1158.   }
  1159. }
  1160.  
  1161. var AMbody;
  1162. var AMnoMathML = false, AMtranslated = false;
  1163.  
  1164. function translate(spanclassAM) {
  1165.   if (!AMtranslated) { // run this only once
  1166.     AMtranslated = true;
  1167.     AMinitSymbols();
  1168.     AMbody = document.getElementsByTagName("body")[0];
  1169.     AMprocessNode(AMbody, false, spanclassAM);
  1170.   }
  1171. }
  1172.  
  1173. if (isIE) { // avoid adding MathPlayer info explicitly to each webpage
  1174.   document.write("<object id=\"mathplayer\"\
  1175.  classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");
  1176.   document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");
  1177. }
  1178.  
  1179. // GO1.1 Generic onload by Brothercake
  1180. // http://www.brothercake.com/
  1181. //onload function (replaces the onload="translate()" in the <body> tag)
  1182. function generic()
  1183. {
  1184.   translate();
  1185. };
  1186. //setup onload function
  1187. if(typeof window.addEventListener != 'undefined')
  1188. {
  1189.   //.. gecko, safari, konqueror and standard
  1190.   window.addEventListener('load', generic, false);
  1191. }
  1192. else if(typeof document.addEventListener != 'undefined')
  1193. {
  1194.   //.. opera 7
  1195.   document.addEventListener('load', generic, false);
  1196. }
  1197. else if(typeof window.attachEvent != 'undefined')
  1198. {
  1199.   //.. win/ie
  1200.   window.attachEvent('onload', generic);
  1201. }
  1202. //** remove this condition to degrade older browsers
  1203. else
  1204. {
  1205.   //.. mac/ie5 and anything else that gets this far
  1206.   //if there's an existing onload function
  1207.   if(typeof window.onload == 'function')
  1208.   {
  1209.     //store it
  1210.     var existing = onload;
  1211.     //add new onload handler
  1212.     window.onload = function()
  1213.     {
  1214.       //call existing onload function
  1215.       existing();
  1216.       //call generic onload function
  1217.       generic();
  1218.     };
  1219.   }
  1220.   else
  1221.   {
  1222.     //setup onload function
  1223.     window.onload = generic;
  1224.   }
  1225. }
  1226.