--- loncom/html/adm/LC_math_editor/src/enode.js 2014/09/24 18:14:39 1.1
+++ loncom/html/adm/LC_math_editor/src/enode.js 2017/01/27 20:31:09 1.3
@@ -18,19 +18,26 @@ through which recipients can access the
*/
+"use strict";
+
/**
- * Parsed tree node. ENode.toMathML(hcolors) contains the code for the transformation into MathML.
+ * Parsed tree node. ENode.toMathML() contains the code for the transformation into MathML.
* @constructor
- * @param {number} type - ENode.UNKNOWN | NAME | NUMBER | OPERATOR | FUNCTION | VECTOR
+ * @param {number} type - ENode.UNKNOWN | NAME | NUMBER | OPERATOR | FUNCTION | VECTOR | INTERVAL | SET | SUBSCRIPT
* @param {Operator} op - The operator
* @param {string} value - Node value as a string, null for type VECTOR
- * @param {Array.} children - The children nodes, only for types OPERATOR, FUNCTION, VECTOR, SUBSCRIPT
+ * @param {Array.} children - The children nodes, only for types OPERATOR, FUNCTION, VECTOR, INTERVAL, SET, SUBSCRIPT
+ * @param {number} [interval_type] - ENode.NOT_AN_INTERVAL | OPEN_OPEN | OPEN_CLOSED | CLOSED_OPEN | CLOSED_CLOSED
*/
-function ENode(type, op, value, children) {
+function ENode(type, op, value, children, interval_type) {
this.type = type;
this.op = op;
this.value = value;
this.children = children;
+ if (typeof interval_type == "undefined")
+ this.interval_type = ENode.NOT_AN_INTERVAL;
+ else
+ this.interval_type = interval_type;
}
ENode.UNKNOWN = 0;
@@ -39,11 +46,19 @@ ENode.NUMBER = 2;
ENode.OPERATOR = 3;
ENode.FUNCTION = 4;
ENode.VECTOR = 5;
-ENode.SUBSCRIPT = 6;
+ENode.INTERVAL = 6;
+ENode.SET = 7;
+ENode.SUBSCRIPT = 8;
ENode.COLORS = ["#E01010", "#0010FF", "#009000", "#FF00FF", "#00B0B0", "#F09000",
"#800080", "#F080A0", "#6090F0", "#902000", "#70A050", "#A07060",
"#5000FF", "#E06050", "#008080", "#808000"];
+ENode.NOT_AN_INTERVAL = 0;
+ENode.OPEN_OPEN = 1;
+ENode.OPEN_CLOSED = 2;
+ENode.CLOSED_OPEN = 3;
+ENode.CLOSED_CLOSED = 4;
+
/**
* Returns the node as a string, for debug
* @returns {string}
@@ -69,6 +84,12 @@ ENode.prototype.toString = function() {
case ENode.VECTOR:
s += 'VECTOR';
break;
+ case ENode.INTERVAL:
+ s += 'INTERVAL';
+ break;
+ case ENode.SET:
+ s += 'SET';
+ break;
case ENode.SUBSCRIPT:
s += 'SUBSCRIPT';
break;
@@ -86,6 +107,9 @@ ENode.prototype.toString = function() {
}
s += ']';
}
+ if (this.interval_type) {
+ s += " " + this.interval_type;
+ }
s+= ')';
return s;
};
@@ -96,26 +120,40 @@ ENode.prototype.toString = function() {
* @param {Object.} hcolors - hash identifier->color
* @returns {string}
*/
-ENode.prototype.getColorForIdentifier = function(name, hcolors) {
- var res = hcolors[name];
+ENode.prototype.getColorForIdentifier = function(name, context) {
+ var res = context.hcolors[name];
if (!res) {
- res = ENode.COLORS[Object.keys(hcolors).length % ENode.COLORS.length];
- hcolors[name] = res;
+ var colors;
+ if (context.colors)
+ colors = context.colors;
+ else
+ colors = ENode.COLORS;
+ res = colors[Object.keys(context.hcolors).length % colors.length];
+ context.hcolors[name] = res;
}
return res;
}
/**
* Transforms this ENode into a MathML HTML DOM element.
- * @param {Object} [context] - display context (not needed for the root element)
+ * @param {Array.} [colors] - optional override for ENode.COLORS
+ * @returns {Element}
+ */
+ENode.prototype.toMathML = function(colors) {
+ var context = { hcolors: {}, depth: 0 , colors: colors};
+ return(this._toMathML(context));
+}
+
+/**
+ * Transforms this ENode into a MathML HTML DOM element (internal function).
+ * @param {Object} context - display context
* @param {Object.} context.hcolors - hash identifier->color
* @param {number} context.depth - Depth in parenthesis, used for coloring
+ * @param {Array.} context.colors - optional override for ENode.COLORS
* @returns {Element}
*/
-ENode.prototype.toMathML = function(context) {
- var c0, c1, c2, c3, c4, i, j, el, par, mrow, mo, mtable, mfrac, msub, msup;
- if (typeof context == "undefined")
- context = { hcolors: {}, depth: 0 };
+ENode.prototype._toMathML = function(context) {
+ var c0, c1, c2, c3, c4, i, j, el, par, mrow, mo, mtable, mfrac, msub, msup, mrow2;
if (this.children != null && this.children.length > 0)
c0 = this.children[0];
else
@@ -153,7 +191,9 @@ ENode.prototype.toMathML = function(cont
} else {
el = this.mi(this.value)
}
- el.setAttribute("mathcolor", this.getColorForIdentifier(this.value, context.hcolors));
+ el.setAttribute("mathcolor", this.getColorForIdentifier(this.value, context));
+ if (this.value.indexOf('$') === 0)
+ el.setAttribute("fontfamily", "monospace");
return(el);
case ENode.NUMBER:
@@ -175,8 +215,8 @@ ENode.prototype.toMathML = function(cont
case ENode.OPERATOR:
if (this.value == "/") {
mfrac = document.createElement('mfrac');
- mfrac.appendChild(c0.toMathML(context));
- mfrac.appendChild(c1.toMathML(context));
+ mfrac.appendChild(c0._toMathML(context));
+ mfrac.appendChild(c1._toMathML(context));
el = mfrac;
} else if (this.value == "^") {
if (c0.type == ENode.FUNCTION) {
@@ -193,14 +233,14 @@ ENode.prototype.toMathML = function(cont
if (par)
el.appendChild(this.addP(c0, context));
else
- el.appendChild(c0.toMathML(context));
- el.appendChild(c1.toMathML(context));
+ el.appendChild(c0._toMathML(context));
+ el.appendChild(c1._toMathML(context));
} else if (this.value == "*") {
mrow = document.createElement('mrow');
if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
mrow.appendChild(this.addP(c0, context));
else
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
// should the x operator be visible ? We need to check if there is a number to the left of c1
var firstinc1 = c1;
while (firstinc1.type == ENode.OPERATOR) {
@@ -213,23 +253,27 @@ ENode.prototype.toMathML = function(cont
mrow.appendChild(this.mo("*"));
else if (firstinc1.type == ENode.NUMBER)
mrow.appendChild(this.mo("\u22C5"));
+ else if (context.units)
+ mrow.appendChild(this.mo("\u22C5"));
+ else
+ mrow.appendChild(this.mo("\u2062")); // invisible multiplication
if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (this.value == "-") {
mrow = document.createElement('mrow');
if (this.children.length == 1) {
mrow.appendChild(this.mo("-"));
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
} else {
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
mrow.appendChild(this.mo("-"));
if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
}
el = mrow;
} else if (this.value == "!") {
@@ -238,13 +282,13 @@ ENode.prototype.toMathML = function(cont
if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
mrow.appendChild(this.addP(c0, context));
else
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
mrow.appendChild(mo);
el = mrow;
} else if (this.value == "+") {
mrow = document.createElement('mrow');
mo = this.mo(this.value);
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
mrow.appendChild(mo);
// should we add parenthesis ? We need to check if there is a '-' to the left of c1
par = false;
@@ -262,42 +306,50 @@ ENode.prototype.toMathML = function(cont
if (par)
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (this.value == ".") {
mrow = document.createElement('mrow');
if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
mrow.appendChild(this.addP(c0, context));
else
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
mrow.appendChild(this.mo("\u22C5"));
if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (this.value == "`") {
mrow = document.createElement('mrow');
if (c0.type == ENode.OPERATOR && (c0.value == "+" || c0.value == "-"))
mrow.appendChild(this.addP(c0, context));
else
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
// the units should not be in italics
+ // unit multiplication should not be displayed with an invisible operator
var mstyle = document.createElement("mstyle");
mstyle.setAttribute("fontstyle", "normal");
+ var units_context = {};
+ for (var prop in context) {
+ if (context.hasOwnProperty(prop)) {
+ units_context[prop] = context[prop];
+ }
+ }
+ units_context.units = true;
if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
- mstyle.appendChild(this.addP(c1, context));
+ mstyle.appendChild(this.addP(c1, units_context));
else
- mstyle.appendChild(c1.toMathML(context));
+ mstyle.appendChild(c1._toMathML(units_context));
mrow.appendChild(mstyle);
el = mrow;
} else {
// relational operators
mrow = document.createElement('mrow');
mo = this.mo(this.value);
- mrow.appendChild(c0.toMathML(context));
+ mrow.appendChild(c0._toMathML(context));
mrow.appendChild(mo);
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
}
return(el);
@@ -306,24 +358,24 @@ ENode.prototype.toMathML = function(cont
// c0 contains the function name
if (c0.value == "sqrt" && c1 != null) {
el = document.createElement('msqrt');
- el.appendChild(c1.toMathML(context));
+ el.appendChild(c1._toMathML(context));
} else if (c0.value == "abs" && c1 != null) {
mrow = document.createElement('mrow');
mrow.appendChild(this.mo("|"));
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
mrow.appendChild(this.mo("|"));
el = mrow;
} else if (c0.value == "exp" && c1 != null) {
el = document.createElement('msup');
el.appendChild(this.mi("e"));
- el.appendChild(c1.toMathML(context));
+ el.appendChild(c1._toMathML(context));
} else if (c0.value == "factorial") {
mrow = document.createElement('mrow');
mo = this.mo("!");
if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
mrow.appendChild(mo);
el = mrow;
} else if (c0.value == "diff" && this.children != null && this.children.length == 3) {
@@ -338,27 +390,27 @@ ENode.prototype.toMathML = function(cont
if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (c0.value == "diff" && this.children != null && this.children.length == 4) {
mrow = document.createElement('mrow');
mfrac = document.createElement('mfrac');
msup = document.createElement('msup');
msup.appendChild(this.mi("d"));
- msup.appendChild(c3.toMathML(context));
+ msup.appendChild(c3._toMathML(context));
mfrac.appendChild(msup);
var f2 = document.createElement('mrow');
f2.appendChild(this.mi("d"));
msup = document.createElement('msup');
- msup.appendChild(c2.toMathML(context));
- msup.appendChild(c3.toMathML(context));
+ msup.appendChild(c2._toMathML(context));
+ msup.appendChild(c3._toMathML(context));
f2.appendChild(msup);
mfrac.appendChild(f2);
mrow.appendChild(mfrac);
if (c1.type == ENode.OPERATOR && (c1.value == "+" || c1.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (c0.value == "integrate" && this.children != null && this.children.length == 3) {
mrow = document.createElement('mrow');
@@ -368,9 +420,9 @@ ENode.prototype.toMathML = function(cont
if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
mrow.appendChild(this.mi("d"));
- mrow.appendChild(c2.toMathML(context));
+ mrow.appendChild(c2._toMathML(context));
el = mrow;
} else if (c0.value == "integrate" && this.children != null && this.children.length == 5) {
mrow = document.createElement('mrow');
@@ -378,15 +430,15 @@ ENode.prototype.toMathML = function(cont
var mo = this.mo("\u222B");
mo.setAttribute("stretchy", "true"); // doesn't work with MathJax
msubsup.appendChild(mo);
- msubsup.appendChild(c3.toMathML(context));
- msubsup.appendChild(c4.toMathML(context));
+ msubsup.appendChild(c3._toMathML(context));
+ msubsup.appendChild(c4._toMathML(context));
mrow.appendChild(msubsup);
if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
mrow.appendChild(this.mi("d"));
- mrow.appendChild(c2.toMathML(context));
+ mrow.appendChild(c2._toMathML(context));
el = mrow;
} else if (c0.value == "sum" && this.children != null && this.children.length == 5) {
mrow = document.createElement('mrow');
@@ -394,17 +446,17 @@ ENode.prototype.toMathML = function(cont
var mo = this.mo("\u2211");
mo.setAttribute("stretchy", "true"); // doesn't work with MathJax
munderover.appendChild(mo);
- var mrow2 = document.createElement('mrow');
- mrow2.appendChild(c2.toMathML(context));
+ mrow2 = document.createElement('mrow');
+ mrow2.appendChild(c2._toMathML(context));
mrow2.appendChild(this.mo("="));
- mrow2.appendChild(c3.toMathML(context));
+ mrow2.appendChild(c3._toMathML(context));
munderover.appendChild(mrow2);
- munderover.appendChild(c4.toMathML(context));
+ munderover.appendChild(c4._toMathML(context));
mrow.appendChild(munderover);
if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (c0.value == "product" && this.children != null && this.children.length == 5) {
mrow = document.createElement('mrow');
@@ -412,17 +464,17 @@ ENode.prototype.toMathML = function(cont
var mo = this.mo("\u220F");
mo.setAttribute("stretchy", "true"); // doesn't work with MathJax
munderover.appendChild(mo);
- var mrow2 = document.createElement('mrow');
- mrow2.appendChild(c2.toMathML(context));
+ mrow2 = document.createElement('mrow');
+ mrow2.appendChild(c2._toMathML(context));
mrow2.appendChild(this.mo("="));
- mrow2.appendChild(c3.toMathML(context));
+ mrow2.appendChild(c3._toMathML(context));
munderover.appendChild(mrow2);
- munderover.appendChild(c4.toMathML(context));
+ munderover.appendChild(c4._toMathML(context));
mrow.appendChild(munderover);
if (c2.type == ENode.OPERATOR && (c2.value == "+" || c2.value == "-"))
mrow.appendChild(this.addP(c1, context));
else
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (c0.value == "limit") {
mrow = document.createElement('mrow');
@@ -432,9 +484,9 @@ ENode.prototype.toMathML = function(cont
var munder = document.createElement('munder');
munder.appendChild(this.mo("lim"));
var mrowunder = document.createElement('mrow');
- mrowunder.appendChild(c2.toMathML(context));
+ mrowunder.appendChild(c2._toMathML(context));
mrowunder.appendChild(this.mo("\u2192"));
- mrowunder.appendChild(c3.toMathML(context));
+ mrowunder.appendChild(c3._toMathML(context));
if (c4 != null) {
if (c4.value == "plus")
mrowunder.appendChild(this.mo("+"));
@@ -444,7 +496,7 @@ ENode.prototype.toMathML = function(cont
munder.appendChild(mrowunder);
mrow.appendChild(munder);
}
- mrow.appendChild(c1.toMathML(context));
+ mrow.appendChild(c1._toMathML(context));
el = mrow;
} else if (c0.value == "binomial") {
// displayed like a vector
@@ -453,7 +505,7 @@ ENode.prototype.toMathML = function(cont
mtable = document.createElement('mtable');
for (i=1; i 0)
+ mrow2.appendChild(this.mo(Definitions.ARG_SEPARATOR));
+ mrow2.appendChild(this.children[i]._toMathML(context));
+ }
+ mrow.appendChild(mrow2);
+ mrow.appendChild(this.mo("}"));
+ return(mrow);
+
case ENode.SUBSCRIPT:
msub = document.createElement('msub');
- msub.appendChild(c0.toMathML(context));
+ msub.appendChild(c0._toMathML(context));
if (this.children.length > 2) {
mrow = document.createElement('mrow');
for (i=1; i