[LON-CAPA-cvs] cvs: loncom /html/adm/LC_math_editor build.sh test.html /html/adm/LC_math_editor/dist LC_math_editor.min.js /html/adm/LC_math_editor/src definitions.js enode.js operator.js parse_exception.js parser.js token.js tokenizer.js ui.js

damieng damieng at source.lon-capa.org
Tue Feb 24 10:20:45 EST 2015


damieng		Tue Feb 24 15:20:45 2015 EDT

  Modified files:              
    /loncom/html/adm/LC_math_editor	build.sh test.html 
    /loncom/html/adm/LC_math_editor/dist	LC_math_editor.min.js 
    /loncom/html/adm/LC_math_editor/src	definitions.js enode.js 
                                       	operator.js parse_exception.js 
                                       	parser.js token.js tokenizer.js 
                                       	ui.js 
  Log:
  updated to git version (see git for log history), and changed param separator to ,
  
-------------- next part --------------
Index: loncom/html/adm/LC_math_editor/build.sh
diff -u loncom/html/adm/LC_math_editor/build.sh:1.1 loncom/html/adm/LC_math_editor/build.sh:1.2
--- loncom/html/adm/LC_math_editor/build.sh:1.1	Wed Sep 24 18:14:31 2014
+++ loncom/html/adm/LC_math_editor/build.sh	Tue Feb 24 15:20:36 2015
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# this builds dist/LC_math_editor.min.js using google closure compiler with compressjs.
+# this builds dist/LC_math_editor.min.js using google closure compiler.
 # It must be run in the math_editor directory.
 
 cd "$(dirname "$0")"
@@ -18,12 +18,20 @@
         "Operator": Operator,
         "ParseException": ParseException,
         "Parser": Parser,
-        "initEditors": initEditors
+        "initEditors": initEditors,
+        "updateMathSpanAndDiv": updateMathSpanAndDiv
     });
 }();
 %
 
+# use the local application if Java is available
+if hash java 2>/dev/null; then
+    java -jar lib/compiler.jar --language_in=ECMASCRIPT5_STRICT --compilation_level=SIMPLE_OPTIMIZATIONS $tmp >dist/LC_math_editor.min.js
+    exit 0
+fi
+
+# otherwise use the web service with compressjs.sh
 NEWFILE="c`date +"%d%m%y"`.js"
-/bin/sh ../../../build/compressjs.sh -strict $tmp
+/bin/sh ./compressjs.sh -strict $tmp
 mv "$NEWFILE" ./dist/LC_math_editor.min.js
 rm -f $tmp
Index: loncom/html/adm/LC_math_editor/test.html
diff -u loncom/html/adm/LC_math_editor/test.html:1.1 loncom/html/adm/LC_math_editor/test.html:1.2
--- loncom/html/adm/LC_math_editor/test.html:1.1	Wed Sep 24 18:14:31 2014
+++ loncom/html/adm/LC_math_editor/test.html	Tue Feb 24 15:20:36 2015
@@ -8,6 +8,38 @@
         textarea.math { font-family: monospace; height: 3em; width: 100%; }
         span.math-error { border: solid 1px red; min-width: 1px; }
     </style>
+    <script>
+      function addField() {
+        var div = document.createElement('div');
+        div.classList.add('eqnbox');
+        var input = document.createElement('input');
+        input.classList.add('math');
+        input.setAttribute('data-implicit_operators', 'true');
+        input.setAttribute('data-unit_mode', 'true');
+        input.setAttribute('data-constants', 'c, pi, e, hbar, amu');
+        input.setAttribute('spellcheck', 'false');
+        div.appendChild(input);
+        var removeb = document.createElement('button');
+        removeb.appendChild(document.createTextNode('remove'));
+        removeb.addEventListener('click', function(e) {
+            div.parentNode.removeChild(div);
+            initEditors();
+        }, false);
+        div.appendChild(removeb);
+        var modeb = document.createElement('button');
+        modeb.appendChild(document.createTextNode('switch mode'));
+        modeb.addEventListener('click', function(e) {
+            if (input.getAttribute('data-unit_mode') == 'true')
+                input.setAttribute('data-unit_mode', 'false');
+            else
+                input.setAttribute('data-unit_mode', 'true');
+            initEditors();
+        }, false);
+        div.appendChild(modeb);
+        document.body.appendChild(div);
+        initEditors();
+      }
+    </script>
 </head>
 <body>
     <p>Strict syntax, symbolic mode:</p>
@@ -27,8 +59,16 @@
         <textarea class="math" data-implicit_operators="true" data-unit_mode="true" data-constants="c, pi, e, hbar, amu" spellcheck="false" autofocus="autofocus"></textarea>
     </div>
     <div class="eqnbox">
-        Test in a field <input class="math" data-implicit_operators="true" spellcheck="false" autofocus="autofocus"></textarea> with text around (Lax syntax, symbolic mode)
+        Test in a field <input class="math" data-implicit_operators="true" spellcheck="false" autofocus="autofocus"> with text around (Lax syntax, symbolic mode)
+    </div>
+    <div style="position: absolute; left: 500px; top: 400px; background: rgba(200, 255, 200, 0.7)">
+        inside an absolute position div (lax symbolic)<br>
+        <textarea class="math" data-implicit_operators="true" spellcheck="false" autofocus="autofocus"></textarea>
     </div>
+    <p><button onclick="addField();">click to add a field</button></p>
+    <p>static math on a line: <span class="math" data-implicit_operators="true">2x/(3y)</span></p>
+    <p>static math as a block:</p>
+    <div class="math" data-implicit_operators="true">2x/(3y)</div>
     <script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=MML_HTMLorMML"></script>
     <script src="src/definitions.js"></script>
     <script src="src/enode.js"></script>
@@ -40,7 +80,8 @@
     <script src="src/ui.js"></script>
     <script>
         window.addEventListener('load', function(e) {
-            initEditors(); // will be LCMATH.init_editors() with the minimized version
+            initEditors(); // will be LCMATH.initEditors() with the minimized version
+            updateMathSpanAndDiv(); // will be LCMATH.updateMathSpanAndDiv()
         }, false);
     </script>
 </body>
Index: loncom/html/adm/LC_math_editor/dist/LC_math_editor.min.js
diff -u loncom/html/adm/LC_math_editor/dist/LC_math_editor.min.js:1.1 loncom/html/adm/LC_math_editor/dist/LC_math_editor.min.js:1.2
--- loncom/html/adm/LC_math_editor/dist/LC_math_editor.min.js:1.1	Wed Sep 24 18:14:35 2014
+++ loncom/html/adm/LC_math_editor/dist/LC_math_editor.min.js	Tue Feb 24 15:20:41 2015
@@ -1,43 +1,55 @@
-'use strict';var LCMATH=function(){function k(){this.operators=[]}function e(a,b,c,f){this.type=a;this.op=b;this.value=c;this.children=f}function n(a,b,c,f,e,g){this.id=a;this.arity=b;this.lbp=c;this.rbp=f;this.nud=e;this.led=g}function p(a,b,c){this.msg=a;this.from=b;this.to=c?c:this.from}function r(a,b,c){this.implicit_operators="undefined"==typeof a?!1:a;this.unit_mode="undefined"==typeof b?!1:b;this.constants="undefined"==typeof c?[]:c;this.defs=new k;this.defs.define();this.operators=this.defs.operators;
-this.oph={};for(a=0;a<this.operators.length;a++)this.oph[this.operators[a].id]=this.operators[a]}function s(a,b){this.defs=a;this.text=b}function m(a,b,c,f,e){this.type=a;this.from=b;this.to=c;this.value=f;this.op=e}k.ARG_SEPARATOR=";";k.DECIMAL_SIGN_1=".";k.DECIMAL_SIGN_2=",";k.prototype.operator=function(a,b,c,f,e,g){this.operators.push(new n(a,b,c,f,e,g))};k.prototype.separator=function(a){this.operator(a,n.BINARY,0,0,null,null)};k.prototype.infix=function(a,b,c,f){var l;l=n.BINARY;f=f||function(b,
-d){var f=[d,b.expression(c)];return new e(e.OPERATOR,this,a,f)};this.operator(a,l,b,c,null,f)};k.prototype.prefix=function(a,b,c){var f;f=n.UNARY;c=c||function(c){c=[c.expression(b)];return new e(e.OPERATOR,this,a,c)};this.operator(a,f,0,b,c,null)};k.prototype.suffix=function(a,b,c){var f;f=n.UNARY;c=c||function(b,c){return new e(e.OPERATOR,this,a,[c])};this.operator(a,f,b,0,null,c)};k.prototype.findOperator=function(a){for(var b=0;b<this.operators.length;b++)if(this.operators[b].id==a)return this.operators[b];
-return null};k.prototype.define=function(){this.suffix("!",160);this.infix("^",140,139);this.infix(".",130,129);this.infix("`",125,125,function(a,b){for(var c=a.expression(125);null!=a.current_token&&-1!="*/".indexOf(a.current_token.value);){var f=a.tokens[a.token_nr];if(null==f)break;if(f.type!=m.NAME&&"("!=f.value)break;f=a.tokens[a.token_nr+1];if(null!=f&&("("==f.value||f.type==m.NUMBER))break;if(a.unit_mode&&a.tokens[a.token_nr].type==m.NAME){for(var f=a.tokens[a.token_nr].value,l=!1,g=0;g<a.constants.length;g++)if(f==
-a.constants[g]){l=!0;break}if(l)break}f=a.current_token;a.advance();c=f.op.led(a,c)}return new e(e.OPERATOR,this,"`",[b,c])});this.infix("*",120,120);this.infix("/",120,120);this.infix("%",120,120);this.infix("+",100,100);this.operator("-",n.BINARY,100,134,function(a){a=[a.expression(134)];return new e(e.OPERATOR,this,"-",a)},function(a,b){var c=[b,a.expression(100)];return new e(e.OPERATOR,this,"-",c)});this.infix("=",80,80);this.infix("#",80,80);this.infix("<=",80,80);this.infix(">=",80,80);this.infix("<",
-80,80);this.infix(">",80,80);this.separator(")");this.separator(k.ARG_SEPARATOR);this.operator("(",n.BINARY,200,200,function(a){var b=a.expression(0);a.advance(")");return b},function(a,b){if(b.type!=e.NAME&&b.type!=e.SUBSCRIPT)throw new p("Function name expected before a parenthesis.",a.tokens[a.token_nr-1].from);var c=[b];if(null==a.current_token||null==a.current_token.op||")"!==a.current_token.op.id)for(;;){c.push(a.expression(0));if(null==a.current_token||null==a.current_token.op||a.current_token.op.id!==
-k.ARG_SEPARATOR)break;a.advance(k.ARG_SEPARATOR)}a.advance(")");return new e(e.FUNCTION,this,"(",c)});this.separator("]");this.operator("[",n.BINARY,200,70,function(a){var b=[];if(null==a.current_token||null==a.current_token.op||"]"!==a.current_token.op.id)for(;;){b.push(a.expression(0));if(null==a.current_token||null==a.current_token.op||a.current_token.op.id!==k.ARG_SEPARATOR)break;a.advance(k.ARG_SEPARATOR)}a.advance("]");return new e(e.VECTOR,this,null,b)},function(a,b){if(b.type!=e.NAME&&b.type!=
-e.SUBSCRIPT)throw new p("Name expected before a square bracket.",a.tokens[a.token_nr-1].from);var c=[b];if(null==a.current_token||null==a.current_token.op||"]"!==a.current_token.op.id)for(;;){c.push(a.expression(0));if(null==a.current_token||null==a.current_token.op||a.current_token.op.id!==k.ARG_SEPARATOR)break;a.advance(k.ARG_SEPARATOR)}a.advance("]");return new e(e.SUBSCRIPT,this,"[",c)})};e.UNKNOWN=0;e.NAME=1;e.NUMBER=2;e.OPERATOR=3;e.FUNCTION=4;e.VECTOR=5;e.SUBSCRIPT=6;e.COLORS="#E01010 #0010FF #009000 #FF00FF #00B0B0 #F09000 #800080 #F080A0 #6090F0 #902000 #70A050 #A07060 #5000FF #E06050 #008080 #808000".split(" ");
-e.prototype.toString=function(){var a="(";switch(this.type){case e.UNKNOWN:a+="UNKNOWN";break;case e.NAME:a+="NAME";break;case e.NUMBER:a+="NUMBER";break;case e.OPERATOR:a+="OPERATOR";break;case e.FUNCTION:a+="FUNCTION";break;case e.VECTOR:a+="VECTOR";break;case e.SUBSCRIPT:a+="SUBSCRIPT"}this.op&&(a+=" '"+this.op.id+"'");this.value&&(a+=" '"+this.value+"'");if(this.children){for(var a=a+" [",b=0;b<this.children.length;b++)a+=this.children[b].toString(),b!=this.children.length-1&&(a+=",");a+="]"}return a+
-")"};e.prototype.getColorForIdentifier=function(a,b){var c=b[a];c||(c=e.COLORS[Object.keys(b).length%e.COLORS.length],b[a]=c);return c};e.prototype.toMathML=function(a){var b,c,f,l,g,d,h;"undefined"==typeof a&&(a={hcolors:{},depth:0});b=null!=this.children&&0<this.children.length?this.children[0]:null;c=null!=this.children&&1<this.children.length?this.children[1]:null;f=null!=this.children&&2<this.children.length?this.children[2]:null;l=null!=this.children&&3<this.children.length?this.children[3]:
-null;g=null!=this.children&&4<this.children.length?this.children[4]:null;switch(this.type){case e.UNKNOWN:return d=document.createElement("mtext"),d.appendChild(document.createTextNode("???")),d;case e.NAME:return 0<=this.value.search(/^[a-zA-Z]+[0-9]+$/)?(d=this.value.search(/[0-9]/),f=document.createElement("msub"),f.appendChild(this.mi(this.value.substring(0,d))),f.appendChild(this.mn(this.value.substring(d))),d=f):d=this.mi(this.value),d.setAttribute("mathcolor",this.getColorForIdentifier(this.value,
-a.hcolors)),d;case e.NUMBER:return-1!=this.value.indexOf("e")||-1!=this.value.indexOf("E")?(a=this.value.indexOf("e"),-1==a&&(a=this.value.indexOf("E")),d=document.createElement("mrow"),d.appendChild(this.mn(this.value.substring(0,a))),d.appendChild(this.mo("\u22c5")),b=document.createElement("msup"),b.appendChild(this.mn(10)),b.appendChild(this.mn(this.value.substring(a+1))),d.appendChild(b),d):this.mn(this.value);case e.OPERATOR:if("/"==this.value)g=document.createElement("mfrac"),g.appendChild(b.toMathML(a)),
-g.appendChild(c.toMathML(a)),d=g;else if("^"==this.value)f=b.type==e.FUNCTION?"sqrt"==b.value||"abs"==b.value||"matrix"==b.value||"diff"==b.value?!1:!0:b.type==e.OPERATOR?!0:!1,d=document.createElement("msup"),f?d.appendChild(this.addP(b,a)):d.appendChild(b.toMathML(a)),d.appendChild(c.toMathML(a));else if("*"==this.value){d=document.createElement("mrow");b.type!=e.OPERATOR||"+"!=b.value&&"-"!=b.value?d.appendChild(b.toMathML(a)):d.appendChild(this.addP(b,a));for(f=c;f.type==e.OPERATOR;)f=f.children[0];
-b.type==e.VECTOR&&c.type==e.VECTOR?d.appendChild(this.mo("*")):f.type==e.NUMBER&&d.appendChild(this.mo("\u22c5"));c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a))}else if("-"==this.value)d=document.createElement("mrow"),1==this.children.length?(d.appendChild(this.mo("-")),d.appendChild(b.toMathML(a))):(d.appendChild(b.toMathML(a)),d.appendChild(this.mo("-")),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,
-a)));else if("!"==this.value)d=document.createElement("mrow"),h=this.mo(this.value),b.type!=e.OPERATOR||"+"!=b.value&&"-"!=b.value?d.appendChild(b.toMathML(a)):d.appendChild(this.addP(b,a)),d.appendChild(h);else if("+"==this.value){d=document.createElement("mrow");h=this.mo(this.value);d.appendChild(b.toMathML(a));d.appendChild(h);f=!1;for(l=c;l.type==e.OPERATOR;)if("-"==l.value&&1==l.children.length){f=!0;break}else if("+"==l.value||"-"==l.value||"*"==l.value)l=l.children[0];else break;f?d.appendChild(this.addP(c,
-a)):d.appendChild(c.toMathML(a))}else"."==this.value?(d=document.createElement("mrow"),b.type!=e.OPERATOR||"+"!=b.value&&"-"!=b.value?d.appendChild(b.toMathML(a)):d.appendChild(this.addP(b,a)),d.appendChild(this.mo("\u22c5")),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a))):"`"==this.value?(d=document.createElement("mrow"),b.type!=e.OPERATOR||"+"!=b.value&&"-"!=b.value?d.appendChild(b.toMathML(a)):d.appendChild(this.addP(b,a)),f=document.createElement("mstyle"),
-f.setAttribute("fontstyle","normal"),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?f.appendChild(c.toMathML(a)):f.appendChild(this.addP(c,a)),d.appendChild(f)):(d=document.createElement("mrow"),h=this.mo(this.value),d.appendChild(b.toMathML(a)),d.appendChild(h),d.appendChild(c.toMathML(a)));return d;case e.FUNCTION:if("sqrt"==b.value&&null!=c)d=document.createElement("msqrt"),d.appendChild(c.toMathML(a));else if("abs"==b.value&&null!=c)d=document.createElement("mrow"),d.appendChild(this.mo("|")),
-d.appendChild(c.toMathML(a)),d.appendChild(this.mo("|"));else if("exp"==b.value&&null!=c)d=document.createElement("msup"),d.appendChild(this.mi("e")),d.appendChild(c.toMathML(a));else if("factorial"==b.value)d=document.createElement("mrow"),h=this.mo("!"),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a)),d.appendChild(h);else if("diff"==b.value&&null!=this.children&&3==this.children.length)d=document.createElement("mrow"),g=document.createElement("mfrac"),
-g.appendChild(this.mi("d")),h=document.createElement("mrow"),h.appendChild(this.mi("d")),h.appendChild(this.mi(f.value)),g.appendChild(h),d.appendChild(g),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a));else if("diff"==b.value&&null!=this.children&&4==this.children.length)d=document.createElement("mrow"),g=document.createElement("mfrac"),b=document.createElement("msup"),b.appendChild(this.mi("d")),b.appendChild(l.toMathML(a)),g.appendChild(b),
-h=document.createElement("mrow"),h.appendChild(this.mi("d")),b=document.createElement("msup"),b.appendChild(f.toMathML(a)),b.appendChild(l.toMathML(a)),h.appendChild(b),g.appendChild(h),d.appendChild(g),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a));else if("integrate"==b.value&&null!=this.children&&3==this.children.length)d=document.createElement("mrow"),h=this.mo("\u222b"),h.setAttribute("stretchy","true"),d.appendChild(h),f.type!=e.OPERATOR||
-"+"!=f.value&&"-"!=f.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a)),d.appendChild(this.mi("d")),d.appendChild(f.toMathML(a));else if("integrate"==b.value&&null!=this.children&&5==this.children.length)d=document.createElement("mrow"),b=document.createElement("msubsup"),h=this.mo("\u222b"),h.setAttribute("stretchy","true"),b.appendChild(h),b.appendChild(l.toMathML(a)),b.appendChild(g.toMathML(a)),d.appendChild(b),f.type!=e.OPERATOR||"+"!=f.value&&"-"!=f.value?d.appendChild(c.toMathML(a)):
-d.appendChild(this.addP(c,a)),d.appendChild(this.mi("d")),d.appendChild(f.toMathML(a));else if("sum"==b.value&&null!=this.children&&5==this.children.length)d=document.createElement("mrow"),b=document.createElement("munderover"),h=this.mo("\u2211"),h.setAttribute("stretchy","true"),b.appendChild(h),h=document.createElement("mrow"),h.appendChild(f.toMathML(a)),h.appendChild(this.mo("=")),h.appendChild(l.toMathML(a)),b.appendChild(h),b.appendChild(g.toMathML(a)),d.appendChild(b),f.type!=e.OPERATOR||
-"+"!=f.value&&"-"!=f.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a));else if("product"==b.value&&null!=this.children&&5==this.children.length)d=document.createElement("mrow"),b=document.createElement("munderover"),h=this.mo("\u220f"),h.setAttribute("stretchy","true"),b.appendChild(h),h=document.createElement("mrow"),h.appendChild(f.toMathML(a)),h.appendChild(this.mo("=")),h.appendChild(l.toMathML(a)),b.appendChild(h),b.appendChild(g.toMathML(a)),d.appendChild(b),f.type!=e.OPERATOR||
-"+"!=f.value&&"-"!=f.value?d.appendChild(c.toMathML(a)):d.appendChild(this.addP(c,a));else if("limit"==b.value)d=document.createElement("mrow"),4>this.children.length?d.appendChild(this.mo("lim")):(b=document.createElement("munder"),b.appendChild(this.mo("lim")),h=document.createElement("mrow"),h.appendChild(f.toMathML(a)),h.appendChild(this.mo("\u2192")),h.appendChild(l.toMathML(a)),null!=g&&("plus"==g.value?h.appendChild(this.mo("+")):"minus"==g.value&&h.appendChild(this.mo("-"))),b.appendChild(h),
-d.appendChild(b)),d.appendChild(c.toMathML(a));else{if("binomial"==b.value){d=document.createElement("mrow");d.appendChild(this.mo("("));l=document.createElement("mtable");for(c=1;c<this.children.length;c++)b=document.createElement("mtr"),b.appendChild(this.children[c].toMathML(a)),l.appendChild(b);d.appendChild(l)}else if("matrix"==b.value){for(c=1;c<this.children.length;c++)if(this.children[c].type!==e.VECTOR)return d=document.createElement("mtext"),d.appendChild(document.createTextNode("???")),
-d;d=document.createElement("mrow");d.appendChild(this.mo("("));l=document.createElement("mtable");for(c=1;c<this.children.length;c++){b=document.createElement("mtr");for(f=0;f<this.children[c].children.length;f++)b.appendChild(this.children[c].children[f].toMathML(a));l.appendChild(b)}d.appendChild(l)}else for(d=document.createElement("mrow"),d.appendChild(b.toMathML(a)),d.appendChild(this.mo("(")),c=1;c<this.children.length;c++)d.appendChild(this.children[c].toMathML(a)),c<this.children.length-1&&
-d.appendChild(this.mo(k.ARG_SEPARATOR));d.appendChild(this.mo(")"))}return d;case e.VECTOR:g=!0;for(c=0;c<this.children.length;c++)this.children[c].type!==e.VECTOR&&(g=!1);d=document.createElement("mrow");d.appendChild(this.mo("("));l=document.createElement("mtable");for(c=0;c<this.children.length;c++){b=document.createElement("mtr");if(g)for(f=0;f<this.children[c].children.length;f++)b.appendChild(this.children[c].children[f].toMathML(a));else b.appendChild(this.children[c].toMathML(a));l.appendChild(b)}d.appendChild(l);
-d.appendChild(this.mo(")"));return d;case e.SUBSCRIPT:f=document.createElement("msub");f.appendChild(b.toMathML(a));if(2<this.children.length){d=document.createElement("mrow");for(c=1;c<this.children.length;c++)d.appendChild(this.children[c].toMathML(a)),c<this.children.length-1&&d.appendChild(this.mo(k.ARG_SEPARATOR));f.appendChild(d)}else f.appendChild(c.toMathML(a));return f}};e.prototype.mi=function(a){var b=document.createElement("mi");e.symbols[a]&&(a=e.symbols[a]);b.appendChild(document.createTextNode(a));
-return b};e.prototype.mn=function(a){var b=document.createElement("mn");b.appendChild(document.createTextNode(a));return b};e.prototype.mo=function(a){var b=document.createElement("mo");e.symbols[a]&&(a=e.symbols[a]);b.appendChild(document.createTextNode(a));return b};e.prototype.addP=function(a,b){var c,f;c=document.createElement("mrow");f=this.mo("(");f.setAttribute("mathcolor",e.COLORS[b.depth%e.COLORS.length]);c.appendChild(f);b.depth++;c.appendChild(a.toMathML(b));b.depth--;f=this.mo(")");f.setAttribute("mathcolor",
-e.COLORS[b.depth%e.COLORS.length]);c.appendChild(f);return c};e.symbols={alpha:"\u03b1",beta:"\u03b2",gamma:"\u03b3",delta:"\u03b4",epsilon:"\u03b5",zeta:"\u03b6",eta:"\u03b7",theta:"\u03b8",iota:"\u03b9",kappa:"\u03ba",lambda:"\u03bb",mu:"\u03bc",nu:"\u03bd",xi:"\u03be",omicron:"\u03bf",pi:"\u03c0",rho:"\u03c1",sigma:"\u03c3",tau:"\u03c4",upsilon:"\u03c5",phi:"\u03c6",chi:"\u03c7",psi:"\u03c8",omega:"\u03c9",Alpha:"\u0391",Beta:"\u0392",Gamma:"\u0393",Delta:"\u0394",Epsilon:"\u0395",Zeta:"\u0396",
-Eta:"\u0397",Theta:"\u0398",Iota:"\u0399",Kappa:"\u039a",Lambda:"\u039b",Mu:"\u039c",Nu:"\u039d",Xi:"\u039e",Omicron:"\u039f",Pi:"\u03a0",Rho:"\u03a1",Sigma:"\u03a3",Tau:"\u03a4",Upsilon:"\u03a5",Phi:"\u03a6",Chi:"\u03a7",Psi:"\u03a8",Omega:"\u03a9","#":"\u2260",">=":"\u2265","<=":"\u2264",inf:"\u221e",minf:"-\u221e",hbar:"\u210f",G:"\ud835\udca2"};n.UNKNOWN=0;n.UNARY=1;n.BINARY=2;n.TERNARY=3;p.prototype.toString=function(){return this.msg+" at "+this.from+" - "+this.to};r.prototype.expression=function(a){var b,
-c=this.current_token;if(null==c)throw new p("Expected something at the end",this.tokens[this.tokens.length-1].to+1);this.advance();if(null==c.op)b=new e(c.type,null,c.value,null);else{if(null==c.op.nud)throw new p("Unexpected operator '"+c.op.id+"'",c.from);b=c.op.nud(this)}for(;null!=this.current_token&&null!=this.current_token.op&&a<this.current_token.op.lbp;)c=this.current_token,this.advance(),b=c.op.led(this,b);return b};r.prototype.advance=function(a){if(a&&(null==this.current_token||null==this.current_token.op||
-this.current_token.op.id!==a)){if(null==this.current_token)throw new p("Expected '"+a+"' at the end",this.tokens[this.tokens.length-1].to+1);throw new p("Expected '"+a+"'",this.current_token.from);}this.token_nr>=this.tokens.length?this.current_token=null:(this.current_token=this.tokens[this.token_nr],this.token_nr+=1)};r.prototype.addHiddenOperators=function(){for(var a=this.defs.findOperator("*"),b=this.defs.findOperator("`"),c=!1,f=!1,e=0;e<this.tokens.length-1;e++){var g=this.tokens[e],d=this.tokens[e+
-1];this.unit_mode&&("`"==g.value?c=!0:c&&("^"==g.value?f=!0:f&&g.type==m.NUMBER?f=!1:f||g.type!=m.NUMBER?g.type==m.OPERATOR&&-1=="*/^()".indexOf(g.value)?c=!1:g.type==m.NAME&&"("==d.value&&(c=!1):c=!1));if(g.type==m.NAME&&d.type==m.NAME||g.type==m.NUMBER&&d.type==m.NAME||g.type==m.NUMBER&&d.type==m.NUMBER||g.type==m.NUMBER&&("("==d.value||"["==d.value)||(")"==g.value||"]"==g.value)&&d.type==m.NAME||(")"==g.value||"]"==g.value)&&d.type==m.NUMBER||(")"==g.value||"]"==g.value)&&"("==d.value){if(g=this.unit_mode&&
-!c&&(g.type==m.NUMBER||")"==g.value||"]"==g.value)&&(d.type==m.NAME||("("==d.value||"["==d.value)&&this.tokens.length>e+2&&this.tokens[e+2].type==m.NAME)){var h,k;d.type==m.NAME?(h=d,k=e+1):(k=e+2,h=this.tokens[k]);for(var q=0;q<this.constants.length;q++)if(h.value==this.constants[q]){g=!1;break}if(this.tokens.length>k+1&&"("==this.tokens[k+1].value)for(k="pow sqrt abs exp factorial diff integrate sum product limit binomial matrix ln log log10 mod signum ceiling floor sin cos tan asin acos atan atan2 sinh cosh tanh asinh acosh atanh".split(" "),
-q=0;q<k.length;q++)if(h.value==k[q]){g=!1;break}}g?(d=new m(m.OPERATOR,d.from,d.from,b.id,b),c=!0):d=new m(m.OPERATOR,d.from,d.from,a.id,a);this.tokens.splice(e+1,0,d)}}};r.prototype.parse=function(a){this.tokens=(new s(this.defs,a)).tokenize();if(0==this.tokens.length)return null;this.implicit_operators&&this.addHiddenOperators();this.token_nr=0;this.current_token=this.tokens[this.token_nr];this.advance();a=this.expression(0);if(null!=this.current_token)throw new p("Expected the end",this.current_token.from);
-return a};s.prototype.tokenize=function(){var a,b,c,f,e;b=0;a=this.text.charAt(b);e=[];a:for(;a;)if(f=b," ">=a)b++,a=this.text.charAt(b);else{if("0"<=a&&"9">=a||(a===k.DECIMAL_SIGN_1||a===k.DECIMAL_SIGN_2)&&"0"<=this.text.charAt(b+1)&&"9">=this.text.charAt(b+1)){c="";if(a!==k.DECIMAL_SIGN_1&&a!==k.DECIMAL_SIGN_2)for(b++,c+=a;;){a=this.text.charAt(b);if("0">a||"9"<a)break;b++;c+=a}if(a===k.DECIMAL_SIGN_1||a===k.DECIMAL_SIGN_2)for(b++,c+=a;;){a=this.text.charAt(b);if("0">a||"9"<a)break;b+=1;c+=a}if("e"===
-a||"E"===a){b++;c+=a;a=this.text.charAt(b);if("-"===a||"+"===a)b++,c+=a,a=this.text.charAt(b);if("0">a||"9"<a)throw new p("syntax error in number exponent",f,b);do b++,c+=a,a=this.text.charAt(b);while("0"<=a&&"9">=a)}var g=+c.replace(k.DECIMAL_SIGN_1,".").replace(k.DECIMAL_SIGN_2,".");if(isFinite(g)){e.push(new m(m.NUMBER,f,b-1,c,null));continue}else throw new p("syntax error in number",f,b);}for(c=0;c<this.defs.operators.length;c++)if(g=this.defs.operators[c],this.text.substring(b,b+g.id.length)===
-g.id){b+=g.id.length;a=this.text.charAt(b);e.push(new m(m.OPERATOR,f,b-1,g.id,g));continue a}if("a"<=a&&"z">=a||"A"<=a&&"Z">=a){c=a;for(b++;;)if(a=this.text.charAt(b),"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"0"<=a&&"9">=a||"_"===a)c+=a,b++;else break;e.push(new m(m.NAME,f,b-1,c,null))}else throw new p("unrecognized operator",f,b);}return e};m.UNKNOWN=0;m.NAME=1;m.NUMBER=2;m.OPERATOR=3;"use strict";var t=!1;return{Definitions:k,ENode:e,Operator:n,ParseException:p,Parser:r,initEditors:function(){if(!t){t=!0;
-for(var a=[],b=document.getElementsByClassName("math"),c=0;c<b.length;c++){var f=b[c];if("TEXTAREA"==f.nodeName||"INPUT"==f.nodeName){var e=document.createElement("span");e.setAttribute("style","display:none");f.nextSibling?f.parentNode.insertBefore(e,f.nextSibling):f.parentNode.appendChild(e);f.addEventListener("blur",function(a){return function(b){a.setAttribute("style","display:none")}}(e),!1);f.addEventListener("focus",function(a){return function(b){a.setAttribute("style","display: inline-block; background-color: #FFFFE0")}}(e),
-!1);var g="true"===f.getAttribute("data-implicit_operators"),d="true"===f.getAttribute("data-unit_mode"),h=f.getAttribute("data-constants");h&&(h=h.split(/[\s,]+/));a[c]={ta:f,output_node:e,oldtxt:"",parser:new r(g,d,h)};e=function(b){return function(c){var d=a[b];document.activeElement==d.ta&&d.output_node.setAttribute("style","display: inline-block; background-color: #FFFFE0");var e,f,g,h;e=d.ta;c=d.output_node;e=e.value;g="";for(h=e;h!=g;)g=h,h=g.replace(/\[[^\[\]]*\]/g,"");if(h.split("[").length==
-h.split("]").length){for(g="";h!=g;)g=h,h=g.replace(/\([^\(\)]*\)/g,"");h.split("(").length==h.split(")").length&&-1!=h.indexOf(k.ARG_SEPARATOR)&&(e="["+e+"]")}if(e!=d.oldtxt){for(d.oldtxt=e;null!=c.firstChild;)c.removeChild(c.firstChild);c.removeAttribute("title");if(""!=e){d=d.parser;try{if(f=d.parse(e),null!=f){var m=document.createElement("math");m.setAttribute("display","block");m.appendChild(f.toMathML());c.appendChild(m);MathJax.Hub.Queue(["Typeset",MathJax.Hub,c])}}catch(l){f="error: "+l,
-c.setAttribute("title",f),l instanceof p?(c.appendChild(document.createTextNode(e.substring(0,l.from))),f=document.createElement("span"),f.appendChild(document.createTextNode(e.substring(l.from,l.to+1))),f.className="math-error",c.appendChild(f),l.to<e.length-1&&c.appendChild(document.createTextNode(e.substring(l.to+1)))):(e=document.createTextNode(f),c.appendChild(e))}}}}}(c);""!=f.value&&e();f.addEventListener("change",e,!1);f.addEventListener("keyup",e,!1)}}}}}}();
\ No newline at end of file
+'use strict';var LCMATH=function(){function m(){this.operators=[]}function e(b,a,c,g,f){this.type=b;this.op=a;this.value=c;this.children=g;this.interval_type="undefined"==typeof f?e.NOT_AN_INTERVAL:f}function p(b,a,c,g,f,e){this.id=b;this.arity=a;this.lbp=c;this.rbp=g;this.nud=f;this.led=e}function n(b,a,c){this.msg=b;this.from=a;this.to=c?c:this.from}function r(b,a,c){this.implicit_operators="undefined"==typeof b?!1:b;this.unit_mode="undefined"==typeof a?!1:a;this.constants="undefined"==typeof c||
+null==c?[]:c;this.defs=new m;this.defs.define();this.operators=this.defs.operators;this.oph={};for(b=0;b<this.operators.length;b++)this.oph[this.operators[b].id]=this.operators[b]}function t(b,a){this.defs=b;this.text=a}function l(b,a,c,g,f){this.type=b;this.from=a;this.to=c;this.value=g;this.op=f}m.ARG_SEPARATOR=",";m.DECIMAL_SIGN_1=".";m.DECIMAL_SIGN_2=".";m.INTERVAL_SEPARATOR=":";m.prototype.operator=function(b,a,c,g,f,e){this.operators.push(new p(b,a,c,g,f,e))};m.prototype.separator=function(b){this.operator(b,
+p.BINARY,0,0,null,null)};m.prototype.infix=function(b,a,c,g){var f;f=p.BINARY;g=g||function(a,d){var f=[d,a.expression(c)];return new e(e.OPERATOR,this,b,f)};this.operator(b,f,a,c,null,g)};m.prototype.prefix=function(b,a,c){var g;g=p.UNARY;c=c||function(c){c=[c.expression(a)];return new e(e.OPERATOR,this,b,c)};this.operator(b,g,0,a,c,null)};m.prototype.suffix=function(b,a,c){var g;g=p.UNARY;c=c||function(a,c){return new e(e.OPERATOR,this,b,[c])};this.operator(b,g,a,0,null,c)};m.prototype.findOperator=
+function(b){for(var a=0;a<this.operators.length;a++)if(this.operators[a].id==b)return this.operators[a];return null};m.prototype.buildInterval=function(b,a,c,g){g.advance(m.INTERVAL_SEPARATOR);var f=g.expression(0);if(null==g.current_token||null==g.current_token.op||")"!==g.current_token.op.id&&"]"!==g.current_token.op.id)throw new n("Wrong interval syntax.",g.tokens[g.token_nr-1].from);")"==g.current_token.op.id?(g.advance(")"),b=b?e.CLOSED_OPEN:e.OPEN_OPEN):(g.advance("]"),b=b?e.CLOSED_CLOSED:e.OPEN_CLOSED);
+return new e(e.INTERVAL,c,null,[a,f],b)};m.prototype.define=function(){this.suffix("!",160);this.infix("^",140,139);this.infix(".",130,129);this.infix("`",125,125,function(a,b){for(var g=a.expression(125);null!=a.current_token&&-1!="*/".indexOf(a.current_token.value);){var f=a.tokens[a.token_nr];if(null==f)break;if(f.type!=l.NAME&&"("!=f.value)break;f=a.tokens[a.token_nr+1];if(null!=f&&("("==f.value||f.type==l.NUMBER))break;if(a.unit_mode&&a.tokens[a.token_nr].type==l.NAME){for(var f=a.tokens[a.token_nr].value,
+k=!1,d=0;d<a.constants.length;d++)if(f==a.constants[d]){k=!0;break}if(k)break}f=a.current_token;a.advance();g=f.op.led(a,g)}return new e(e.OPERATOR,this,"`",[b,g])});this.infix("*",120,120);this.infix("/",120,120);this.infix("%",120,120);this.infix("+",100,100);this.operator("-",p.BINARY,100,134,function(a){a=[a.expression(134)];return new e(e.OPERATOR,this,"-",a)},function(a,b){var g=[b,a.expression(100)];return new e(e.OPERATOR,this,"-",g)});this.infix("=",80,80);this.infix("#",80,80);this.infix("<=",
+80,80);this.infix(">=",80,80);this.infix("<",80,80);this.infix(">",80,80);this.separator(")");this.separator(m.ARG_SEPARATOR);this.separator(m.INTERVAL_SEPARATOR);var b=this;this.operator("(",p.BINARY,200,200,function(a){var c=a.expression(0);if(null!=a.current_token&&null!=a.current_token.op&&a.current_token.op.id==m.INTERVAL_SEPARATOR)return b.buildInterval(!1,c,this,a);a.advance(")");return c},function(a,b){if(b.type!=e.NAME&&b.type!=e.SUBSCRIPT)throw new n("Function name expected before a parenthesis.",
+a.tokens[a.token_nr-1].from);var g=[b];if(null==a.current_token||null==a.current_token.op||")"!==a.current_token.op.id)for(;;){g.push(a.expression(0));if(null==a.current_token||null==a.current_token.op||a.current_token.op.id!==m.ARG_SEPARATOR)break;a.advance(m.ARG_SEPARATOR)}a.advance(")");return new e(e.FUNCTION,this,"(",g)});this.separator("]");this.operator("[",p.BINARY,200,70,function(a){var c=[];if(null==a.current_token||null==a.current_token.op||"]"!==a.current_token.op.id){var g=a.expression(0);
+if(null!=a.current_token&&null!=a.current_token.op&&a.current_token.op.id==m.INTERVAL_SEPARATOR)return b.buildInterval(!0,g,this,a);for(;;){c.push(g);if(null==a.current_token||null==a.current_token.op||a.current_token.op.id!==m.ARG_SEPARATOR)break;a.advance(m.ARG_SEPARATOR);g=a.expression(0)}}a.advance("]");return new e(e.VECTOR,this,null,c)},function(a,b){if(b.type!=e.NAME&&b.type!=e.SUBSCRIPT)throw new n("Name expected before a square bracket.",a.tokens[a.token_nr-1].from);var g=[b];if(null==a.current_token||
+null==a.current_token.op||"]"!==a.current_token.op.id)for(;;){g.push(a.expression(0));if(null==a.current_token||null==a.current_token.op||a.current_token.op.id!==m.ARG_SEPARATOR)break;a.advance(m.ARG_SEPARATOR)}a.advance("]");return new e(e.SUBSCRIPT,this,"[",g)});this.separator("}");this.prefix("{",200,function(a){var b=[];if(null==a.current_token||null==a.current_token.op||"}"!==a.current_token.op.id)for(;;){b.push(a.expression(0));if(null==a.current_token||null==a.current_token.op||a.current_token.op.id!==
+m.ARG_SEPARATOR)break;a.advance(m.ARG_SEPARATOR)}a.advance("}");return new e(e.SET,this,null,b)});this.prefix("$",300,function(a){var b=a.expression(300);if(b.type!=e.NAME)throw new n("Variable name expected after a $.",a.tokens[a.token_nr-1].from);b.value="$"+b.value;return b})};"use strict";e.UNKNOWN=0;e.NAME=1;e.NUMBER=2;e.OPERATOR=3;e.FUNCTION=4;e.VECTOR=5;e.INTERVAL=6;e.SET=7;e.SUBSCRIPT=8;e.COLORS="#E01010 #0010FF #009000 #FF00FF #00B0B0 #F09000 #800080 #F080A0 #6090F0 #902000 #70A050 #A07060 #5000FF #E06050 #008080 #808000".split(" ");
+e.NOT_AN_INTERVAL=0;e.OPEN_OPEN=1;e.OPEN_CLOSED=2;e.CLOSED_OPEN=3;e.CLOSED_CLOSED=4;e.prototype.toString=function(){var b="(";switch(this.type){case e.UNKNOWN:b+="UNKNOWN";break;case e.NAME:b+="NAME";break;case e.NUMBER:b+="NUMBER";break;case e.OPERATOR:b+="OPERATOR";break;case e.FUNCTION:b+="FUNCTION";break;case e.VECTOR:b+="VECTOR";break;case e.INTERVAL:b+="INTERVAL";break;case e.SET:b+="SET";break;case e.SUBSCRIPT:b+="SUBSCRIPT"}this.op&&(b+=" '"+this.op.id+"'");this.value&&(b+=" '"+this.value+
+"'");if(this.children){for(var b=b+" [",a=0;a<this.children.length;a++)b+=this.children[a].toString(),a!=this.children.length-1&&(b+=",");b+="]"}this.interval_type&&(b+=" "+this.interval_type);return b+")"};e.prototype.getColorForIdentifier=function(b,a){var c=a.hcolors[b];c||(c=a.colors?a.colors:e.COLORS,c=c[Object.keys(a.hcolors).length%c.length],a.hcolors[b]=c);return c};e.prototype.toMathML=function(b){return this._toMathML({hcolors:{},depth:0,colors:b})};e.prototype._toMathML=function(b){var a,
+c,g,f,k,d,h;a=null!=this.children&&0<this.children.length?this.children[0]:null;c=null!=this.children&&1<this.children.length?this.children[1]:null;g=null!=this.children&&2<this.children.length?this.children[2]:null;f=null!=this.children&&3<this.children.length?this.children[3]:null;k=null!=this.children&&4<this.children.length?this.children[4]:null;switch(this.type){case e.UNKNOWN:return d=document.createElement("mtext"),d.appendChild(document.createTextNode("???")),d;case e.NAME:return 0<=this.value.search(/^[a-zA-Z]+[0-9]+$/)?
+(d=this.value.search(/[0-9]/),g=document.createElement("msub"),g.appendChild(this.mi(this.value.substring(0,d))),g.appendChild(this.mn(this.value.substring(d))),d=g):d=this.mi(this.value),d.setAttribute("mathcolor",this.getColorForIdentifier(this.value,b)),0===this.value.indexOf("$")&&d.setAttribute("fontfamily","monospace"),d;case e.NUMBER:return-1!=this.value.indexOf("e")||-1!=this.value.indexOf("E")?(b=this.value.indexOf("e"),-1==b&&(b=this.value.indexOf("E")),d=document.createElement("mrow"),
+d.appendChild(this.mn(this.value.substring(0,b))),d.appendChild(this.mo("\u22c5")),a=document.createElement("msup"),a.appendChild(this.mn(10)),a.appendChild(this.mn(this.value.substring(b+1))),d.appendChild(a),d):this.mn(this.value);case e.OPERATOR:if("/"==this.value)k=document.createElement("mfrac"),k.appendChild(a._toMathML(b)),k.appendChild(c._toMathML(b)),d=k;else if("^"==this.value)g=a.type==e.FUNCTION?"sqrt"==a.value||"abs"==a.value||"matrix"==a.value||"diff"==a.value?!1:!0:a.type==e.OPERATOR?
+!0:!1,d=document.createElement("msup"),g?d.appendChild(this.addP(a,b)):d.appendChild(a._toMathML(b)),d.appendChild(c._toMathML(b));else if("*"==this.value){d=document.createElement("mrow");a.type!=e.OPERATOR||"+"!=a.value&&"-"!=a.value?d.appendChild(a._toMathML(b)):d.appendChild(this.addP(a,b));for(g=c;g.type==e.OPERATOR;)g=g.children[0];a.type==e.VECTOR&&c.type==e.VECTOR?d.appendChild(this.mo("*")):g.type==e.NUMBER?d.appendChild(this.mo("\u22c5")):b.units?d.appendChild(this.mo("\u22c5")):d.appendChild(this.mo("\u2062"));
+c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b))}else if("-"==this.value)d=document.createElement("mrow"),1==this.children.length?(d.appendChild(this.mo("-")),d.appendChild(a._toMathML(b))):(d.appendChild(a._toMathML(b)),d.appendChild(this.mo("-")),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b)));else if("!"==this.value)d=document.createElement("mrow"),h=this.mo(this.value),a.type!=
+e.OPERATOR||"+"!=a.value&&"-"!=a.value?d.appendChild(a._toMathML(b)):d.appendChild(this.addP(a,b)),d.appendChild(h);else if("+"==this.value){d=document.createElement("mrow");h=this.mo(this.value);d.appendChild(a._toMathML(b));d.appendChild(h);g=!1;for(f=c;f.type==e.OPERATOR;)if("-"==f.value&&1==f.children.length){g=!0;break}else if("+"==f.value||"-"==f.value||"*"==f.value)f=f.children[0];else break;g?d.appendChild(this.addP(c,b)):d.appendChild(c._toMathML(b))}else if("."==this.value)d=document.createElement("mrow"),
+a.type!=e.OPERATOR||"+"!=a.value&&"-"!=a.value?d.appendChild(a._toMathML(b)):d.appendChild(this.addP(a,b)),d.appendChild(this.mo("\u22c5")),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b));else if("`"==this.value){d=document.createElement("mrow");a.type!=e.OPERATOR||"+"!=a.value&&"-"!=a.value?d.appendChild(a._toMathML(b)):d.appendChild(this.addP(a,b));g=document.createElement("mstyle");g.setAttribute("fontstyle","normal");f={};for(h in b)b.hasOwnProperty(h)&&
+(f[h]=b[h]);f.units=!0;c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?g.appendChild(c._toMathML(f)):g.appendChild(this.addP(c,f));d.appendChild(g)}else d=document.createElement("mrow"),h=this.mo(this.value),d.appendChild(a._toMathML(b)),d.appendChild(h),d.appendChild(c._toMathML(b));return d;case e.FUNCTION:if("sqrt"==a.value&&null!=c)d=document.createElement("msqrt"),d.appendChild(c._toMathML(b));else if("abs"==a.value&&null!=c)d=document.createElement("mrow"),d.appendChild(this.mo("|")),d.appendChild(c._toMathML(b)),
+d.appendChild(this.mo("|"));else if("exp"==a.value&&null!=c)d=document.createElement("msup"),d.appendChild(this.mi("e")),d.appendChild(c._toMathML(b));else if("factorial"==a.value)d=document.createElement("mrow"),h=this.mo("!"),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b)),d.appendChild(h);else if("diff"==a.value&&null!=this.children&&3==this.children.length)d=document.createElement("mrow"),k=document.createElement("mfrac"),k.appendChild(this.mi("d")),
+h=document.createElement("mrow"),h.appendChild(this.mi("d")),h.appendChild(this.mi(g.value)),k.appendChild(h),d.appendChild(k),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b));else if("diff"==a.value&&null!=this.children&&4==this.children.length)d=document.createElement("mrow"),k=document.createElement("mfrac"),a=document.createElement("msup"),a.appendChild(this.mi("d")),a.appendChild(f._toMathML(b)),k.appendChild(a),h=document.createElement("mrow"),
+h.appendChild(this.mi("d")),a=document.createElement("msup"),a.appendChild(g._toMathML(b)),a.appendChild(f._toMathML(b)),h.appendChild(a),k.appendChild(h),d.appendChild(k),c.type!=e.OPERATOR||"+"!=c.value&&"-"!=c.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b));else if("integrate"==a.value&&null!=this.children&&3==this.children.length)d=document.createElement("mrow"),h=this.mo("\u222b"),h.setAttribute("stretchy","true"),d.appendChild(h),g.type!=e.OPERATOR||"+"!=g.value&&"-"!=g.value?
+d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b)),d.appendChild(this.mi("d")),d.appendChild(g._toMathML(b));else if("integrate"==a.value&&null!=this.children&&5==this.children.length)d=document.createElement("mrow"),a=document.createElement("msubsup"),h=this.mo("\u222b"),h.setAttribute("stretchy","true"),a.appendChild(h),a.appendChild(f._toMathML(b)),a.appendChild(k._toMathML(b)),d.appendChild(a),g.type!=e.OPERATOR||"+"!=g.value&&"-"!=g.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,
+b)),d.appendChild(this.mi("d")),d.appendChild(g._toMathML(b));else if("sum"==a.value&&null!=this.children&&5==this.children.length){d=document.createElement("mrow");var l=document.createElement("munderover");h=this.mo("\u2211");h.setAttribute("stretchy","true");l.appendChild(h);a=document.createElement("mrow");a.appendChild(g._toMathML(b));a.appendChild(this.mo("="));a.appendChild(f._toMathML(b));l.appendChild(a);l.appendChild(k._toMathML(b));d.appendChild(l);g.type!=e.OPERATOR||"+"!=g.value&&"-"!=
+g.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b))}else if("product"==a.value&&null!=this.children&&5==this.children.length)d=document.createElement("mrow"),l=document.createElement("munderover"),h=this.mo("\u220f"),h.setAttribute("stretchy","true"),l.appendChild(h),a=document.createElement("mrow"),a.appendChild(g._toMathML(b)),a.appendChild(this.mo("=")),a.appendChild(f._toMathML(b)),l.appendChild(a),l.appendChild(k._toMathML(b)),d.appendChild(l),g.type!=e.OPERATOR||"+"!=g.value&&
+"-"!=g.value?d.appendChild(c._toMathML(b)):d.appendChild(this.addP(c,b));else if("limit"==a.value)d=document.createElement("mrow"),4>this.children.length?d.appendChild(this.mo("lim")):(a=document.createElement("munder"),a.appendChild(this.mo("lim")),h=document.createElement("mrow"),h.appendChild(g._toMathML(b)),h.appendChild(this.mo("\u2192")),h.appendChild(f._toMathML(b)),null!=k&&("plus"==k.value?h.appendChild(this.mo("+")):"minus"==k.value&&h.appendChild(this.mo("-"))),a.appendChild(h),d.appendChild(a)),
+d.appendChild(c._toMathML(b));else if("binomial"==a.value){d=document.createElement("mrow");d.appendChild(this.mo("("));g=document.createElement("mtable");for(f=1;f<this.children.length;f++)a=document.createElement("mtr"),a.appendChild(this.children[f]._toMathML(b)),g.appendChild(a);d.appendChild(g);d.appendChild(this.mo(")"))}else if("matrix"==a.value){for(f=1;f<this.children.length;f++)if(this.children[f].type!==e.VECTOR)return d=document.createElement("mtext"),d.appendChild(document.createTextNode("???")),
+d;d=document.createElement("mrow");d.appendChild(this.mo("("));g=document.createElement("mtable");for(f=1;f<this.children.length;f++){a=document.createElement("mtr");for(c=0;c<this.children[f].children.length;c++)a.appendChild(this.children[f].children[c]._toMathML(b));g.appendChild(a)}d.appendChild(g);d.appendChild(this.mo(")"))}else if("union"==a.value&&3==this.children.length){for(f=1;f<this.children.length;f++)if(this.children[f].type!==e.INTERVAL&&this.children[f].type!==e.SET)return d=document.createElement("mtext"),
+d.appendChild(document.createTextNode("???")),d;d=document.createElement("mrow");d.appendChild(c._toMathML(b));d.appendChild(this.mo("\u222a"));d.appendChild(g._toMathML(b))}else if("intersection"==a.value&&3==this.children.length){for(f=1;f<this.children.length;f++)if(this.children[f].type!==e.INTERVAL&&this.children[f].type!==e.SET)return d=document.createElement("mtext"),d.appendChild(document.createTextNode("???")),d;d=document.createElement("mrow");d.appendChild(c._toMathML(b));d.appendChild(this.mo("\u2229"));
+d.appendChild(g._toMathML(b))}else{d=document.createElement("mrow");d.appendChild(a._toMathML(b));d.appendChild(this.mo("("));for(f=1;f<this.children.length;f++)d.appendChild(this.children[f]._toMathML(b)),f<this.children.length-1&&d.appendChild(this.mo(m.ARG_SEPARATOR));d.appendChild(this.mo(")"))}return d;case e.VECTOR:k=!0;for(f=0;f<this.children.length;f++)this.children[f].type!==e.VECTOR&&(k=!1);d=document.createElement("mrow");d.appendChild(this.mo("("));g=document.createElement("mtable");for(f=
+0;f<this.children.length;f++){a=document.createElement("mtr");if(k)for(c=0;c<this.children[f].children.length;c++)a.appendChild(this.children[f].children[c]._toMathML(b));else a.appendChild(this.children[f]._toMathML(b));g.appendChild(a)}d.appendChild(g);d.appendChild(this.mo(")"));return d;case e.INTERVAL:return d=document.createElement("mrow"),h=this.interval_type==e.OPEN_OPEN||this.interval_type==e.OPEN_CLOSED?this.mo("("):this.mo("["),d.appendChild(h),a=document.createElement("mrow"),a.appendChild(this.children[0]._toMathML(b)),
+a.appendChild(this.mo(":")),a.appendChild(this.children[1]._toMathML(b)),d.appendChild(a),h=this.interval_type==e.OPEN_OPEN||this.interval_type==e.CLOSED_OPEN?this.mo(")"):this.mo("]"),d.appendChild(h),d;case e.SET:d=document.createElement("mrow");d.appendChild(this.mo("{"));a=document.createElement("mrow");for(f=0;f<this.children.length;f++)0<f&&a.appendChild(this.mo(";")),a.appendChild(this.children[f]._toMathML(b));d.appendChild(a);d.appendChild(this.mo("}"));return d;case e.SUBSCRIPT:g=document.createElement("msub");
+g.appendChild(a._toMathML(b));if(2<this.children.length){d=document.createElement("mrow");for(f=1;f<this.children.length;f++)d.appendChild(this.children[f]._toMathML(b)),f<this.children.length-1&&d.appendChild(this.mo(m.ARG_SEPARATOR));g.appendChild(d)}else g.appendChild(c._toMathML(b));return g}};e.prototype.mi=function(b){var a=document.createElement("mi");e.symbols[b]&&(b=e.symbols[b]);a.appendChild(document.createTextNode(b));return a};e.prototype.mn=function(b){var a=document.createElement("mn");
+a.appendChild(document.createTextNode(b));return a};e.prototype.mo=function(b){var a=document.createElement("mo");e.symbols[b]&&(b=e.symbols[b]);a.appendChild(document.createTextNode(b));return a};e.prototype.addP=function(b,a){var c,g;c=document.createElement("mrow");g=this.mo("(");var f;f=a.colors?a.colors:e.COLORS;g.setAttribute("mathcolor",f[a.depth%f.length]);c.appendChild(g);a.depth++;c.appendChild(b._toMathML(a));a.depth--;g=this.mo(")");g.setAttribute("mathcolor",f[a.depth%f.length]);c.appendChild(g);
+return c};e.symbols={alpha:"\u03b1",beta:"\u03b2",gamma:"\u03b3",delta:"\u03b4",epsilon:"\u03b5",zeta:"\u03b6",eta:"\u03b7",theta:"\u03b8",iota:"\u03b9",kappa:"\u03ba",lambda:"\u03bb",mu:"\u03bc",nu:"\u03bd",xi:"\u03be",omicron:"\u03bf",pi:"\u03c0",rho:"\u03c1",sigma:"\u03c3",tau:"\u03c4",upsilon:"\u03c5",phi:"\u03c6",chi:"\u03c7",psi:"\u03c8",omega:"\u03c9",Alpha:"\u0391",Beta:"\u0392",Gamma:"\u0393",Delta:"\u0394",Epsilon:"\u0395",Zeta:"\u0396",Eta:"\u0397",Theta:"\u0398",Iota:"\u0399",Kappa:"\u039a",
+Lambda:"\u039b",Mu:"\u039c",Nu:"\u039d",Xi:"\u039e",Omicron:"\u039f",Pi:"\u03a0",Rho:"\u03a1",Sigma:"\u03a3",Tau:"\u03a4",Upsilon:"\u03a5",Phi:"\u03a6",Chi:"\u03a7",Psi:"\u03a8",Omega:"\u03a9","#":"\u2260",">=":"\u2265","<=":"\u2264",inf:"\u221e",minf:"-\u221e",hbar:"\u210f",G:"\ud835\udca2"};"use strict";p.UNKNOWN=0;p.UNARY=1;p.BINARY=2;p.TERNARY=3;"use strict";n.prototype.toString=function(){return this.msg+" at "+this.from+" - "+this.to};"use strict";r.prototype.expression=function(b){var a,c=
+this.current_token;if(null==c)throw new n("Expected something at the end",this.tokens[this.tokens.length-1].to+1);this.advance();if(null==c.op)a=new e(c.type,null,c.value,null);else{if(null==c.op.nud)throw new n("Unexpected operator '"+c.op.id+"'",c.from);a=c.op.nud(this)}for(;null!=this.current_token&&null!=this.current_token.op&&b<this.current_token.op.lbp;)c=this.current_token,this.advance(),a=c.op.led(this,a);return a};r.prototype.advance=function(b){if(b&&(null==this.current_token||null==this.current_token.op||
+this.current_token.op.id!==b)){if(null==this.current_token)throw new n("Expected '"+b+"' at the end",this.tokens[this.tokens.length-1].to+1);throw new n("Expected '"+b+"'",this.current_token.from);}this.token_nr>=this.tokens.length?this.current_token=null:(this.current_token=this.tokens[this.token_nr],this.token_nr+=1)};r.prototype.addHiddenOperators=function(){for(var b=this.defs.findOperator("*"),a=this.defs.findOperator("`"),c=!1,g=!1,f=0;f<this.tokens.length-1;f++){var e=this.tokens[f],d=this.tokens[f+
+1];this.unit_mode&&("`"==e.value?c=!0:c&&("^"==e.value?g=!0:g&&e.type==l.NUMBER?g=!1:g||e.type!=l.NUMBER?g||e.type!=l.OPERATOR||-1!="*/^()".indexOf(e.value)?e.type==l.NAME&&"("==d.value&&(c=!1):c=!1:c=!1));if(e.type==l.NAME&&d.type==l.NAME||e.type==l.NUMBER&&d.type==l.NAME||e.type==l.NUMBER&&d.type==l.NUMBER||e.type==l.NUMBER&&("("==d.value||"["==d.value||"{"==d.value)||(")"==e.value||"]"==e.value||"}"==e.value)&&d.type==l.NAME||(")"==e.value||"]"==e.value||"}"==e.value)&&d.type==l.NUMBER||(")"==
+e.value||"]"==e.value||"}"==e.value)&&"("==d.value){if(e=this.unit_mode&&!c&&(e.type==l.NUMBER||")"==e.value||"]"==e.value||"}"==e.value)&&(d.type==l.NAME||("("==d.value||"["==d.value||"{"==d.value)&&this.tokens.length>f+2&&this.tokens[f+2].type==l.NAME)){var h,m;d.type==l.NAME?(h=d,m=f+1):(m=f+2,h=this.tokens[m]);for(var s=0;s<this.constants.length;s++)if(h.value==this.constants[s]){e=!1;break}if(this.tokens.length>m+1&&"("==this.tokens[m+1].value)for(m="pow sqrt abs exp factorial diff integrate sum product limit binomial matrix ln log log10 mod signum ceiling floor sin cos tan asin acos atan atan2 sinh cosh tanh asinh acosh atanh".split(" "),
+s=0;s<m.length;s++)if(h.value==m[s]){e=!1;break}}e?(d=new l(l.OPERATOR,d.from,d.from,a.id,a),c=!0):d=new l(l.OPERATOR,d.from,d.from,b.id,b);this.tokens.splice(f+1,0,d)}}};r.prototype.parse=function(b){this.tokens=(new t(this.defs,b)).tokenize();if(0==this.tokens.length)return null;this.implicit_operators&&this.addHiddenOperators();this.token_nr=0;this.current_token=this.tokens[this.token_nr];this.advance();b=this.expression(0);if(null!=this.current_token)throw new n("Expected the end",this.current_token.from);
+return b};"use strict";t.prototype.tokenize=function(){var b,a,c,g,f;a=0;b=this.text.charAt(a);f=[];a:for(;b;)if(g=a," ">=b)a++,b=this.text.charAt(a);else{if("0"<=b&&"9">=b||(b===m.DECIMAL_SIGN_1||b===m.DECIMAL_SIGN_2)&&"0"<=this.text.charAt(a+1)&&"9">=this.text.charAt(a+1)){c="";if(b!==m.DECIMAL_SIGN_1&&b!==m.DECIMAL_SIGN_2)for(a++,c+=b;;){b=this.text.charAt(a);if("0">b||"9"<b)break;a++;c+=b}if(b===m.DECIMAL_SIGN_1||b===m.DECIMAL_SIGN_2)for(a++,c+=b;;){b=this.text.charAt(a);if("0">b||"9"<b)break;
+a+=1;c+=b}if("e"===b||"E"===b){a++;c+=b;b=this.text.charAt(a);if("-"===b||"+"===b)a++,c+=b,b=this.text.charAt(a);if("0">b||"9"<b)throw new n("syntax error in number exponent",g,a);do a++,c+=b,b=this.text.charAt(a);while("0"<=b&&"9">=b)}var e=+c.replace(m.DECIMAL_SIGN_1,".").replace(m.DECIMAL_SIGN_2,".");if(isFinite(e)){f.push(new l(l.NUMBER,g,a-1,c,null));continue}else throw new n("syntax error in number",g,a);}for(c=0;c<this.defs.operators.length;c++)if(e=this.defs.operators[c],this.text.substring(a,
+a+e.id.length)===e.id){a+=e.id.length;b=this.text.charAt(a);f.push(new l(l.OPERATOR,g,a-1,e.id,e));continue a}if("a"<=b&&"z">=b||"A"<=b&&"Z">=b||"\u03b1"<=b&&"\u03c9">=b||"\u0391"<=b&&"\u03a9">=b||"\u00b5"==b){c=b;for(a++;;)if(b=this.text.charAt(a),"a"<=b&&"z">=b||"A"<=b&&"Z">=b||"\u03b1"<=b&&"\u03c9">=b||"\u0391"<=b&&"\u03a9">=b||"\u00b5"==b||"0"<=b&&"9">=b||"_"===b)c+=b,a++;else break;f.push(new l(l.NAME,g,a-1,c,null))}else throw new n("unrecognized operator",g,a);}return f};"use strict";l.UNKNOWN=
+0;l.NAME=1;l.NUMBER=2;l.OPERATOR=3;"use strict";var u=function(b){var a,c,e,f,k;a=b.ta;c=b.output_node;a=a.value;f="";for(k=a;k!=f;)f=k,k=f.replace(/\[[^\[\]]*\]/g,"");if(k.split("[").length==k.split("]").length){for(f="";k!=f;)f=k,k=f.replace(/\([^\(\)]*\)/g,"");if(k.split("(").length==k.split(")").length){for(f="";k!=f;)f=k,k=f.replace(/\{[^\{\}]*\}/g,"");k.split("{").length==k.split("}").length&&-1!=k.indexOf(m.ARG_SEPARATOR)&&(a="["+a+"]")}}if(a!=b.oldtxt){for(b.oldtxt=a;null!=c.firstChild;)c.removeChild(c.firstChild);
+c.removeAttribute("title");if(""!=a){b=b.parser;try{if(e=b.parse(a),null!=e){var d=document.createElement("math");d.setAttribute("display","block");d.appendChild(e.toMathML());c.appendChild(d);MathJax.Hub.Queue(["Typeset",MathJax.Hub,c])}}catch(h){e="error: "+h,c.setAttribute("title",e),h instanceof n?(c.appendChild(document.createTextNode(a.substring(0,h.from))),e=document.createElement("span"),e.appendChild(document.createTextNode(a.substring(h.from,h.to+1))),e.className="math-error",c.appendChild(e),
+h.to<a.length-1&&c.appendChild(document.createTextNode(a.substring(h.to+1)))):(a=document.createTextNode(e),c.appendChild(a))}}}},q=[];return{Definitions:m,ENode:e,Operator:p,ParseException:n,Parser:r,initEditors:function(){MathJax.Hub.Config({messageStyle:"none"});for(var b=document.getElementsByClassName("math"),a=0;a<q.length;a++){for(var c=q[a].ta,e=!1,f=0;f<b.length;f++)if(b[f]==c){e=!0;break}e||(f=q[a].output_node,f.parentNode&&f.parentNode.removeChild(f),q.splice(a,1),a--)}for(a=0;a<b.length;a++)if(c=
+b[a],"TEXTAREA"==c.nodeName||"INPUT"==c.nodeName){for(var k=-1,f=0;f<q.length;f++)if(q[f].ta==c){k=f;break}var e="true"===c.getAttribute("data-implicit_operators"),d="true"===c.getAttribute("data-unit_mode"),h=c.getAttribute("data-constants");h&&(h=h.split(/[\s,]+/));if(-1==k){f=document.createElement("span");f.style.display="none";f.style.position="absolute";f.style.backgroundColor="rgba(255,255,224,0.9)";f.style.color="black";f.style.border="1px solid #A0A0A0";f.style.padding="5px";f.style.zIndex=
+"1";var m=function(a,b){var c,d=a.getBoundingClientRect();c=a;for(var e=0,f=0;c&&!isNaN(c.offsetLeft)&&!isNaN(c.offsetTop);)if(e+=c.offsetLeft-c.scrollLeft,f+=c.offsetTop-c.scrollTop,c=c.offsetParent){var g=window.getComputedStyle(c);if("absolute"==g.position||"relative"==g.position)break}c=f;b.style.left=e+"px";b.style.top=window.innerHeight>d.bottom+b.offsetHeight?c+a.offsetHeight+"px":c-b.offsetHeight+"px"};c.nextSibling?c.parentNode.insertBefore(f,c.nextSibling):c.parentNode.appendChild(f);k=
+function(a){return function(b){a.style.display="none"}};c.addEventListener("blur",k(f),!1);c.addEventListener("focus",function(a,b){return function(c){""!=a.value&&(b.style.display="block",m(a,b))}}(c,f),!1);f.addEventListener("mouseenter",k(f),!1);k=q.length;q[k]={ta:c,output_node:f,oldtxt:"",parser:new r(e,d,h)};e=function(a){return function(b){var c=q[a];u(c);document.activeElement==c.ta&&(""!=c.ta.value?(c.output_node.style.display="block",MathJax.Hub.Queue(function(){m(c.ta,c.output_node)})):
+c.output_node.style.display="none")}}(k);""!=c.value&&e();c.addEventListener("change",e,!1);c.addEventListener("keyup",e,!1)}else{var l,n=q[k].parser;if(h||0!=n.constants.length)if(h){if(l=n.constants.length==h.length)for(f=0;f<h.length;f++)if(n.constants[f]!=h[f]){l=!1;break}}else l=!1;else l=!0;n.implicit_operators==e&&n.unit_mode==d&&l||(q[k].parser=new r(e,d,h),""!=c.value&&(q[k].oldtxt="",u(q[k])))}}},updateMathSpanAndDiv:function(){for(var b=document.getElementsByClassName("math"),a=[],c=0,
+e=a.length=b.length;c<e;c++)a[c]=b[c];for(c=0;c<a.length;c++)if(b=a[c],("SPAN"==b.nodeName||"DIV"==b.nodeName)&&null!=b.firstChild&&3==b.firstChild.nodeType){var e="SPAN"==b.nodeName,f=b.firstChild.nodeValue,k="true"===b.getAttribute("data-implicit_operators"),d="true"===b.getAttribute("data-unit_mode"),h=b.getAttribute("data-constants");h&&(h=h.split(/[\s,]+/));k=new r(k,d,h);try{var m=k.parse(f);if(null!=m){var l=document.createElement("math");l.setAttribute("display",e?"inline":"block");l.appendChild(m.toMathML(["#000000"]));
+b.classList.remove("math");b.removeChild(b.firstChild);b.appendChild(l);MathJax.Hub.Queue(["Typeset",MathJax.Hub,b])}}catch(n){b.firstChild.nodeValue="[syntax error in math:"+n+"]",b.classList.remove("math")}}}}}();
Index: loncom/html/adm/LC_math_editor/src/definitions.js
diff -u loncom/html/adm/LC_math_editor/src/definitions.js:1.1 loncom/html/adm/LC_math_editor/src/definitions.js:1.2
--- loncom/html/adm/LC_math_editor/src/definitions.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/definitions.js	Tue Feb 24 15:20:44 2015
@@ -18,6 +18,8 @@
 
 */
 
+"use strict";
+
 /**
  * Operator definitions (see function define() at the end).
  * @constructor
@@ -26,9 +28,10 @@
     this.operators = [];  /* Array of Operator */
 }
 
-Definitions.ARG_SEPARATOR = ";";
+Definitions.ARG_SEPARATOR = ",";
 Definitions.DECIMAL_SIGN_1 = ".";
-Definitions.DECIMAL_SIGN_2 = ",";
+Definitions.DECIMAL_SIGN_2 = ".";
+Definitions.INTERVAL_SEPARATOR = ":";
 
 /**
  * Creates a new operator.
@@ -120,6 +123,38 @@
 }
 
 /**
+ * Returns the ENode for the interval, parsing starting just before the interval separator
+ * @param {boolean} closed - was the first operator closed ?
+ * @param {ENode} e1 - First argument (already parsed)
+ * @param {Operator} op - The operator
+ * @param {Parser} p - The parser
+ * @returns {ENode}
+ */
+Definitions.prototype.buildInterval = function(closed, e1, op, p) {
+    p.advance(Definitions.INTERVAL_SEPARATOR);
+    var e2 = p.expression(0);
+    if (p.current_token == null || p.current_token.op == null ||
+            (p.current_token.op.id !== ")" && p.current_token.op.id !== "]")) {
+        throw new ParseException("Wrong interval syntax.", p.tokens[p.token_nr - 1].from);
+    }
+    var interval_type;
+    if (p.current_token.op.id == ")") {
+        p.advance(")");
+        if (closed)
+            interval_type = ENode.CLOSED_OPEN;
+        else
+            interval_type = ENode.OPEN_OPEN;
+    } else {
+        p.advance("]");
+        if (closed)
+            interval_type = ENode.CLOSED_CLOSED;
+        else
+            interval_type = ENode.OPEN_CLOSED;
+    }
+    return new ENode(ENode.INTERVAL, op, null, [e1, e2], interval_type);
+}
+
+/**
  * Defines all the operators.
  */
 Definitions.prototype.define = function() {
@@ -180,9 +215,15 @@
     
     this.separator(")");
     this.separator(Definitions.ARG_SEPARATOR);
+    this.separator(Definitions.INTERVAL_SEPARATOR);
+    var defs = this;
     this.operator("(", Operator.BINARY, 200, 200, function(p) {
-        // nud (for parenthesis)
+        // nud (for parenthesis and intervals)
         var e = p.expression(0);
+        if (p.current_token != null && p.current_token.op != null &&
+                p.current_token.op.id == Definitions.INTERVAL_SEPARATOR) {
+            return defs.buildInterval(false, e, this, p);
+        }
         p.advance(")");
         return e;
     }, function(p, left) {
@@ -205,15 +246,21 @@
     
     this.separator("]");
     this.operator("[", Operator.BINARY, 200, 70, function(p) {
-        // nud (for vectors)
+        // nud (for vectors and intervals)
         var children = [];
         if (p.current_token == null || p.current_token.op == null || p.current_token.op.id !== "]") {
+            var e = p.expression(0);
+            if (p.current_token != null && p.current_token.op != null &&
+                    p.current_token.op.id == Definitions.INTERVAL_SEPARATOR) {
+                return defs.buildInterval(true, e, this, p);
+            }
             while (true) {
-                children.push(p.expression(0));
+                children.push(e);
                 if (p.current_token == null || p.current_token.op == null || p.current_token.op.id !== Definitions.ARG_SEPARATOR) {
                     break;
                 }
                 p.advance(Definitions.ARG_SEPARATOR);
+                e = p.expression(0);
             }
         }
         p.advance("]");
@@ -235,5 +282,30 @@
         p.advance("]");
         return new ENode(ENode.SUBSCRIPT, this, "[", children);
     });
+    
+    this.separator("}");
+    this.prefix("{", 200, function(p) {
+        // nud (for sets)
+        var children = [];
+        if (p.current_token == null || p.current_token.op == null || p.current_token.op.id !== "}") {
+            while (true) {
+                children.push(p.expression(0));
+                if (p.current_token == null || p.current_token.op == null || p.current_token.op.id !== Definitions.ARG_SEPARATOR) {
+                    break;
+                }
+                p.advance(Definitions.ARG_SEPARATOR);
+            }
+        }
+        p.advance("}");
+        return new ENode(ENode.SET, this, null, children);
+    });
+    this.prefix("$", 300, function(p) {
+        // Perl variables
+        var e = p.expression(300);
+        if (e.type != ENode.NAME)
+            throw new ParseException("Variable name expected after a $.", p.tokens[p.token_nr - 1].from);
+        e.value = '$' + e.value;
+        return e;
+    });
 };
 
Index: loncom/html/adm/LC_math_editor/src/enode.js
diff -u loncom/html/adm/LC_math_editor/src/enode.js:1.1 loncom/html/adm/LC_math_editor/src/enode.js:1.2
--- loncom/html/adm/LC_math_editor/src/enode.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/enode.js	Tue Feb 24 15:20:44 2015
@@ -18,19 +18,26 @@
 
 */
 
+"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.<ENode>} children - The children nodes, only for types OPERATOR, FUNCTION, VECTOR, SUBSCRIPT
+ * @param {Array.<ENode>} 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.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 @@
         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 @@
         }
         s += ']';
     }
+    if (this.interval_type) {
+        s += " " + this.interval_type;
+    }
     s+= ')';
     return s;
 };
@@ -96,26 +120,40 @@
  * @param {Object.<string, string>} 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.<string>} [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.<string, string>} context.hcolors - hash identifier->color
  * @param {number} context.depth - Depth in parenthesis, used for coloring
+ * @param {Array.<string>} 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 @@
             } 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 @@
         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 @@
                 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 @@
                     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 @@
                 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 @@
                 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 @@
             // 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 @@
                 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 @@
                 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 @@
                 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 @@
                 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 @@
                 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 @@
                     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 @@
                     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 @@
                 mtable = document.createElement('mtable');
                 for (i=1; i<this.children.length; i++) {
                     var mtr = document.createElement('mtr');
-                    mtr.appendChild(this.children[i].toMathML(context));
+                    mtr.appendChild(this.children[i]._toMathML(context));
                     mtable.appendChild(mtr);
                 }
                 mrow.appendChild(mtable);
@@ -474,20 +526,48 @@
                 for (i=1; i<this.children.length; i++) {
                     var mtr = document.createElement('mtr');
                     for (j=0; j<this.children[i].children.length; j++) {
-                        mtr.appendChild(this.children[i].children[j].toMathML(context));
+                        mtr.appendChild(this.children[i].children[j]._toMathML(context));
                     }
                     mtable.appendChild(mtr);
                 }
                 mrow.appendChild(mtable);
                 mrow.appendChild(this.mo(")"));
                 el = mrow;
+            } else if (c0.value == "union" && this.children.length == 3) {
+                for (i=1; i<this.children.length; i++) {
+                    // check that all children are intervals or sets
+                    if (this.children[i].type !== ENode.INTERVAL && this.children[i].type !== ENode.SET) {
+                        el = document.createElement('mtext');
+                        el.appendChild(document.createTextNode("???"));
+                        return(el);
+                    }
+                }
+                mrow = document.createElement('mrow');
+                mrow.appendChild(c1._toMathML(context));
+                mrow.appendChild(this.mo("\u222A"));
+                mrow.appendChild(c2._toMathML(context));
+                el = mrow;
+            } else if (c0.value == "intersection" && this.children.length == 3) {
+                for (i=1; i<this.children.length; i++) {
+                    // check that all children are intervals or sets
+                    if (this.children[i].type !== ENode.INTERVAL && this.children[i].type !== ENode.SET) {
+                        el = document.createElement('mtext');
+                        el.appendChild(document.createTextNode("???"));
+                        return(el);
+                    }
+                }
+                mrow = document.createElement('mrow');
+                mrow.appendChild(c1._toMathML(context));
+                mrow.appendChild(this.mo("\u2229"));
+                mrow.appendChild(c2._toMathML(context));
+                el = mrow;
             } else {
                 // default display for a function
                 mrow = document.createElement('mrow');
-                mrow.appendChild(c0.toMathML(context));
+                mrow.appendChild(c0._toMathML(context));
                 mrow.appendChild(this.mo("("));
                 for (i=1; i<this.children.length; i++) {
-                    mrow.appendChild(this.children[i].toMathML(context));
+                    mrow.appendChild(this.children[i]._toMathML(context));
                     if (i < this.children.length - 1)
                         mrow.appendChild(this.mo(Definitions.ARG_SEPARATOR));
                 }
@@ -509,32 +589,67 @@
                 var mtr = document.createElement('mtr');
                 if (is_matrix) {
                     for (j=0; j<this.children[i].children.length; j++) {
-                        mtr.appendChild(this.children[i].children[j].toMathML(context));
+                        mtr.appendChild(this.children[i].children[j]._toMathML(context));
                     }
                 } else {
-                    mtr.appendChild(this.children[i].toMathML(context));
+                    mtr.appendChild(this.children[i]._toMathML(context));
                 }
                 mtable.appendChild(mtr);
             }
             mrow.appendChild(mtable);
             mrow.appendChild(this.mo(")"));
             return(mrow);
+        
+        case ENode.INTERVAL:
+            mrow = document.createElement('mrow');
+            if (this.interval_type == ENode.OPEN_OPEN || this.interval_type == ENode.OPEN_CLOSED) {
+                mo = this.mo("(");
+            } else {
+                mo = this.mo("[");
+            }
+            mrow.appendChild(mo);
+            mrow2 = document.createElement('mrow');
+            mrow2.appendChild(this.children[0]._toMathML(context));
+            mrow2.appendChild(this.mo(":"));
+            mrow2.appendChild(this.children[1]._toMathML(context));
+            mrow.appendChild(mrow2);
+            if (this.interval_type == ENode.OPEN_OPEN || this.interval_type == ENode.CLOSED_OPEN) {
+                mo = this.mo(")");
+            } else {
+                mo = this.mo("]");
+            }
+            mrow.appendChild(mo);
+            return(mrow);
             
+        case ENode.SET:
+            mrow = document.createElement('mrow');
+            mrow.appendChild(this.mo("{"));
+            mrow2 = document.createElement('mrow');
+            for (i=0; i<this.children.length; i++) {
+                if (i > 0)
+                    mrow2.appendChild(this.mo(";"));
+                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<this.children.length; i++) {
-                    mrow.appendChild(this.children[i].toMathML(context));
+                    mrow.appendChild(this.children[i]._toMathML(context));
                     if (i < this.children.length - 1)
                         mrow.appendChild(this.mo(Definitions.ARG_SEPARATOR));
                 }
                 msub.appendChild(mrow);
             } else {
-                msub.appendChild(c1.toMathML(context));
+                msub.appendChild(c1._toMathML(context));
             }
             return(msub);
+            
     }
 };
 
@@ -587,13 +702,18 @@
     var mrow, mo;
     mrow = document.createElement('mrow');
     mo = this.mo("(");
-    mo.setAttribute("mathcolor", ENode.COLORS[context.depth % ENode.COLORS.length]);
+    var colors;
+    if (context.colors)
+        colors = context.colors;
+    else
+        colors = ENode.COLORS;
+    mo.setAttribute("mathcolor", colors[context.depth % colors.length]);
     mrow.appendChild(mo);
     context.depth++;
-    mrow.appendChild(en.toMathML(context));
+    mrow.appendChild(en._toMathML(context));
     context.depth--;
     mo = this.mo(")");
-    mo.setAttribute("mathcolor", ENode.COLORS[context.depth % ENode.COLORS.length]);
+    mo.setAttribute("mathcolor", colors[context.depth % colors.length]);
     mrow.appendChild(mo);
     return mrow;
 };
Index: loncom/html/adm/LC_math_editor/src/operator.js
diff -u loncom/html/adm/LC_math_editor/src/operator.js:1.1 loncom/html/adm/LC_math_editor/src/operator.js:1.2
--- loncom/html/adm/LC_math_editor/src/operator.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/operator.js	Tue Feb 24 15:20:44 2015
@@ -18,6 +18,8 @@
 
 */
 
+"use strict";
+
 /**
  * Null denotation function
  * @callback nudFunction
Index: loncom/html/adm/LC_math_editor/src/parse_exception.js
diff -u loncom/html/adm/LC_math_editor/src/parse_exception.js:1.1 loncom/html/adm/LC_math_editor/src/parse_exception.js:1.2
--- loncom/html/adm/LC_math_editor/src/parse_exception.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/parse_exception.js	Tue Feb 24 15:20:44 2015
@@ -18,6 +18,8 @@
 
 */
 
+"use strict";
+
 /**
  * Parse exception
  * @constructor
Index: loncom/html/adm/LC_math_editor/src/parser.js
diff -u loncom/html/adm/LC_math_editor/src/parser.js:1.1 loncom/html/adm/LC_math_editor/src/parser.js:1.2
--- loncom/html/adm/LC_math_editor/src/parser.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/parser.js	Tue Feb 24 15:20:44 2015
@@ -18,6 +18,8 @@
 
 */
 
+"use strict";
+
 /**
  * Equation parser
  * @constructor
@@ -34,7 +36,7 @@
         this.unit_mode = false;
     else
         this.unit_mode = unit_mode;
-    if (typeof constants == "undefined")
+    if (typeof constants == "undefined" || constants == null)
         this.constants = [];
     else
         this.constants = constants;
@@ -117,7 +119,7 @@
                     in_exp = false;
                 else if (!in_exp && token.type == Token.NUMBER)
                     in_units = false;
-                else if (token.type == Token.OPERATOR && "*/^()".indexOf(token.value) == -1)
+                else if (!in_exp && token.type == Token.OPERATOR && "*/^()".indexOf(token.value) == -1)
                     in_units = false;
                 else if (token.type == Token.NAME && next_token.value == "(")
                     in_units = false;
@@ -127,18 +129,18 @@
                 (token.type == Token.NAME && next_token.type == Token.NAME) ||
                 (token.type == Token.NUMBER && next_token.type == Token.NAME) ||
                 (token.type == Token.NUMBER && next_token.type == Token.NUMBER) ||
-                (token.type == Token.NUMBER && (next_token.value == "(" || next_token.value == "[")) ||
+                (token.type == Token.NUMBER && (next_token.value == "(" || next_token.value == "[" || next_token.value == "{")) ||
                 /*(token.type == Token.NAME && next_token.value == "(") ||*/
                 /* name ( could be a function call */
-                ((token.value == ")" || token.value == "]") && next_token.type == Token.NAME) ||
-                ((token.value == ")" || token.value == "]") && next_token.type == Token.NUMBER) ||
-                ((token.value == ")" || token.value == "]") && next_token.value == "(")
+                ((token.value == ")" || token.value == "]" || token.value == "}") && next_token.type == Token.NAME) ||
+                ((token.value == ")" || token.value == "]" || token.value == "}") && next_token.type == Token.NUMBER) ||
+                ((token.value == ")" || token.value == "]" || token.value == "}") && next_token.value == "(")
            ) {
             // support for things like "(1/2) (m/s)" is complex...
             var units = (this.unit_mode && !in_units && (token.type == Token.NUMBER ||
-                (token.value == ")" || token.value == "]")) &&
+                (token.value == ")" || token.value == "]" || token.value == "}")) &&
                 (next_token.type == Token.NAME ||
-                    ((next_token.value == "(" || next_token.value == "[") && this.tokens.length > i + 2 &&
+                    ((next_token.value == "(" || next_token.value == "[" || next_token.value == "{") && this.tokens.length > i + 2 &&
                     this.tokens[i + 2].type == Token.NAME)));
             if (units) {
                 var test_token, index_test;
Index: loncom/html/adm/LC_math_editor/src/token.js
diff -u loncom/html/adm/LC_math_editor/src/token.js:1.1 loncom/html/adm/LC_math_editor/src/token.js:1.2
--- loncom/html/adm/LC_math_editor/src/token.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/token.js	Tue Feb 24 15:20:44 2015
@@ -18,6 +18,8 @@
 
 */
 
+"use strict";
+
 /**
  * A token from the equation text.
  * @constructor
Index: loncom/html/adm/LC_math_editor/src/tokenizer.js
diff -u loncom/html/adm/LC_math_editor/src/tokenizer.js:1.1 loncom/html/adm/LC_math_editor/src/tokenizer.js:1.2
--- loncom/html/adm/LC_math_editor/src/tokenizer.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/tokenizer.js	Tue Feb 24 15:20:44 2015
@@ -18,6 +18,8 @@
 
 */
 
+"use strict";
+
 /**
  * String tokenizer. Recognizes only names, numbers, and parser operators.
  * @constructor
@@ -141,12 +143,14 @@
         }
         
         // names
-        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+                (c >= 'α' && c <= 'ω') || (c >= 'Α' && c <= 'Ω') || c == 'µ') {
             value = c;
             i++;
             for (;;) {
                 c = this.text.charAt(i);
                 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+                        (c >= 'α' && c <= 'ω') || (c >= 'Α' && c <= 'Ω') || c == 'µ' ||
                         (c >= '0' && c <= '9') || c === '_') {
                     value += c;
                     i++;
Index: loncom/html/adm/LC_math_editor/src/ui.js
diff -u loncom/html/adm/LC_math_editor/src/ui.js:1.1 loncom/html/adm/LC_math_editor/src/ui.js:1.2
--- loncom/html/adm/LC_math_editor/src/ui.js:1.1	Wed Sep 24 18:14:39 2014
+++ loncom/html/adm/LC_math_editor/src/ui.js	Tue Feb 24 15:20:44 2015
@@ -43,8 +43,15 @@
         test2 = test1.replace(/\([^\(\)]*\)/g, '');
       }
       if (test2.split("(").length == test2.split(")").length) {
-        if (test2.indexOf(Definitions.ARG_SEPARATOR) != -1) {
-          txt = '['+txt+']';
+        test1 = '';
+        while (test2 != test1) {
+          test1 = test2;
+          test2 = test1.replace(/\{[^\{\}]*\}/g, '');
+        }
+        if (test2.split("{").length == test2.split("}").length) {
+          if (test2.indexOf(Definitions.ARG_SEPARATOR) != -1) {
+            txt = '['+txt+']';
+          }
         }
       }
     }
@@ -86,64 +93,217 @@
     }
 }
 
-var init_done = false;
+var math_objects = [];
 
 /*
   Looks for elements with the "math" class, and
   adds a preview div afterward which is updated automatically.
+  Can be called again after math fields have been added, removed, or when options have changed.
 */
 var initEditors = function() {
-    if (init_done)
-        return;
-    init_done = true;
-    var math_objects = [];
+    // to hide the MathJax messages (note: this could be done elsewhere)
+    MathJax.Hub.Config({
+        messageStyle: "none"
+    });
     var math_inputs = document.getElementsByClassName('math');
+    // first remove the nodes and objects for the inputs that are gone
+    for (var i=0; i<math_objects.length; i++) {
+        var ta = math_objects[i].ta;
+        var found = false;
+        for (var j=0; j<math_inputs.length; j++) {
+            if (math_inputs[j] == ta) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            var output_node = math_objects[i].output_node;
+            if (output_node.parentNode) {
+                output_node.parentNode.removeChild(output_node);
+            }
+            math_objects.splice(i, 1);
+            i--;
+        }
+    }
+    // then create or update nodes and objects for the new inputs
     for (var i=0; i<math_inputs.length; i++) {
         var ta = math_inputs[i];
         if (ta.nodeName == "TEXTAREA" || ta.nodeName == "INPUT") {
-            var output_node = document.createElement("span");
-            output_node.setAttribute("style", "display:none");
-            if (ta.nextSibling)
-                ta.parentNode.insertBefore(output_node, ta.nextSibling);
-            else
-                ta.parentNode.appendChild(output_node);
-            var hideNode = function(node) {
-                return function(e) { node.setAttribute("style", "display:none"); };
-            };
-            var showNode = function(node) {
-                return function(e) { node.setAttribute("style", "display: inline-block; background-color: #FFFFE0"); };
-            };
-            ta.addEventListener("blur", hideNode(output_node), false);
-            ta.addEventListener("focus", showNode(output_node), false);
+            var ind_math = -1;
+            for (var j=0; j<math_objects.length; j++) {
+                if (math_objects[j].ta == ta) {
+                    ind_math = j;
+                    break;
+                }
+            }
             var implicit_operators = (ta.getAttribute("data-implicit_operators") === "true");
             var unit_mode = (ta.getAttribute("data-unit_mode") === "true");
             var constants = ta.getAttribute("data-constants");
             if (constants)
                 constants = constants.split(/[\s,]+/);
-            var oldtxt = "";
-            math_objects[i] = {
-                "ta": ta,
-                "output_node": output_node,
-                "oldtxt": oldtxt,
-                "parser": new Parser(implicit_operators, unit_mode, constants)
-            };
-            var changeObjectN = function(n) {
-                return function(e) {
-                  var obj = math_objects[n];
-                  if (document.activeElement == obj.ta) {
-                    // this is useful if there is data in the field with the page default focus
-                    // (there might not be a focus event for the active element)
-                    obj.output_node.setAttribute("style", "display: inline-block; background-color: #FFFFE0");
-                  }
-                  handleChange(obj);
+            var output_node;
+            if (ind_math == -1) {
+                output_node = document.createElement("span");
+                output_node.style.display = "none";
+                output_node.style.position = "absolute";
+                output_node.style.backgroundColor = "rgba(255,255,224,0.9)";
+                output_node.style.color = "black";
+                output_node.style.border = "1px solid #A0A0A0";
+                output_node.style.padding = "5px";
+                output_node.style.zIndex = "1";
+                var getCSSAbsolutePosition = function getCSSAbsolutePosition(el) {
+                    var x = 0;
+                    var y = 0;
+                    while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
+                        x += el.offsetLeft - el.scrollLeft;
+                        y += el.offsetTop - el.scrollTop;
+                        el = el.offsetParent;
+                        if (el) {
+                            var style = window.getComputedStyle(el);
+                            if (style.position == 'absolute' || style.position == 'relative')
+                                break;
+                        }
+                    }
+                    return {top: y, left: x};
+                }
+                var place = function(ta, output_node) {
+                    // position the output_node below or on top of ta
+                    var ta_rect = ta.getBoundingClientRect();
+                    var root = document.documentElement;
+                    var docTop = (window.pageYOffset || root.scrollTop)  - (root.clientTop || 0);
+                    var docLeft = (window.pageXOffset || root.scrollLeft) - (root.clientLeft || 0);
+                    var ta_pos = getCSSAbsolutePosition(ta);
+                    output_node.style.left = ta_pos.left + "px";
+                    if (window.innerHeight > ta_rect.bottom + output_node.offsetHeight)
+                        output_node.style.top = (ta_pos.top + ta.offsetHeight) + "px";
+                    else
+                        output_node.style.top = (ta_pos.top - output_node.offsetHeight) + "px";
+                }
+                if (ta.nextSibling)
+                    ta.parentNode.insertBefore(output_node, ta.nextSibling);
+                else
+                    ta.parentNode.appendChild(output_node);
+                var hide_node = function(an_output_node) {
+                    // returns a function that will hide the node on any event
+                    // (we can't use the node directly because it changes in the loop)
+                    return function(e) {
+                      an_output_node.style.display = "none";
+                    };
+                }
+                var focus = function(a_ta, an_output_node) {
+                    return function(e) {
+                        if (a_ta.value != '') {
+                            an_output_node.style.display = "block";
+                            place(a_ta, an_output_node);
+                        }
+                    };
                 };
-            };
-            var startChange = changeObjectN(i);
-            if (ta.value != oldtxt)
-                startChange(); // process non-empty fields even though they are not visible yet
-            ta.addEventListener('change', startChange, false);
-            ta.addEventListener('keyup', startChange, false);
+                ta.addEventListener("blur", hide_node(output_node), false);
+                ta.addEventListener("focus", focus(ta, output_node), false);
+                output_node.addEventListener("mouseenter", hide_node(output_node), false);
+                ind_math = math_objects.length;
+                var oldtxt = "";
+                math_objects[ind_math] = {
+                    "ta": ta,
+                    "output_node": output_node,
+                    "oldtxt": oldtxt,
+                    "parser": new Parser(implicit_operators, unit_mode, constants)
+                };
+                var changeObjectN = function(n) {
+                    return function(e) {
+                      var obj = math_objects[n];
+                      handleChange(obj);
+                      if (document.activeElement == obj.ta) {
+                          if (obj.ta.value != '') {
+                              obj.output_node.style.display = "block";
+                              MathJax.Hub.Queue(function () {
+                                  // position the element only when MathJax is done, because the output_node height might change
+                                  place(obj.ta, obj.output_node);
+                              });
+                          } else {
+                              obj.output_node.style.display = "none";
+                          }
+                      }
+                    };
+                };
+                var startChange = changeObjectN(ind_math);
+                if (ta.value != oldtxt)
+                    startChange(); // process non-empty fields even though they are not visible yet
+                ta.addEventListener('change', startChange, false);
+                ta.addEventListener('keyup', startChange, false);
+            } else {
+                // only create a new parser and update the result if the options have changed
+                var same_constants;
+                var parser = math_objects[ind_math].parser;
+                if (!constants && parser.constants.length == 0) {
+                    same_constants = true;
+                } else {
+                    if (constants) {
+                        same_constants = parser.constants.length == constants.length;
+                        if (same_constants) {
+                            for (var j=0; j<constants.length; j++) {
+                                if (parser.constants[j] != constants[j]) {
+                                    same_constants = false;
+                                    break;
+                                }
+                            }
+                        }
+                    } else {
+                        same_constants = false;
+                    }
+                }
+                if (parser.implicit_operators != implicit_operators || parser.unit_mode != unit_mode || !same_constants) {
+                    math_objects[ind_math].parser = new Parser(implicit_operators, unit_mode, constants);
+                    if (ta.value != '') {
+                        math_objects[ind_math].oldtxt = '';
+                        handleChange(math_objects[ind_math]);
+                    }
+                }
+            }
         }
     }
 }
 
+/**
+ * Updates display for <span class="math"> and <div class="math"> (LON-CAPA ln and dlm tags)
+ */
+var updateMathSpanAndDiv = function() {
+    var nl = document.getElementsByClassName('math');
+    // convert to an array because the nodelist would change as we are removing nodes from the document
+    var math_nodes = [];
+    for (var i = 0, ref = math_nodes.length = nl.length; i < ref; i++) {
+      math_nodes[i] = nl[i];
+    }
+    for (var i=0; i<math_nodes.length; i++) {
+        var el = math_nodes[i];
+        if (el.nodeName == "SPAN" || el.nodeName == "DIV") {
+            if (el.firstChild == null || el.firstChild.nodeType != 3)
+                continue;
+            var bspan = (el.nodeName == "SPAN");
+            var txt = el.firstChild.nodeValue;
+            var implicit_operators = (el.getAttribute("data-implicit_operators") === "true");
+            var unit_mode = (el.getAttribute("data-unit_mode") === "true");
+            var constants = el.getAttribute("data-constants");
+            if (constants)
+                constants = constants.split(/[\s,]+/);
+            var parser = new Parser(implicit_operators, unit_mode, constants);
+            try {
+                var root = parser.parse(txt);
+                if (root != null) {
+                    var math = document.createElement("math");
+                    math.setAttribute("display", bspan ? "inline" : "block");
+                    math.appendChild(root.toMathML(['#000000']));
+                    // at this point it would be nice to replace el by math, but MathJax does not
+                    // always typeset math elements when given directly, so we need to typeset the parent...
+                    el.classList.remove('math');
+                    el.removeChild(el.firstChild);
+                    el.appendChild(math);
+                    MathJax.Hub.Queue(["Typeset", MathJax.Hub, el]);
+                }
+            } catch (e) {
+                el.firstChild.nodeValue = "[syntax error in math:" + e + "]";
+                el.classList.remove('math');
+            }
+        }
+    }
+}


More information about the LON-CAPA-cvs mailing list