Annotation of modules/damieng/graphical_editor/loncapa_daxe/web/nodes/chem.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:  * Display for the chem element.
                     22:  * Jaxe display type: 'chem'.
                     23:  */
                     24: class Chem extends DNString {
                     25:   bool preview;
                     26:   StreamSubscription<h.MouseEvent> listener = null;
                     27:   
                     28:   Chem.fromRef(x.Element elementRef) : super.fromRef(elementRef) {
                     29:     preview = false;
                     30:   }
                     31:   
                     32:   Chem.fromNode(x.Node node, DaxeNode parent) : super.fromNode(node, parent) {
                     33:     preview = previewIsPossible();
                     34:   }
                     35:   
                     36:   bool previewIsPossible() {
                     37:     return (firstChild is DNText && !firstChild.nodeValue.trim().startsWith('\$'));
                     38:   }
                     39:   
                     40:   @override
                     41:   h.Element html() {
                     42:     if (!preview) {
                     43:       if (listener == null)
                     44:         listener = h.document.onClick.listen((h.MouseEvent e) => onClick(e));
                     45:       return super.html();
                     46:     }
                     47:     h.SpanElement span = new h.SpanElement();
                     48:     span.id = "$id";
                     49:     span.classes.add('dn');
                     50:     if (!valid)
                     51:       span.classes.add('invalid');
                     52:     String text = firstChild.nodeValue.trim();
                     53:     span.setInnerHtml(Chem.textToHTML(text));
                     54:     span.onClick.listen((h.MouseEvent e) {
                     55:       preview = false;
                     56:       updateHTML();
1.3     ! damieng    57:       // prevent calling onClick(e):
        !            58:       // (it could switch back to preview mode if the element takes more
        !            59:       // space and moves to the next line after switching to non-preview).
        !            60:       e.stopPropagation();
        !            61:       e.preventDefault();
        !            62:       // but set cursor inside:
        !            63:       page.moveCursorTo(new Position(this, this.offsetLength));
1.1       damieng    64:     });
1.2       damieng    65:     setupDrag(span);
1.1       damieng    66:     return(span);
                     67:   }
                     68:   
                     69:   void onClick(h.MouseEvent e) {
                     70:     if (!previewIsPossible())
                     71:       return; // NOTE: that will generate a lot of events for nothing when variables are used...
                     72:     h.Element node = getHTMLNode();
                     73:     if (node == null) {
                     74:       listener.cancel();
                     75:       listener = null;
                     76:       return;
                     77:     }
                     78:     h.Rectangle r = node.getBoundingClientRect(); // could be more precise with getClientRects
1.3     ! damieng    79:     if (!r.containsPoint(e.client)) {
        !            80:       listener.cancel();
        !            81:       listener = null;
        !            82:       preview = true;
        !            83:       updateHTML();
        !            84:       e.stopPropagation();
        !            85:       e.preventDefault();
        !            86:       page.cursor.refresh();
        !            87:     }
1.1       damieng    88:   }
                     89:   
                     90:   @override
                     91:   h.Element getHTMLContentsNode() {
                     92:     if (!preview)
                     93:       return super.getHTMLContentsNode();
                     94:     return(getHTMLNode());
                     95:   }
                     96: 
                     97:   @override
                     98:   Position firstCursorPositionInside() {
                     99:     if (!preview)
                    100:       return super.firstCursorPositionInside();
                    101:     return(null);
                    102:   }
                    103:   
                    104:   @override
                    105:   Position lastCursorPositionInside() {
                    106:     if (!preview)
                    107:       return super.lastCursorPositionInside();
                    108:     return(null);
                    109:   }
                    110:   
                    111:   static String textToHTML(String reaction) {
                    112:     // this is doing the same thing as chemparse, except it uses UNICODE characters instead of LaTeX
                    113:     //List<String> tokens = reaction.split(new RegExp(r"(\s\+|\->|<=>|<\-|\.)"));
                    114:     // this did not work (delimiters are not preserved)
                    115:     // using look-ahead/behind does not work either...
                    116:     List<String> tokens = getTokensWithDelimiters(reaction, new RegExp(r"(\s\+|\->|<=>|<\-|\.)"));
                    117:     String formula = '';
                    118:     for (int i=0; i<tokens.length; i++) {
                    119:         String token = tokens[i];
                    120:         if (token == '->' ) {
                    121:             formula += '&#8594; ';
                    122:             continue;
                    123:         }
                    124:         if (token == '<-' ) {
                    125:             formula += '&#8592; ';
                    126:             continue;
                    127:         }  
                    128:         if (token == '<=>') {
                    129:             formula += '&#8652; ';
                    130:             continue;
                    131:         }
                    132:         if (token == '.') {
                    133:           formula = formula.replaceFirst(new RegExp(r"&nbsp;| "), '');
                    134:           formula += '&middot;';
                    135:           continue;
                    136:         }
                    137:         Iterable<Match> matches = new RegExp(r"^\s*([\d|\/]*(?:&frac\d\d)?)(.*)").allMatches(token);
                    138:         String molecule;
                    139:         if (matches.length > 0) {
                    140:           Match firstMatch = matches.first;
                    141:           if (firstMatch.group(1) != null)
                    142:             formula += firstMatch.group(1); // stoichiometric coefficient
                    143:           if (firstMatch.group(2) != null)
                    144:             molecule = firstMatch.group(2);
                    145:           else
                    146:             molecule = '';
                    147:         } else
                    148:           molecule = '';
                    149:         // subscripts
                    150:         // $molecule =~ s|(?<=[a-zA-Z\)\]\s])(\d+)|<sub>$1</sub>|g;
                    151:         // Javascript does not support look-behind like Perl
                    152:         molecule = molecule.replaceAllMapped(new RegExp(r"([a-zA-Z\)\]\s])(\d+)"), (Match m) => "${m[1]}<sub>${m[2]}</sub>");
                    153:         // superscripts
                    154:         molecule = molecule.replaceAllMapped(new RegExp(r"\^(\d*[+\-]*)"), (Match m) => "<sup>${m[1]}</sup>");
                    155:         // strip whitespace
                    156:         molecule = molecule.replaceAll(new RegExp(r"\s*"), '');
                    157:         // forced space
                    158:         molecule = molecule.replaceAll('_', ' ');
                    159:         molecule = molecule.replaceAll('-', '&minus;');
                    160:         formula += molecule + '&nbsp;';
                    161:     }
                    162:     // get rid of trailing space
                    163:     formula = formula.replaceFirst(new RegExp(r"(&nbsp;| )$"), '');
                    164:     return formula;
                    165:   }
                    166:   
                    167:   static List<String> getTokensWithDelimiters(String s, Pattern p) {
                    168:     int start = 0;
                    169:     int ind = s.indexOf(p, start);
                    170:     List<String> list = new List<String>();
                    171:     while (ind >= 0) {
                    172:       if (ind > 0)
                    173:         list.add(s.substring(start, ind));
                    174:       Match m = p.matchAsPrefix(s, ind);
                    175:       String delimiter = m.group(0);
                    176:       list.add(delimiter);
                    177:       start = ind + delimiter.length;
                    178:       ind = s.indexOf(p, start);
                    179:     }
                    180:     if (start < s.length)
                    181:       list.add(s.substring(start));
                    182:     return list;
                    183:   }
                    184: }

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