Annotation of loncom/html/adm/LC_math_editor/src/enode.js, revision 1.2
1.1 damieng 1: /*
2:
3: Copyright (C) 2014 Michigan State University Board of Trustees
4:
5: The JavaScript code in this page is free software: you can
6: redistribute it and/or modify it under the terms of the GNU
7: General Public License (GNU GPL) as published by the Free Software
8: Foundation, either version 3 of the License, or (at your option)
9: any later version. The code is distributed WITHOUT ANY WARRANTY;
10: without even the implied warranty of MERCHANTABILITY or FITNESS
11: FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
12:
13: As additional permission under GNU GPL version 3 section 7, you
14: may distribute non-source (e.g., minimized or compacted) forms of
15: that code without the copy of the GNU GPL normally required by
16: section 4, provided you include this license notice and a URL
17: through which recipients can access the Corresponding Source.
18:
19: */
20:
1.2 ! damieng 21: "use strict";
! 22:
1.1 damieng 23: /**
1.2 ! damieng 24: * Parsed tree node. ENode.toMathML() contains the code for the transformation into MathML.
1.1 damieng 25: * @constructor
1.2 ! damieng 26: * @param {number} type - ENode.UNKNOWN | NAME | NUMBER | OPERATOR | FUNCTION | VECTOR | INTERVAL | SET | SUBSCRIPT
1.1 damieng 27: * @param {Operator} op - The operator
28: * @param {string} value - Node value as a string, null for type VECTOR
1.2 ! damieng 29: * @param {Array.<ENode>} children - The children nodes, only for types OPERATOR, FUNCTION, VECTOR, INTERVAL, SET, SUBSCRIPT
! 30: * @param {number} [interval_type] - ENode.NOT_AN_INTERVAL | OPEN_OPEN | OPEN_CLOSED | CLOSED_OPEN | CLOSED_CLOSED
1.1 damieng 31: */
1.2 ! damieng 32: function ENode(type, op, value, children, interval_type) {
1.1 damieng 33: this.type = type;
34: this.op = op;
35: this.value = value;
36: this.children = children;
1.2 ! damieng 37: if (typeof interval_type == "undefined")
! 38: this.interval_type = ENode.NOT_AN_INTERVAL;
! 39: else
! 40: this.interval_type = interval_type;
1.1 damieng 41: }
42:
43: ENode.UNKNOWN = 0;
44: ENode.NAME = 1;
45: ENode.NUMBER = 2;
46: ENode.OPERATOR = 3;
47: ENode.FUNCTION = 4;
48: ENode.VECTOR = 5;
1.2 ! damieng 49: ENode.INTERVAL = 6;
! 50: ENode.SET = 7;
! 51: ENode.SUBSCRIPT = 8;
1.1 damieng 52: ENode.COLORS = ["#E01010", "#0010FF", "#009000", "#FF00FF", "#00B0B0", "#F09000",
53: "#800080", "#F080A0", "#6090F0", "#902000", "#70A050", "#A07060",
54: "#5000FF", "#E06050", "#008080", "#808000"];
55:
1.2 ! damieng 56: ENode.NOT_AN_INTERVAL = 0;
! 57: ENode.OPEN_OPEN = 1;
! 58: ENode.OPEN_CLOSED = 2;
! 59: ENode.CLOSED_OPEN = 3;
! 60: ENode.CLOSED_CLOSED = 4;
! 61:
1.1 damieng 62: /**
63: * Returns the node as a string, for debug
64: * @returns {string}
65: */
66: ENode.prototype.toString = function() {
67: var s = '(';
68: switch (this.type) {
69: case ENode.UNKNOWN:
70: s += 'UNKNOWN';
71: break;
72: case ENode.NAME:
73: s += 'NAME';
74: break;
75: case ENode.NUMBER:
76: s += 'NUMBER';
77: break;
78: case ENode.OPERATOR:
79: s += 'OPERATOR';
80: break;
81: case ENode.FUNCTION:
82: s += 'FUNCTION';
83: break;
84: case ENode.VECTOR:
85: s += 'VECTOR';
86: break;
1.2 ! damieng 87: case ENode.INTERVAL:
! 88: s += 'INTERVAL';
! 89: break;
! 90: case ENode.SET:
! 91: s += 'SET';
! 92: break;
1.1 damieng 93: case ENode.SUBSCRIPT:
94: s += 'SUBSCRIPT';
95: break;
96: }
97: if (this.op)
98: s += " '" + this.op.id + "'";
99: if (this.value)
100: s += " '" + this.value + "'";
101: if (this.children) {
102: s += ' [';
103: for (var i = 0; i < this.children.length; i++) {
104: s += this.children[i].toString();
105: if (i != this.children.length - 1)
106: s += ',';
107: }
108: s += ']';
109: }
1.2 ! damieng 110: if (this.interval_type) {
! 111: s += " " + this.interval_type;
! 112: }
1.1 damieng 113: s+= ')';
114: return s;
115: };
116:
117: /**
118: * Returns the color for an identifier.
119: * @param {string} name
120: * @param {Object.<string, string>} hcolors - hash identifier->color
121: * @returns {string}
122: */
1.2 ! damieng 123: ENode.prototype.getColorForIdentifier = function(name, context) {
! 124: var res = context.hcolors[name];
1.1 damieng 125: if (!res) {
1.2 ! damieng 126: var colors;
! 127: if (context.colors)
! 128: colors = context.colors;
! 129: else
! 130: colors = ENode.COLORS;
! 131: res = colors[Object.keys(context.hcolors).length % colors.length];
! 132: context.hcolors[name] = res;
1.1 damieng 133: }
134: return res;
135: }
136:
137: /**
138: * Transforms this ENode into a MathML HTML DOM element.
1.2 ! damieng 139: * @param {Array.<string>} [colors] - optional override for ENode.COLORS
! 140: * @returns {Element}
! 141: */
! 142: ENode.prototype.toMathML = function(colors) {
! 143: var context = { hcolors: {}, depth: 0 , colors: colors};
! 144: return(this._toMathML(context));
! 145: }
! 146:
! 147: /**
! 148: * Transforms this ENode into a MathML HTML DOM element (internal function).
! 149: * @param {Object} context - display context
1.1 damieng 150: * @param {Object.<string, string>} context.hcolors - hash identifier->color
151: * @param {number} context.depth - Depth in parenthesis, used for coloring
1.2 ! damieng 152: * @param {Array.<string>} context.colors - optional override for ENode.COLORS
1.1 damieng 153: * @returns {Element}
154: */
1.2 ! damieng 155: ENode.prototype._toMathML = function(context) {
! 156: var c0, c1, c2, c3, c4, i, j, el, par, mrow, mo, mtable, mfrac, msub, msup, mrow2;
1.1 damieng 157: if (this.children != null && this.children.length > 0)
158: c0 = this.children[0];
159: else
160: c0 = null;
161: if (this.children != null && this.children.length > 1)
162: c1 = this.children[1];
163: else
164: c1 = null;
165: if (this.children != null && this.children.length > 2)
166: c2 = this.children[2];
167: else
168: c2 = null;
169: if (this.children != null && this.children.length > 3)
170: c3 = this.children[3];
171: else
172: c3 = null;
173: if (this.children != null && this.children.length > 4)
174: c4 = this.children[4];
175: else
176: c4 = null;
177:
178: switch (this.type) {
179: case ENode.UNKNOWN:
180: el = document.createElement('mtext');
181: el.appendChild(document.createTextNode("???"));
182: return(el);
183:
184: case ENode.NAME:
185: if (this.value.search(/^[a-zA-Z]+[0-9]+$/) >= 0) {
186: var ind = this.value.search(/[0-9]/);
187: msub = document.createElement('msub');
188: msub.appendChild(this.mi(this.value.substring(0,ind)));
189: msub.appendChild(this.mn(this.value.substring(ind)));
190: el = msub;
191: } else {
192: el = this.mi(this.value)
193: }
1.2 ! damieng 194: el.setAttribute("mathcolor", this.getColorForIdentifier(this.value, context));
! 195: if (this.value.indexOf('$') === 0)
! 196: el.setAttribute("fontfamily", "monospace");
1.1 damieng 197: return(el);
198:
199: case ENode.NUMBER:
200: if (this.value.indexOf('e') != -1 || this.value.indexOf('E') != -1) {
201: var index = this.value.indexOf('e');
202: if (index == -1)
203: index = this.value.indexOf('E');
204: mrow = document.createElement('mrow');
205: mrow.appendChild(this.mn(this.value.substring(0, index)));
206: mrow.appendChild(this.mo("\u22C5"));
207: msup = document.createElement('msup');
208: msup.appendChild(this.mn(10));
209: msup.appendChild(this.mn(this.value.substring(index + 1)));
210: mrow.appendChild(msup);
211: return(mrow);
212: }
213: return(this.mn(this.value));
214:
215: case ENode.OPERATOR:
216: if (this.value == "/") {
217: mfrac = document.createElement('mfrac');
1.2 ! damieng 218: mfrac.appendChild(c0._toMathML(context));
! 219: mfrac.appendChild(c1._toMathML(context));
1.1 damieng 220: el = mfrac;
221: } else if (this.value == "^") {
222: if (c0.type == ENode.FUNCTION) {
223: if (c0.value == "sqrt" || c0.value == "abs" || c0.value == "matrix" ||
224: c0.value == "diff")
225: par = false;
226: else
227: par = true;
228: } else if (c0.type == ENode.OPERATOR) {
229: par = true;
230: } else
231: par = false;
232: el = document.createElement('msup');
233: if (par)
234: el.appendChild(this.addP(c0, context));
235: else
1.2 ! damieng 236: el.appendChild(c0._toMathML(context));
! 237: el.appendChild(c1._toMathML(context));
1.1 damieng 238: } else if (this.value == "*") {
239: mrow = document.createElement('mrow');
240: if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
241: mrow.appendChild(this.addP(c0, context));
242: else
1.2 ! damieng 243: mrow.appendChild(c0._toMathML(context));
1.1 damieng 244: // should the x operator be visible ? We need to check if there is a number to the left of c1
245: var firstinc1 = c1;
246: while (firstinc1.type == ENode.OPERATOR) {
247: firstinc1 = firstinc1.children[0];
248: }
249: // ... and if it's an operation between vectors/matrices, the * operator should be displayed
250: // (it is ambiguous otherwise)
251: // note: this will not work if the matrix is calculated, for instance with 2[1;2]*[3;4]
252: if (c0.type == ENode.VECTOR && c1.type == ENode.VECTOR)
253: mrow.appendChild(this.mo("*"));
254: else if (firstinc1.type == ENode.NUMBER)
255: mrow.appendChild(this.mo("\u22C5"));
1.2 ! damieng 256: else if (context.units)
! 257: mrow.appendChild(this.mo("\u22C5"));
! 258: else
! 259: mrow.appendChild(this.mo("\u2062")); // invisible multiplication
1.1 damieng 260: if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
261: mrow.appendChild(this.addP(c1, context));
262: else
1.2 ! damieng 263: mrow.appendChild(c1._toMathML(context));
1.1 damieng 264: el = mrow;
265: } else if (this.value == "-") {
266: mrow = document.createElement('mrow');
267: if (this.children.length == 1) {
268: mrow.appendChild(this.mo("-"));
1.2 ! damieng 269: mrow.appendChild(c0._toMathML(context));
1.1 damieng 270: } else {
1.2 ! damieng 271: mrow.appendChild(c0._toMathML(context));
1.1 damieng 272: mrow.appendChild(this.mo("-"));
273: if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
274: mrow.appendChild(this.addP(c1, context));
275: else
1.2 ! damieng 276: mrow.appendChild(c1._toMathML(context));
1.1 damieng 277: }
278: el = mrow;
279: } else if (this.value == "!") {
280: mrow = document.createElement('mrow');
281: mo = this.mo(this.value);
282: if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
283: mrow.appendChild(this.addP(c0, context));
284: else
1.2 ! damieng 285: mrow.appendChild(c0._toMathML(context));
1.1 damieng 286: mrow.appendChild(mo);
287: el = mrow;
288: } else if (this.value == "+") {
289: mrow = document.createElement('mrow');
290: mo = this.mo(this.value);
1.2 ! damieng 291: mrow.appendChild(c0._toMathML(context));
1.1 damieng 292: mrow.appendChild(mo);
293: // should we add parenthesis ? We need to check if there is a '-' to the left of c1
294: par = false;
295: var first = c1;
296: while (first.type == ENode.OPERATOR) {
297: if (first.value == "-" && first.children.length == 1) {
298: par = true;
299: break;
300: } else if (first.value == "+" || first.value == "-" || first.value == "*") {
301: first = first.children[0];
302: } else {
303: break;
304: }
305: }
306: if (par)
307: mrow.appendChild(this.addP(c1, context));
308: else
1.2 ! damieng 309: mrow.appendChild(c1._toMathML(context));
1.1 damieng 310: el = mrow;
311: } else if (this.value == ".") {
312: mrow = document.createElement('mrow');
313: if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
314: mrow.appendChild(this.addP(c0, context));
315: else
1.2 ! damieng 316: mrow.appendChild(c0._toMathML(context));
1.1 damieng 317: mrow.appendChild(this.mo("\u22C5"));
318: if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
319: mrow.appendChild(this.addP(c1, context));
320: else
1.2 ! damieng 321: mrow.appendChild(c1._toMathML(context));
1.1 damieng 322: el = mrow;
323: } else if (this.value == "`") {
324: mrow = document.createElement('mrow');
325: if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
326: mrow.appendChild(this.addP(c0, context));
327: else
1.2 ! damieng 328: mrow.appendChild(c0._toMathML(context));
1.1 damieng 329: // the units should not be in italics
1.2 ! damieng 330: // unit multiplication should not be displayed with an invisible operator
1.1 damieng 331: var mstyle = document.createElement("mstyle");
332: mstyle.setAttribute("fontstyle", "normal");
1.2 ! damieng 333: var units_context = {};
! 334: for (var prop in context) {
! 335: if (context.hasOwnProperty(prop)) {
! 336: units_context[prop] = context[prop];
! 337: }
! 338: }
! 339: units_context.units = true;
1.1 damieng 340: if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
1.2 ! damieng 341: mstyle.appendChild(this.addP(c1, units_context));
1.1 damieng 342: else
1.2 ! damieng 343: mstyle.appendChild(c1._toMathML(units_context));
1.1 damieng 344: mrow.appendChild(mstyle);
345: el = mrow;
346: } else {
347: // relational operators
348: mrow = document.createElement('mrow');
349: mo = this.mo(this.value);
1.2 ! damieng 350: mrow.appendChild(c0._toMathML(context));
1.1 damieng 351: mrow.appendChild(mo);
1.2 ! damieng 352: mrow.appendChild(c1._toMathML(context));
1.1 damieng 353: el = mrow;
354: }
355: return(el);
356:
357: case ENode.FUNCTION: /* TODO: throw exceptions if wrong nb of args ? */
358: // c0 contains the function name
359: if (c0.value == "sqrt" && c1 != null) {
360: el = document.createElement('msqrt');
1.2 ! damieng 361: el.appendChild(c1._toMathML(context));
1.1 damieng 362: } else if (c0.value == "abs" && c1 != null) {
363: mrow = document.createElement('mrow');
364: mrow.appendChild(this.mo("|"));
1.2 ! damieng 365: mrow.appendChild(c1._toMathML(context));
1.1 damieng 366: mrow.appendChild(this.mo("|"));
367: el = mrow;
368: } else if (c0.value == "exp" && c1 != null) {
369: el = document.createElement('msup');
370: el.appendChild(this.mi("e"));
1.2 ! damieng 371: el.appendChild(c1._toMathML(context));
1.1 damieng 372: } else if (c0.value == "factorial") {
373: mrow = document.createElement('mrow');
374: mo = this.mo("!");
375: if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
376: mrow.appendChild(this.addP(c1, context));
377: else
1.2 ! damieng 378: mrow.appendChild(c1._toMathML(context));
1.1 damieng 379: mrow.appendChild(mo);
380: el = mrow;
381: } else if (c0.value == "diff" && this.children != null && this.children.length == 3) {
382: mrow = document.createElement('mrow');
383: mfrac = document.createElement('mfrac');
384: mfrac.appendChild(this.mi("d"));
385: var f2 = document.createElement('mrow');
386: f2.appendChild(this.mi("d"));
387: f2.appendChild(this.mi(c2.value));
388: mfrac.appendChild(f2);
389: mrow.appendChild(mfrac);
390: if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
391: mrow.appendChild(this.addP(c1, context));
392: else
1.2 ! damieng 393: mrow.appendChild(c1._toMathML(context));
1.1 damieng 394: el = mrow;
395: } else if (c0.value == "diff" && this.children != null && this.children.length == 4) {
396: mrow = document.createElement('mrow');
397: mfrac = document.createElement('mfrac');
398: msup = document.createElement('msup');
399: msup.appendChild(this.mi("d"));
1.2 ! damieng 400: msup.appendChild(c3._toMathML(context));
1.1 damieng 401: mfrac.appendChild(msup);
402: var f2 = document.createElement('mrow');
403: f2.appendChild(this.mi("d"));
404: msup = document.createElement('msup');
1.2 ! damieng 405: msup.appendChild(c2._toMathML(context));
! 406: msup.appendChild(c3._toMathML(context));
1.1 damieng 407: f2.appendChild(msup);
408: mfrac.appendChild(f2);
409: mrow.appendChild(mfrac);
410: if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
411: mrow.appendChild(this.addP(c1, context));
412: else
1.2 ! damieng 413: mrow.appendChild(c1._toMathML(context));
1.1 damieng 414: el = mrow;
415: } else if (c0.value == "integrate" && this.children != null && this.children.length == 3) {
416: mrow = document.createElement('mrow');
417: var mo = this.mo("\u222B");
418: mo.setAttribute("stretchy", "true"); // doesn't work with MathJax
419: mrow.appendChild(mo);
420: if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
421: mrow.appendChild(this.addP(c1, context));
422: else
1.2 ! damieng 423: mrow.appendChild(c1._toMathML(context));
1.1 damieng 424: mrow.appendChild(this.mi("d"));
1.2 ! damieng 425: mrow.appendChild(c2._toMathML(context));
1.1 damieng 426: el = mrow;
427: } else if (c0.value == "integrate" && this.children != null && this.children.length == 5) {
428: mrow = document.createElement('mrow');
429: var msubsup = document.createElement('msubsup');
430: var mo = this.mo("\u222B");
431: mo.setAttribute("stretchy", "true"); // doesn't work with MathJax
432: msubsup.appendChild(mo);
1.2 ! damieng 433: msubsup.appendChild(c3._toMathML(context));
! 434: msubsup.appendChild(c4._toMathML(context));
1.1 damieng 435: mrow.appendChild(msubsup);
436: if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
437: mrow.appendChild(this.addP(c1, context));
438: else
1.2 ! damieng 439: mrow.appendChild(c1._toMathML(context));
1.1 damieng 440: mrow.appendChild(this.mi("d"));
1.2 ! damieng 441: mrow.appendChild(c2._toMathML(context));
1.1 damieng 442: el = mrow;
443: } else if (c0.value == "sum" && this.children != null && this.children.length == 5) {
444: mrow = document.createElement('mrow');
445: var munderover = document.createElement('munderover');
446: var mo = this.mo("\u2211");
447: mo.setAttribute("stretchy", "true"); // doesn't work with MathJax
448: munderover.appendChild(mo);
1.2 ! damieng 449: mrow2 = document.createElement('mrow');
! 450: mrow2.appendChild(c2._toMathML(context));
1.1 damieng 451: mrow2.appendChild(this.mo("="));
1.2 ! damieng 452: mrow2.appendChild(c3._toMathML(context));
1.1 damieng 453: munderover.appendChild(mrow2);
1.2 ! damieng 454: munderover.appendChild(c4._toMathML(context));
1.1 damieng 455: mrow.appendChild(munderover);
456: if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
457: mrow.appendChild(this.addP(c1, context));
458: else
1.2 ! damieng 459: mrow.appendChild(c1._toMathML(context));
1.1 damieng 460: el = mrow;
461: } else if (c0.value == "product" && this.children != null && this.children.length == 5) {
462: mrow = document.createElement('mrow');
463: var munderover = document.createElement('munderover');
464: var mo = this.mo("\u220F");
465: mo.setAttribute("stretchy", "true"); // doesn't work with MathJax
466: munderover.appendChild(mo);
1.2 ! damieng 467: mrow2 = document.createElement('mrow');
! 468: mrow2.appendChild(c2._toMathML(context));
1.1 damieng 469: mrow2.appendChild(this.mo("="));
1.2 ! damieng 470: mrow2.appendChild(c3._toMathML(context));
1.1 damieng 471: munderover.appendChild(mrow2);
1.2 ! damieng 472: munderover.appendChild(c4._toMathML(context));
1.1 damieng 473: mrow.appendChild(munderover);
474: if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
475: mrow.appendChild(this.addP(c1, context));
476: else
1.2 ! damieng 477: mrow.appendChild(c1._toMathML(context));
1.1 damieng 478: el = mrow;
479: } else if (c0.value == "limit") {
480: mrow = document.createElement('mrow');
481: if (this.children.length < 4) {
482: mrow.appendChild(this.mo("lim"));
483: } else {
484: var munder = document.createElement('munder');
485: munder.appendChild(this.mo("lim"));
486: var mrowunder = document.createElement('mrow');
1.2 ! damieng 487: mrowunder.appendChild(c2._toMathML(context));
1.1 damieng 488: mrowunder.appendChild(this.mo("\u2192"));
1.2 ! damieng 489: mrowunder.appendChild(c3._toMathML(context));
1.1 damieng 490: if (c4 != null) {
491: if (c4.value == "plus")
492: mrowunder.appendChild(this.mo("+"));
493: else if (c4.value == "minus")
494: mrowunder.appendChild(this.mo("-"));
495: }
496: munder.appendChild(mrowunder);
497: mrow.appendChild(munder);
498: }
1.2 ! damieng 499: mrow.appendChild(c1._toMathML(context));
1.1 damieng 500: el = mrow;
501: } else if (c0.value == "binomial") {
502: // displayed like a vector
503: mrow = document.createElement('mrow');
504: mrow.appendChild(this.mo("("));
505: mtable = document.createElement('mtable');
506: for (i=1; i<this.children.length; i++) {
507: var mtr = document.createElement('mtr');
1.2 ! damieng 508: mtr.appendChild(this.children[i]._toMathML(context));
1.1 damieng 509: mtable.appendChild(mtr);
510: }
511: mrow.appendChild(mtable);
512: mrow.appendChild(this.mo(")"));
513: el = mrow;
514: } else if (c0.value == "matrix") {
515: for (i=1; i<this.children.length; i++) {
516: // check that all children are vectors
517: if (this.children[i].type !== ENode.VECTOR) {
518: el = document.createElement('mtext');
519: el.appendChild(document.createTextNode("???")); // could throw here
520: return(el);
521: }
522: }
523: mrow = document.createElement('mrow');
524: mrow.appendChild(this.mo("("));
525: mtable = document.createElement('mtable');
526: for (i=1; i<this.children.length; i++) {
527: var mtr = document.createElement('mtr');
528: for (j=0; j<this.children[i].children.length; j++) {
1.2 ! damieng 529: mtr.appendChild(this.children[i].children[j]._toMathML(context));
1.1 damieng 530: }
531: mtable.appendChild(mtr);
532: }
533: mrow.appendChild(mtable);
534: mrow.appendChild(this.mo(")"));
535: el = mrow;
1.2 ! damieng 536: } else if (c0.value == "union" && this.children.length == 3) {
! 537: for (i=1; i<this.children.length; i++) {
! 538: // check that all children are intervals or sets
! 539: if (this.children[i].type !== ENode.INTERVAL && this.children[i].type !== ENode.SET) {
! 540: el = document.createElement('mtext');
! 541: el.appendChild(document.createTextNode("???"));
! 542: return(el);
! 543: }
! 544: }
! 545: mrow = document.createElement('mrow');
! 546: mrow.appendChild(c1._toMathML(context));
! 547: mrow.appendChild(this.mo("\u222A"));
! 548: mrow.appendChild(c2._toMathML(context));
! 549: el = mrow;
! 550: } else if (c0.value == "intersection" && this.children.length == 3) {
! 551: for (i=1; i<this.children.length; i++) {
! 552: // check that all children are intervals or sets
! 553: if (this.children[i].type !== ENode.INTERVAL && this.children[i].type !== ENode.SET) {
! 554: el = document.createElement('mtext');
! 555: el.appendChild(document.createTextNode("???"));
! 556: return(el);
! 557: }
! 558: }
! 559: mrow = document.createElement('mrow');
! 560: mrow.appendChild(c1._toMathML(context));
! 561: mrow.appendChild(this.mo("\u2229"));
! 562: mrow.appendChild(c2._toMathML(context));
! 563: el = mrow;
1.1 damieng 564: } else {
565: // default display for a function
566: mrow = document.createElement('mrow');
1.2 ! damieng 567: mrow.appendChild(c0._toMathML(context));
1.1 damieng 568: mrow.appendChild(this.mo("("));
569: for (i=1; i<this.children.length; i++) {
1.2 ! damieng 570: mrow.appendChild(this.children[i]._toMathML(context));
1.1 damieng 571: if (i < this.children.length - 1)
572: mrow.appendChild(this.mo(Definitions.ARG_SEPARATOR));
573: }
574: mrow.appendChild(this.mo(")"));
575: el = mrow;
576: }
577: return(el);
578:
579: case ENode.VECTOR:
580: var is_matrix = true;
581: for (i=0; i<this.children.length; i++) {
582: if (this.children[i].type !== ENode.VECTOR)
583: is_matrix = false;
584: }
585: mrow = document.createElement('mrow');
586: mrow.appendChild(this.mo("("));
587: mtable = document.createElement('mtable');
588: for (i=0; i<this.children.length; i++) {
589: var mtr = document.createElement('mtr');
590: if (is_matrix) {
591: for (j=0; j<this.children[i].children.length; j++) {
1.2 ! damieng 592: mtr.appendChild(this.children[i].children[j]._toMathML(context));
1.1 damieng 593: }
594: } else {
1.2 ! damieng 595: mtr.appendChild(this.children[i]._toMathML(context));
1.1 damieng 596: }
597: mtable.appendChild(mtr);
598: }
599: mrow.appendChild(mtable);
600: mrow.appendChild(this.mo(")"));
601: return(mrow);
1.2 ! damieng 602:
! 603: case ENode.INTERVAL:
! 604: mrow = document.createElement('mrow');
! 605: if (this.interval_type == ENode.OPEN_OPEN || this.interval_type == ENode.OPEN_CLOSED) {
! 606: mo = this.mo("(");
! 607: } else {
! 608: mo = this.mo("[");
! 609: }
! 610: mrow.appendChild(mo);
! 611: mrow2 = document.createElement('mrow');
! 612: mrow2.appendChild(this.children[0]._toMathML(context));
! 613: mrow2.appendChild(this.mo(":"));
! 614: mrow2.appendChild(this.children[1]._toMathML(context));
! 615: mrow.appendChild(mrow2);
! 616: if (this.interval_type == ENode.OPEN_OPEN || this.interval_type == ENode.CLOSED_OPEN) {
! 617: mo = this.mo(")");
! 618: } else {
! 619: mo = this.mo("]");
! 620: }
! 621: mrow.appendChild(mo);
! 622: return(mrow);
1.1 damieng 623:
1.2 ! damieng 624: case ENode.SET:
! 625: mrow = document.createElement('mrow');
! 626: mrow.appendChild(this.mo("{"));
! 627: mrow2 = document.createElement('mrow');
! 628: for (i=0; i<this.children.length; i++) {
! 629: if (i > 0)
! 630: mrow2.appendChild(this.mo(";"));
! 631: mrow2.appendChild(this.children[i]._toMathML(context));
! 632: }
! 633: mrow.appendChild(mrow2);
! 634: mrow.appendChild(this.mo("}"));
! 635: return(mrow);
! 636:
1.1 damieng 637: case ENode.SUBSCRIPT:
638: msub = document.createElement('msub');
1.2 ! damieng 639: msub.appendChild(c0._toMathML(context));
1.1 damieng 640: if (this.children.length > 2) {
641: mrow = document.createElement('mrow');
642: for (i=1; i<this.children.length; i++) {
1.2 ! damieng 643: mrow.appendChild(this.children[i]._toMathML(context));
1.1 damieng 644: if (i < this.children.length - 1)
645: mrow.appendChild(this.mo(Definitions.ARG_SEPARATOR));
646: }
647: msub.appendChild(mrow);
648: } else {
1.2 ! damieng 649: msub.appendChild(c1._toMathML(context));
1.1 damieng 650: }
651: return(msub);
1.2 ! damieng 652:
1.1 damieng 653: }
654: };
655:
656: /**
657: * Creates a MathML mi element with the given name
658: * @param {string} name
659: * @returns {Element}
660: */
661: ENode.prototype.mi = function(name) {
662: var mi = document.createElement('mi');
663: if (ENode.symbols[name])
664: name = ENode.symbols[name];
665: mi.appendChild(document.createTextNode(name));
666: return mi;
667: };
668:
669: /**
670: * Creates a MathML mn element with the given number or string
671: * @param {string} n
672: * @returns {Element}
673: */
674: ENode.prototype.mn = function(n) {
675: var mn = document.createElement('mn');
676: mn.appendChild(document.createTextNode(n));
677: return mn;
678: };
679:
680: /**
681: * Creates a MathML mo element with the given name
682: * @param {string} name
683: * @returns {Element}
684: */
685: ENode.prototype.mo = function(name) {
686: var mo = document.createElement('mo');
687: if (ENode.symbols[name])
688: name = ENode.symbols[name];
689: mo.appendChild(document.createTextNode(name));
690: return mo;
691: };
692:
693: /**
694: * Add parenthesis and returns a MathML element
695: * @param {ENode} en
696: * @param {Object} [context] - display context (not needed for the root element)
697: * @param {Object.<string, string>} context.hcolors - hash identifier->color
698: * @param {number} context.depth - Depth in parenthesis, used for coloring
699: * @returns {Element}
700: */
701: ENode.prototype.addP = function(en, context) {
702: var mrow, mo;
703: mrow = document.createElement('mrow');
704: mo = this.mo("(");
1.2 ! damieng 705: var colors;
! 706: if (context.colors)
! 707: colors = context.colors;
! 708: else
! 709: colors = ENode.COLORS;
! 710: mo.setAttribute("mathcolor", colors[context.depth % colors.length]);
1.1 damieng 711: mrow.appendChild(mo);
712: context.depth++;
1.2 ! damieng 713: mrow.appendChild(en._toMathML(context));
1.1 damieng 714: context.depth--;
715: mo = this.mo(")");
1.2 ! damieng 716: mo.setAttribute("mathcolor", colors[context.depth % colors.length]);
1.1 damieng 717: mrow.appendChild(mo);
718: return mrow;
719: };
720:
721: ENode.symbols = {
722: /* lowercase greek */
723: "alpha": "\u03B1", "beta": "\u03B2", "gamma": "\u03B3",
724: "delta": "\u03B4", "epsilon": "\u03B5", "zeta": "\u03B6",
725: "eta": "\u03B7", "theta": "\u03B8", "iota": "\u03B9",
726: "kappa": "\u03BA", "lambda": "\u03BB", "mu": "\u03BC",
727: "nu": "\u03BD", "xi": "\u03BE", "omicron": "\u03BF",
728: "pi": "\u03C0", "rho": "\u03C1", "sigma": "\u03C3",
729: "tau": "\u03C4", "upsilon": "\u03C5", "phi": "\u03C6",
730: "chi": "\u03C7", "psi": "\u03C8", "omega": "\u03C9",
731: /* uppercase greek */
732: "Alpha": "\u0391", "Beta": "\u0392", "Gamma": "\u0393",
733: "Delta": "\u0394", "Epsilon": "\u0395", "Zeta": "\u0396",
734: "Eta": "\u0397", "Theta": "\u0398", "Iota": "\u0399",
735: "Kappa": "\u039A", "Lambda": "\u039B", "Mu": "\u039C",
736: "Nu": "\u039D", "Xi": "\u039E", "Omicron": "\u039F",
737: "Pi": "\u03A0", "Rho": "\u03A1", "Sigma": "\u03A3",
738: "Tau": "\u03A4", "Upsilon": "\u03A5", "Phi": "\u03A6",
739: "Chi": "\u03A7", "Psi": "\u03A8", "Omega": "\u03A9",
740:
741: /* operators */
742: "#": "\u2260",
743: ">=": "\u2265",
744: "<=": "\u2264",
745:
746: /* other */
747: "inf": "\u221E",
748: "minf": "-\u221E",
749: "hbar": "\u210F",
750: "G": "\uD835\uDCA2" // 1D4A2
751: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>