Index: runtime/observatory/lib/src/elements/vm_connect.dart |
diff --git a/runtime/observatory/lib/src/elements/vm_connect.dart b/runtime/observatory/lib/src/elements/vm_connect.dart |
index 5d42edc4e8a6ad17a1bfd1cb6ee49e21654b4214..e197d54d5384571f77396752a1b435734f274051 100644 |
--- a/runtime/observatory/lib/src/elements/vm_connect.dart |
+++ b/runtime/observatory/lib/src/elements/vm_connect.dart |
@@ -4,102 +4,168 @@ |
library vm_connect_element; |
-import 'dart:convert'; |
import 'dart:html'; |
+import 'dart:async'; |
+import 'dart:convert'; |
+import 'package:observatory/models.dart' as M; |
+import 'package:observatory/src/elements/helpers/tag.dart'; |
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
+import 'package:observatory/src/elements/nav/bar.dart'; |
+import 'package:observatory/src/elements/nav/notify.dart'; |
+import 'package:observatory/src/elements/nav/top_menu.dart'; |
+import 'package:observatory/src/elements/view_footer.dart'; |
+import 'package:observatory/src/elements/vm_connect_target.dart'; |
+ |
+class VMConnectElement extends HtmlElement implements Renderable{ |
+ static const tag = const Tag<VMConnectElement>('vm-connect', |
+ dependencies: const [NavBarElement.tag, |
+ NavTopMenuElement.tag, |
+ NavNotifyElement.tag, |
+ ViewFooterElement.tag, |
+ VMConnectTargetElement.tag]); |
+ |
+ RenderingScheduler _r; |
+ |
+ Stream<RenderedEvent<VMConnectElement>> get onRendered => _r.onRendered; |
+ |
+ M.DumpRepository _dump; |
+ M.NotificationRepository _notifications; |
+ M.TargetRepository _targets; |
+ StreamSubscription _targetsSubscription; |
+ |
+ String _address = ''; |
+ |
+ factory VMConnectElement(M.TargetRepository targets, |
+ M.DumpRepository dump, |
+ M.NotificationRepository notifications, |
+ {RenderingQueue queue}) { |
+ assert(dump != null); |
+ assert(notifications != null); |
+ assert(targets != null); |
+ VMConnectElement e = document.createElement(tag.name); |
+ e._r = new RenderingScheduler(e, queue: queue); |
+ e._dump = dump; |
+ e._notifications = notifications; |
+ e._targets = targets; |
+ return e; |
+ } |
-import 'observatory_element.dart'; |
-import 'package:observatory/app.dart'; |
-import 'package:observatory/elements.dart'; |
-import 'package:observatory/service_html.dart'; |
-import 'package:polymer/polymer.dart'; |
- |
-void _connectToVM(ObservatoryApplication app, WebSocketVMTarget target) { |
- app.vm = new WebSocketVM(target); |
-} |
- |
-@CustomTag('vm-connect-target') |
-class VMConnectTargetElement extends ObservatoryElement { |
- @published WebSocketVMTarget target; |
- |
- VMConnectTargetElement.created() : super.created(); |
+ VMConnectElement.created() : super.created(); |
- bool get isCurrentTarget { |
- if (app.vm == null) { |
- return false; |
- } |
- return (app.vm as WebSocketVM).target == target; |
+ @override |
+ void attached() { |
+ super.attached(); _r.enable(); |
+ _targetsSubscription = _targets.onChange.listen((_) => _r.dirty()); |
} |
- void connectToVm(MouseEvent event, var detail, Element node) { |
- if (event.button > 0 || event.metaKey || event.ctrlKey || |
- event.shiftKey || event.altKey) { |
- // Not a left-click or a left-click with a modifier key: |
- // Let browser handle. |
- return; |
- } |
- event.preventDefault(); |
- WebSocketVM currentVM = app.vm; |
- if ((currentVM == null) || |
- currentVM.isDisconnected || |
- (currentVM.target != target)) { |
- _connectToVM(app, target); |
- } |
- var href = node.attributes['href']; |
- app.locationManager.go(href); |
+ @override |
+ void detached() { |
+ super.detached(); children = []; _r.disable(notify: true); |
+ _targetsSubscription.cancel(); _targetsSubscription = null; |
} |
- void deleteVm(MouseEvent event, var detail, Element node) { |
- app.targets.remove(target); |
+ void render() { |
+ children = [ |
+ new NavBarElement(queue: _r.queue) |
+ ..children = [ |
+ new NavTopMenuElement(last: true, queue: _r.queue), |
+ new NavNotifyElement(_notifications, queue: _r.queue) |
+ ], |
+ new DivElement() |
+ ..classes = ['content-centered'] |
+ ..children = [ |
+ new HeadingElement.h1()..text = 'Connect to a Dart VM', |
+ new BRElement(), new HRElement(), |
+ new DivElement() |
+ ..classes = ['flex-row'] |
+ ..children = [ |
+ new DivElement() |
+ ..classes = ['flex-item-40-percent'] |
+ ..children = [ |
+ new HeadingElement.h2()..text = 'WebSocket', |
+ new BRElement(), |
+ new UListElement() |
+ ..children = _targets.list().map((target) { |
+ return new LIElement() |
+ ..children = [new VMConnectTargetElement(target, |
+ current: target == _targets.current, queue: _r.queue) |
+ ..onConnect.listen(_connect) |
+ ..onDelete.listen(_delete) |
+ ]; |
+ }), |
+ new HRElement(), |
+ new FormElement() |
+ ..autocomplete = 'on' |
+ ..children = [ |
+ _createAddressBox(), |
+ new SpanElement()..text = ' ', |
+ new ButtonElement() |
+ ..text = 'Connect' |
+ ..onClick.listen((e) { |
+ e.preventDefault(); _create(); }), |
+ ], |
+ new BRElement(), |
+ new PreElement() |
+ ..classes = ['well'] |
+ ..text = 'Run Standalone with: \'--observe\'', |
+ new HRElement() |
+ ], |
+ new DivElement() |
+ ..classes = ['flex-item-20-percent'], |
+ new DivElement() |
+ ..classes = ['flex-item-40-percent'] |
+ ..children = [ |
+ new HeadingElement.h2()..text = 'Crash dump', |
+ new BRElement(), |
+ _createCrushDumpLoader(), |
+ new BRElement(), new BRElement(), |
+ new PreElement() |
+ ..classes = ['well'] |
+ ..text = 'Request a crash dump with:\n' |
+ '\'curl localhost:8181/_getCrashDump > dump.json\'', |
+ new HRElement() |
+ ] |
+ ], |
+ ], |
+ new ViewFooterElement(queue: _r.queue) |
+ ]; |
} |
-} |
-@CustomTag('vm-connect') |
-class VMConnectElement extends ObservatoryElement { |
- @published String standaloneVmAddress = ''; |
- |
- VMConnectElement.created() : super.created() { |
+ TextInputElement _createAddressBox() { |
+ var textbox = new TextInputElement() |
+ ..classes = ['textbox'] |
+ ..placeholder = 'localhost:8181' |
+ ..value = _address; |
+ textbox.onChange.listen((e) { |
+ _address = textbox.value; |
+ }); |
+ return textbox; |
} |
- void _connect(WebSocketVMTarget target) { |
- _connectToVM(app, target); |
- app.locationManager.goForwardingParameters('/vm'); |
+ FileUploadInputElement _createCrushDumpLoader() { |
+ FileUploadInputElement e = new FileUploadInputElement() |
+ ..id = 'crashDumpFile'; |
+ e.onChange.listen((_) { |
+ var reader = new FileReader(); |
+ reader.readAsText(e.files[0]); |
+ reader.onLoad.listen((_) { |
+ var crashDump = JSON.decode(reader.result); |
+ _dump.load(crashDump); |
+ }); |
+ }); |
+ return e; |
} |
- |
- @override |
- void attached() { |
- super.attached(); |
- var fileInput = shadowRoot.querySelector('#crashDumpFile'); |
- fileInput.onChange.listen(_onCrashDumpFileChange); |
+ void _create() { |
+ if (_address == null || _address.isEmpty) return; |
+ _targets.add(_normalizeStandaloneAddress(_address)); |
} |
+ void _connect(TargetEvent e) => _targets.setCurrent(e.target); |
+ void _delete(TargetEvent e) => _targets.delete(e.target); |
- String _normalizeStandaloneAddress(String networkAddress) { |
+ static String _normalizeStandaloneAddress(String networkAddress) { |
if (networkAddress.startsWith('ws://')) { |
return networkAddress; |
} |
return 'ws://${networkAddress}/ws'; |
} |
- |
- void connectStandalone(Event e, var detail, Node target) { |
- // Prevent any form action. |
- e.preventDefault(); |
- if (standaloneVmAddress == null) { |
- return; |
- } |
- if (standaloneVmAddress.isEmpty) { |
- return; |
- } |
- var targetAddress = _normalizeStandaloneAddress(standaloneVmAddress); |
- var target = app.targets.findOrMake(targetAddress); |
- _connect(target); |
- } |
- |
- _onCrashDumpFileChange(e) { |
- var fileInput = shadowRoot.querySelector('#crashDumpFile'); |
- var reader = new FileReader(); |
- reader.readAsText(fileInput.files[0]); |
- reader.onLoad.listen((_) { |
- var crashDump = JSON.decode(reader.result); |
- app.loadCrashDump(crashDump); |
- }); |
- } |
} |