Annotation of modules/damieng/graphical_editor/loncapa_daxe/web/nodes/lm.dart, revision 1.3
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: select.append(symbolsOption);
137: h.OptionElement unitsOption = new h.OptionElement();
138: unitsOption.value = 'units';
139: unitsOption.appendText(LCDStrings.get('lm_units'));
1.3 ! damieng 140: select.append(unitsOption);
1.1 damieng 141: if (getAttribute('mode') == 'units')
1.3 ! damieng 142: select.value = 'units';
! 143: else
! 144: select.value = 'symbols';
! 145: select.onChange.listen((h.Event event) {
1.1 damieng 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>