Project

General

Profile

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
}
(2-2/21)