| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library eval_box_element; | 5 library eval_box_element; |
| 6 | 6 |
| 7 import 'dart:html'; |
| 7 import 'dart:async'; | 8 import 'dart:async'; |
| 8 import 'dart:html'; | 9 import 'package:observatory/models.dart' as M; |
| 9 import 'observatory_element.dart'; | 10 import 'package:observatory/src/elements/helpers/any_ref.dart'; |
| 10 import 'package:polymer/polymer.dart'; | 11 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| 12 import 'package:observatory/src/elements/helpers/tag.dart'; |
| 13 import 'package:observatory/src/elements/instance_ref.dart'; |
| 11 | 14 |
| 15 class EvalBoxElement extends HtmlElement implements Renderable { |
| 16 static const tag = const Tag<EvalBoxElement>('eval-box-wrapped', |
| 17 dependencies: const [ |
| 18 InstanceRefElement.tag |
| 19 ]); |
| 12 | 20 |
| 13 typedef Future evalType(String text); | 21 RenderingScheduler<EvalBoxElement> _r; |
| 14 | 22 |
| 23 Stream<RenderedEvent<EvalBoxElement>> get onRendered => _r.onRendered; |
| 15 | 24 |
| 16 @CustomTag('eval-box') | 25 M.IsolateRef _isolate; |
| 17 class EvalBoxElement extends ObservatoryElement { | 26 M.ObjectRef _context; |
| 18 @observable String text; | 27 M.InstanceRepository _instances; |
| 19 @observable String lineMode = "1-line"; | 28 M.EvalRepository _eval; |
| 20 int _exprCount = 0; | 29 final _results = <_ExpressionDescription>[]; |
| 30 String _expression = ''; |
| 31 bool _multiline; |
| 21 | 32 |
| 22 @published evalType callback; | 33 M.IsolateRef get isolate => _isolate; |
| 23 @observable ObservableList results = toObservable([]); | 34 M.ObjectRef get context => _context; |
| 24 | 35 |
| 25 void updateLineMode(Event e, var detail, Node target) { | 36 factory EvalBoxElement(M.IsolateRef isolate, M.ObjectRef context, |
| 26 lineMode = (e.target as InputElement).value; | 37 M.InstanceRepository instances, |
| 27 if (lineMode == '1-line' && text != null) { | 38 M.EvalRepository eval, |
| 28 text = text.replaceAll('\n', ' '); | 39 {bool multiline: false, RenderingQueue queue}) { |
| 29 } | 40 assert(isolate != null); |
| 30 } | 41 assert(context != null); |
| 31 | 42 assert(instances != null); |
| 32 void evaluate(Event e, var detail, Node target) { | 43 assert(eval != null); |
| 33 // Prevent any form action. | 44 assert(multiline != null); |
| 34 e.preventDefault(); | 45 EvalBoxElement e = document.createElement(tag.name); |
| 35 | 46 e._r = new RenderingScheduler(e, queue: queue); |
| 36 // Clear the text box. | 47 e._isolate = isolate; |
| 37 var expr = text; | 48 e._context = context; |
| 38 text = ''; | 49 e._instances = instances; |
| 39 | 50 e._eval = eval; |
| 40 // Use provided callback to eval the expression. | 51 e._multiline = multiline; |
| 41 if (callback != null) { | 52 return e; |
| 42 var map = toObservable({}); | |
| 43 map['id'] = (_exprCount++).toString(); | |
| 44 map['expr'] = expr; | |
| 45 results.insert(0, map); | |
| 46 callback(expr).then((result) { | |
| 47 map['value'] = result; | |
| 48 }).catchError((e, st) { | |
| 49 map['error'] = e.message; | |
| 50 app.handleException(e, st); | |
| 51 }); | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 void selectExpr(MouseEvent e) { | |
| 56 assert(e.target is Element); | |
| 57 Element targetElement = e.target; | |
| 58 text = targetElement.getAttribute('expr'); | |
| 59 } | |
| 60 | |
| 61 void closeItem(MouseEvent e) { | |
| 62 assert(e.target is Element); | |
| 63 Element targetElement = e.target; | |
| 64 var closeId = targetElement.getAttribute('closeId'); | |
| 65 results.removeWhere((item) => item['id'] == closeId); | |
| 66 } | 53 } |
| 67 | 54 |
| 68 EvalBoxElement.created() : super.created(); | 55 EvalBoxElement.created() : super.created(); |
| 56 |
| 57 @override |
| 58 void attached() { |
| 59 super.attached(); |
| 60 _r.enable(); |
| 61 } |
| 62 |
| 63 @override |
| 64 void detached() { |
| 65 super.detached(); |
| 66 _r.disable(notify: true); |
| 67 children = []; |
| 68 _results.clear(); |
| 69 } |
| 70 |
| 71 void render() { |
| 72 children = [ |
| 73 new DivElement()..classes = const ['heading'] |
| 74 ..children = [ |
| 75 new FormElement() |
| 76 ..autocomplete = 'on' |
| 77 ..children = [ |
| 78 _multiline ? _createEvalTextArea() : _createEvalTextBox(), |
| 79 new SpanElement()..classes = const ['buttons'] |
| 80 ..children = [ |
| 81 _createEvalButton(), |
| 82 _createMultilineCheckbox(), |
| 83 new SpanElement()..text = 'multi-line' |
| 84 ] |
| 85 ] |
| 86 ], |
| 87 new TableElement() |
| 88 ..children = _results.reversed.map((result) => |
| 89 new TableRowElement() |
| 90 ..children = [ |
| 91 new TableCellElement()..classes = const ['historyExpr'] |
| 92 ..children = [ |
| 93 new ButtonElement()..text = result.expression |
| 94 ..onClick.listen((_) { |
| 95 _expression = result.expression; |
| 96 _r.dirty(); |
| 97 }) |
| 98 ], |
| 99 new TableCellElement()..classes = const ['historyValue'] |
| 100 ..children = [ |
| 101 result.isPending |
| 102 ? (new SpanElement()..text = 'Pending...') |
| 103 : anyRef(_isolate, result.value, _instances, |
| 104 queue: _r.queue) |
| 105 ], |
| 106 new TableCellElement()..classes = const ['historyDelete'] |
| 107 ..children = [ |
| 108 new ButtonElement()..text = '✖ Remove' |
| 109 ..onClick.listen((_) { |
| 110 _results.remove(result); |
| 111 _r.dirty(); |
| 112 }) |
| 113 ] |
| 114 ]).toList() |
| 115 ]; |
| 116 } |
| 117 |
| 118 TextInputElement _createEvalTextArea() { |
| 119 var area = new TextAreaElement() |
| 120 ..classes = ['textbox'] |
| 121 ..placeholder = 'evaluate an expression' |
| 122 ..value = _expression |
| 123 ..onKeyUp |
| 124 .where((e) => e.key == '\n') |
| 125 .listen((e) { |
| 126 e.preventDefault(); |
| 127 _run(); |
| 128 }); |
| 129 area.onInput.listen((e) { |
| 130 _expression = area.value; |
| 131 }); |
| 132 return area; |
| 133 } |
| 134 |
| 135 TextInputElement _createEvalTextBox() { |
| 136 _expression = (_expression ?? '').split('\n')[0]; |
| 137 var textbox = new TextInputElement() |
| 138 ..classes = ['textbox'] |
| 139 ..placeholder = 'evaluate an expression' |
| 140 ..value = _expression |
| 141 ..onKeyUp |
| 142 .where((e) => e.key == '\n') |
| 143 .listen((e) { |
| 144 e.preventDefault(); |
| 145 _run(); |
| 146 }); |
| 147 textbox.onInput.listen((e) { |
| 148 _expression = textbox.value; |
| 149 }); |
| 150 return textbox; |
| 151 } |
| 152 |
| 153 ButtonElement _createEvalButton() { |
| 154 final button = new ButtonElement() |
| 155 ..text = 'evaluate' |
| 156 ..onClick.listen((e) { |
| 157 e.preventDefault(); |
| 158 _run(); |
| 159 }); |
| 160 return button; |
| 161 } |
| 162 |
| 163 CheckboxInputElement _createMultilineCheckbox() { |
| 164 final checkbox = new CheckboxInputElement() |
| 165 ..checked = _multiline; |
| 166 checkbox.onClick.listen((e) { |
| 167 e.preventDefault(); |
| 168 _multiline = checkbox.checked; |
| 169 _r.dirty(); |
| 170 }); |
| 171 return checkbox; |
| 172 } |
| 173 |
| 174 Future _run() async { |
| 175 if (_expression == null || _expression.isEmpty) return; |
| 176 final expression = _expression; |
| 177 _expression = null; |
| 178 final result = new _ExpressionDescription.pending(expression); |
| 179 _results.add(result); |
| 180 _r.dirty(); |
| 181 final index = _results.indexOf(result); |
| 182 _results[index] = new _ExpressionDescription(expression, |
| 183 await _eval.evaluate(_isolate, _context, expression)); |
| 184 _r.dirty(); |
| 185 } |
| 69 } | 186 } |
| 187 |
| 188 class _ExpressionDescription { |
| 189 final String expression; |
| 190 final M.ObjectRef value; |
| 191 bool get isPending => value == null; |
| 192 |
| 193 _ExpressionDescription(this.expression, this.value); |
| 194 _ExpressionDescription.pending(this.expression) |
| 195 : value = null; |
| 196 } |
| OLD | NEW |