Annotation of modules/damieng/graphical_editor/loncapa_daxe/web/nodes/lm.dart, revision 1.2

1.1       damieng     1: /*
                      2:   This file is part of LONCAPA-Daxe.
                      3: 
                      4:   LONCAPA-Daxe is free software: you can redistribute it and/or modify
                      5:   it under the terms of the GNU General Public License as published by
                      6:   the Free Software Foundation, either version 3 of the License, or
                      7:   (at your option) any later version.
                      8: 
                      9:   LONCAPA-Daxe is distributed in the hope that it will be useful,
                     10:   but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     12:   GNU General Public License for more details.
                     13: 
                     14:   You should have received a copy of the GNU General Public License
                     15:   along with Daxe.  If not, see <http://www.gnu.org/licenses/>.
                     16: */
                     17: 
                     18: part of loncapa_daxe;
                     19: 
                     20: /**
                     21:  * Displays lm and dlm elements (LON-CAPA inline and display math).
                     22:  * Jaxe display type: 'lm'.
                     23:  */
                     24: class Lm extends DaxeNode {
                     25:   
1.2     ! damieng    26:   static List<String> constants = ['c', 'pi', 'e', 'hbar', 'amu'];
1.1       damieng    27:   static js.JsObject parser_symbols;
                     28:   static js.JsObject parser_units;
                     29:   
                     30:   Lm.fromRef(x.Element elementRef) : super.fromRef(elementRef) {
                     31:   }
                     32:   
                     33:   Lm.fromNode(x.Node node, DaxeNode parent) : super.fromNode(node, parent) {
                     34:   }
                     35:   
                     36:   @override
                     37:   h.Element html() {
                     38:     h.Element el;
                     39:     if (nodeName == 'dlm')
                     40:       el = new h.DivElement();
                     41:     else
                     42:       el = new h.SpanElement();
                     43:     el.id = "$id";
                     44:     el.classes.add('dn');
                     45:     el.classes.add('math');
                     46:     if (!valid)
                     47:       el.classes.add('invalid');
                     48:     el.onClick.listen((h.MouseEvent event) => makeEditable());
                     49:     updateEquationDisplay(el);
                     50:     return(el);
                     51:   }
                     52:   
                     53:   @override
                     54:   void newNodeCreationUI(ActionFunction okfct) {
                     55:     okfct();
                     56:     makeEditable();
                     57:   }
                     58:   
                     59:   @override
                     60:   Position firstCursorPositionInside() {
                     61:     return(null);
                     62:   }
                     63:   
                     64:   @override
                     65:   Position lastCursorPositionInside() {
                     66:     return(null);
                     67:   }
                     68:   
                     69:   @override
                     70:   void afterInsert() {
                     71:     h.Element el = h.document.getElementById(id);
                     72:     updateEquationDisplay(el);
                     73:   }
                     74:   
                     75:   void updateEquationDisplay(h.Element el) {
                     76:     String equationText = '?';
                     77:     if (firstChild != null && firstChild.nodeValue.trim() != '')
                     78:       equationText = firstChild.nodeValue;
                     79:     js.JsObject parser;
                     80:     if (getAttribute('mode') == 'units') {
                     81:       if (parser_units == null)
                     82:         parser_units = new js.JsObject(js.context['LCMATH']['Parser'], [true, true, constants]);
                     83:       parser = parser_units;
                     84:     } else {
                     85:       if (parser_symbols == null)
                     86:         parser_symbols = new js.JsObject(js.context['LCMATH']['Parser'], [true, false, constants]);
                     87:       parser = parser_symbols;
                     88:     }
                     89:     for (h.Node n in el.childNodes)
                     90:       n.remove();
                     91:     try {
                     92:       js.JsObject root = parser.callMethod('parse', [equationText]);
                     93:       if (root != null) {
                     94:         h.Element math = h.document.createElement('math');
                     95:         math.setAttribute('display', nodeName == 'dlm' ? 'block' : 'inline');
                     96:         js.JsObject colors = new js.JsObject.jsify(['#000000']); // to use only black
                     97:         math.append(root.callMethod('toMathML', [colors]));
                     98:         el.append(math);
                     99:         Timer.run(() {
                    100:           js.JsArray params = new js.JsObject.jsify( ['Typeset', js.context['MathJax']['Hub'], id] );
                    101:           js.context['MathJax']['Hub'].callMethod('Queue', [params]);
                    102:           js.context['MathJax']['Hub'].callMethod('Queue', [() => page.cursor.refresh()]);
                    103:         });
                    104:       }
                    105:     } catch (e) {
                    106:       el.text = 'Error: ' + e.toString();
                    107:     }
                    108:   }
                    109:   
                    110:   void makeEditable() {
                    111:     h.Element el = h.document.getElementById(id);
                    112:     if (el == null)
                    113:       return;
                    114:     h.Element editEl;
                    115:     if (nodeName == 'dlm')
                    116:       editEl = new h.DivElement();
                    117:     else
                    118:       editEl = new h.SpanElement();
                    119:     editEl.id = id;
                    120:     h.TextInputElement input = new h.TextInputElement();
                    121:     input.classes.add('math');
                    122:     input.setAttribute('data-unit_mode', getAttribute('mode') == 'units' ? 'true' : 'false');
1.2     ! damieng   123:     input.setAttribute('data-constants', constants.join(','));
1.1       damieng   124:     input.setAttribute('data-implicit_operators', 'true');
                    125:     input.setAttribute('spellcheck', 'false');
                    126:     if (firstChild != null) {
                    127:       input.value = firstChild.nodeValue;
                    128:       if (input.value.length > 20)
                    129:         input.size = input.value.length;
                    130:     }
                    131:     editEl.append(input);
                    132:     h.SelectElement select = new h.SelectElement();
                    133:     h.OptionElement symbolsOption = new h.OptionElement();
                    134:     symbolsOption.value = 'symbols';
                    135:     symbolsOption.appendText(LCDStrings.get('lm_symbols'));
                    136:     if (getAttribute('mode') != 'units')
                    137:       symbolsOption.setAttribute('selected', 'selected');
                    138:     select.append(symbolsOption);
                    139:     h.OptionElement unitsOption = new h.OptionElement();
                    140:     unitsOption.value = 'units';
                    141:     unitsOption.appendText(LCDStrings.get('lm_units'));
                    142:     if (getAttribute('mode') == 'units')
                    143:       unitsOption.setAttribute('selected', 'selected');
                    144:     select.append(unitsOption);
                    145:     select.onInput.listen((h.Event event) {
                    146:       if (select.value == 'symbols' && getAttribute('mode') == 'units') {
                    147:         setAttribute('mode', 'symbols');
                    148:         input.setAttribute('data-unit_mode', 'false');
                    149:         js.context['LCMATH'].callMethod('initEditors');
                    150:       } else if (select.value == 'units' && getAttribute('mode') != 'units') {
                    151:         setAttribute('mode', 'units');
                    152:         input.setAttribute('data-unit_mode', 'true');
                    153:         js.context['LCMATH'].callMethod('initEditors');
                    154:       }
                    155:       input.focus();
                    156:     });
                    157:     editEl.append(select);
                    158:     el.replaceWith(editEl);
                    159:     input.focus();
                    160:     js.context['LCMATH'].callMethod('initEditors');
                    161:     var switchDisplay = () {
                    162:       String equationText = input.value;
                    163:       if (equationText != '') {
1.2     ! damieng   164:         if (firstChild != null) {
        !           165:           if (firstChild.nodeValue != equationText) {
        !           166:             UndoableEdit edit = new UndoableEdit.compound(Strings.get('undo.insert_text'));
        !           167:             edit.addSubEdit(new UndoableEdit.removeNode(firstChild));
        !           168:             edit.addSubEdit(new UndoableEdit.insertString(new Position(this, 0), equationText));
        !           169:             doc.doNewEdit(edit);
        !           170:           }
        !           171:         } else {
        !           172:           //doc.insertString(new Position(this, 0), equationText);
        !           173:           // We do not use an edit in this case, so that an undo does not bring back an empty equation.
        !           174:           // An undo will remove the lm element, because the only reason there can be
        !           175:           // no child is that the element just got inserted.
1.1       damieng   176:           appendChild(new DNText(equationText));
1.2     ! damieng   177:         }
        !           178:         editEl.replaceWith(html());
1.1       damieng   179:       } else {
1.2     ! damieng   180:         doc.removeNode(this);
1.1       damieng   181:       }
                    182:     };
                    183:     input.onBlur.listen((h.Event event) {
                    184:       Timer.run(() { // timer so that activeElement is updated
                    185:         if (h.document.activeElement == select)
                    186:           return;
                    187:         switchDisplay();
                    188:       });
                    189:     });
                    190:     select.onBlur.listen((h.Event event) {
                    191:       Timer.run(() {
                    192:         if (h.document.activeElement == input)
                    193:           return;
                    194:         switchDisplay();
                    195:       });
                    196:     });
                    197:     if (editEl is h.DivElement) {
                    198:       editEl.onClick.listen((h.MouseEvent event) {
                    199:         if (event.target != input && event.target != select) {
                    200:           page.moveCursorTo(new Position(parent, parent.offsetOf(this)+1));
                    201:         }
                    202:       });
                    203:     }
                    204:     input.onKeyDown.listen((h.KeyboardEvent event) {
1.2     ! damieng   205:       if (event.keyCode == h.KeyCode.ENTER) {
        !           206:         event.preventDefault();
        !           207:         input.blur();
        !           208:         return;
        !           209:       }
1.1       damieng   210:       String equationText = input.value;
                    211:       int inputSize = input.size;
                    212:       if (equationText != null && equationText.length > inputSize)
                    213:         input.size = equationText.length;
                    214:     });
                    215:   }
                    216: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>