OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 vm_connect_element; | 5 library vm_connect_element; |
6 | 6 |
| 7 import 'dart:html'; |
| 8 import 'dart:async'; |
7 import 'dart:convert'; | 9 import 'dart:convert'; |
8 import 'dart:html'; | 10 import 'package:observatory/models.dart' as M; |
| 11 import 'package:observatory/src/elements/helpers/tag.dart'; |
| 12 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| 13 import 'package:observatory/src/elements/nav/bar.dart'; |
| 14 import 'package:observatory/src/elements/nav/notify.dart'; |
| 15 import 'package:observatory/src/elements/nav/top_menu.dart'; |
| 16 import 'package:observatory/src/elements/view_footer.dart'; |
| 17 import 'package:observatory/src/elements/vm_connect_target.dart'; |
9 | 18 |
10 import 'observatory_element.dart'; | 19 class VMConnectElement extends HtmlElement implements Renderable{ |
11 import 'package:observatory/app.dart'; | 20 static const tag = const Tag<VMConnectElement>('vm-connect', |
12 import 'package:observatory/elements.dart'; | 21 dependencies: const [NavBarElement.tag, |
13 import 'package:observatory/service_html.dart'; | 22 NavTopMenuElement.tag, |
14 import 'package:polymer/polymer.dart'; | 23 NavNotifyElement.tag, |
| 24 ViewFooterElement.tag, |
| 25 VMConnectTargetElement.tag]); |
15 | 26 |
16 void _connectToVM(ObservatoryApplication app, WebSocketVMTarget target) { | 27 RenderingScheduler _r; |
17 app.vm = new WebSocketVM(target); | |
18 } | |
19 | 28 |
20 @CustomTag('vm-connect-target') | 29 Stream<RenderedEvent<VMConnectElement>> get onRendered => _r.onRendered; |
21 class VMConnectTargetElement extends ObservatoryElement { | |
22 @published WebSocketVMTarget target; | |
23 | 30 |
24 VMConnectTargetElement.created() : super.created(); | 31 M.DumpRepository _dump; |
| 32 M.NotificationRepository _notifications; |
| 33 M.TargetRepository _targets; |
| 34 StreamSubscription _targetsSubscription; |
25 | 35 |
26 bool get isCurrentTarget { | 36 String _address = ''; |
27 if (app.vm == null) { | 37 |
28 return false; | 38 factory VMConnectElement(M.TargetRepository targets, |
29 } | 39 M.DumpRepository dump, |
30 return (app.vm as WebSocketVM).target == target; | 40 M.NotificationRepository notifications, |
| 41 {RenderingQueue queue}) { |
| 42 assert(dump != null); |
| 43 assert(notifications != null); |
| 44 assert(targets != null); |
| 45 VMConnectElement e = document.createElement(tag.name); |
| 46 e._r = new RenderingScheduler(e, queue: queue); |
| 47 e._dump = dump; |
| 48 e._notifications = notifications; |
| 49 e._targets = targets; |
| 50 return e; |
31 } | 51 } |
32 | 52 |
33 void connectToVm(MouseEvent event, var detail, Element node) { | 53 VMConnectElement.created() : super.created(); |
34 if (event.button > 0 || event.metaKey || event.ctrlKey || | |
35 event.shiftKey || event.altKey) { | |
36 // Not a left-click or a left-click with a modifier key: | |
37 // Let browser handle. | |
38 return; | |
39 } | |
40 event.preventDefault(); | |
41 WebSocketVM currentVM = app.vm; | |
42 if ((currentVM == null) || | |
43 currentVM.isDisconnected || | |
44 (currentVM.target != target)) { | |
45 _connectToVM(app, target); | |
46 } | |
47 var href = node.attributes['href']; | |
48 app.locationManager.go(href); | |
49 } | |
50 | 54 |
51 void deleteVm(MouseEvent event, var detail, Element node) { | 55 @override |
52 app.targets.remove(target); | 56 void attached() { |
53 } | 57 super.attached(); _r.enable(); |
54 } | 58 _targetsSubscription = _targets.onChange.listen((_) => _r.dirty()); |
55 | |
56 @CustomTag('vm-connect') | |
57 class VMConnectElement extends ObservatoryElement { | |
58 @published String standaloneVmAddress = ''; | |
59 | |
60 VMConnectElement.created() : super.created() { | |
61 } | |
62 | |
63 void _connect(WebSocketVMTarget target) { | |
64 _connectToVM(app, target); | |
65 app.locationManager.goForwardingParameters('/vm'); | |
66 } | 59 } |
67 | 60 |
68 @override | 61 @override |
69 void attached() { | 62 void detached() { |
70 super.attached(); | 63 super.detached(); children = []; _r.disable(notify: true); |
71 var fileInput = shadowRoot.querySelector('#crashDumpFile'); | 64 _targetsSubscription.cancel(); _targetsSubscription = null; |
72 fileInput.onChange.listen(_onCrashDumpFileChange); | |
73 } | 65 } |
74 | 66 |
75 String _normalizeStandaloneAddress(String networkAddress) { | 67 void render() { |
| 68 children = [ |
| 69 new NavBarElement(queue: _r.queue) |
| 70 ..children = [ |
| 71 new NavTopMenuElement(last: true, queue: _r.queue), |
| 72 new NavNotifyElement(_notifications, queue: _r.queue) |
| 73 ], |
| 74 new DivElement() |
| 75 ..classes = ['content-centered'] |
| 76 ..children = [ |
| 77 new HeadingElement.h1()..text = 'Connect to a Dart VM', |
| 78 new BRElement(), new HRElement(), |
| 79 new DivElement() |
| 80 ..classes = ['flex-row'] |
| 81 ..children = [ |
| 82 new DivElement() |
| 83 ..classes = ['flex-item-40-percent'] |
| 84 ..children = [ |
| 85 new HeadingElement.h2()..text = 'WebSocket', |
| 86 new BRElement(), |
| 87 new UListElement() |
| 88 ..children = _targets.list().map((target) { |
| 89 return new LIElement() |
| 90 ..children = [new VMConnectTargetElement(target, |
| 91 current: target == _targets.current, queue: _r.queue) |
| 92 ..onConnect.listen(_connect) |
| 93 ..onDelete.listen(_delete) |
| 94 ]; |
| 95 }), |
| 96 new HRElement(), |
| 97 new FormElement() |
| 98 ..autocomplete = 'on' |
| 99 ..children = [ |
| 100 _createAddressBox(), |
| 101 new SpanElement()..text = ' ', |
| 102 new ButtonElement() |
| 103 ..text = 'Connect' |
| 104 ..onClick.listen((e) { |
| 105 e.preventDefault(); _create(); }), |
| 106 ], |
| 107 new BRElement(), |
| 108 new PreElement() |
| 109 ..classes = ['well'] |
| 110 ..text = 'Run Standalone with: \'--observe\'', |
| 111 new HRElement() |
| 112 ], |
| 113 new DivElement() |
| 114 ..classes = ['flex-item-20-percent'], |
| 115 new DivElement() |
| 116 ..classes = ['flex-item-40-percent'] |
| 117 ..children = [ |
| 118 new HeadingElement.h2()..text = 'Crash dump', |
| 119 new BRElement(), |
| 120 _createCrushDumpLoader(), |
| 121 new BRElement(), new BRElement(), |
| 122 new PreElement() |
| 123 ..classes = ['well'] |
| 124 ..text = 'Request a crash dump with:\n' |
| 125 '\'curl localhost:8181/_getCrashDump > dump.json\'', |
| 126 new HRElement() |
| 127 ] |
| 128 ], |
| 129 ], |
| 130 new ViewFooterElement(queue: _r.queue) |
| 131 ]; |
| 132 } |
| 133 |
| 134 TextInputElement _createAddressBox() { |
| 135 var textbox = new TextInputElement() |
| 136 ..classes = ['textbox'] |
| 137 ..placeholder = 'localhost:8181' |
| 138 ..value = _address; |
| 139 textbox.onChange.listen((e) { |
| 140 _address = textbox.value; |
| 141 }); |
| 142 return textbox; |
| 143 } |
| 144 |
| 145 FileUploadInputElement _createCrushDumpLoader() { |
| 146 FileUploadInputElement e = new FileUploadInputElement() |
| 147 ..id = 'crashDumpFile'; |
| 148 e.onChange.listen((_) { |
| 149 var reader = new FileReader(); |
| 150 reader.readAsText(e.files[0]); |
| 151 reader.onLoad.listen((_) { |
| 152 var crashDump = JSON.decode(reader.result); |
| 153 _dump.load(crashDump); |
| 154 }); |
| 155 }); |
| 156 return e; |
| 157 } |
| 158 void _create() { |
| 159 if (_address == null || _address.isEmpty) return; |
| 160 _targets.add(_normalizeStandaloneAddress(_address)); |
| 161 } |
| 162 void _connect(TargetEvent e) => _targets.setCurrent(e.target); |
| 163 void _delete(TargetEvent e) => _targets.delete(e.target); |
| 164 |
| 165 static String _normalizeStandaloneAddress(String networkAddress) { |
76 if (networkAddress.startsWith('ws://')) { | 166 if (networkAddress.startsWith('ws://')) { |
77 return networkAddress; | 167 return networkAddress; |
78 } | 168 } |
79 return 'ws://${networkAddress}/ws'; | 169 return 'ws://${networkAddress}/ws'; |
80 } | 170 } |
81 | |
82 void connectStandalone(Event e, var detail, Node target) { | |
83 // Prevent any form action. | |
84 e.preventDefault(); | |
85 if (standaloneVmAddress == null) { | |
86 return; | |
87 } | |
88 if (standaloneVmAddress.isEmpty) { | |
89 return; | |
90 } | |
91 var targetAddress = _normalizeStandaloneAddress(standaloneVmAddress); | |
92 var target = app.targets.findOrMake(targetAddress); | |
93 _connect(target); | |
94 } | |
95 | |
96 _onCrashDumpFileChange(e) { | |
97 var fileInput = shadowRoot.querySelector('#crashDumpFile'); | |
98 var reader = new FileReader(); | |
99 reader.readAsText(fileInput.files[0]); | |
100 reader.onLoad.listen((_) { | |
101 var crashDump = JSON.decode(reader.result); | |
102 app.loadCrashDump(crashDump); | |
103 }); | |
104 } | |
105 } | 171 } |
OLD | NEW |