Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Side by Side Diff: sky/examples/terminal/terminal.sky

Issue 1032743002: A crappy "netcat"-type example (in Dart). (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « examples/dart/netcat/main.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 <!-- 1 <!--
2 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Copyright 2015 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be 3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file. 4 // found in the LICENSE file.
5 --> 5 -->
6 <import src="/sky/framework/elements/sky-element.sky" /> 6 <import src="/sky/framework/elements/sky-element.sky" />
7 <import src="/sky/framework/elements/sky-scrollable.sky" />
8 <sky-element> 7 <sky-element>
9 <template> 8 <template>
10 <style> 9 <style>
11 #control { 10 #container {
12 height: -webkit-fill-available; 11 height: -webkit-fill-available;
12 }
13 #input-box {
14 position: absolute;
15 left: 0;
16 top: 0;
17 z-index: 10;
18 width: 100%;
19 height: 100%;
20 opacity: 0;
21 }
22 #output-box {
23 position: absolute;
24 left: 0;
25 top: 0;
26 z-index: 0;
27 width: 100%;
28 height: 100%;
13 background-color: black; 29 background-color: black;
14 color: rgb(255, 191, 0); 30 color: rgb(255, 191, 0);
15 font-family: 'Courier', 'monospace'; 31 font-family: 'Courier', 'monospace';
16 font-size: small; 32 font-size: small;
17 } 33 }
18 .line { 34 .line {
35 height: 1em;
19 white-space: nowrap; 36 white-space: nowrap;
20 } 37 }
21 </style> 38 </style>
22 <sky-scrollable id="control" contenteditable /> 39 <div id="container">
40 <div id="input-box" contenteditable />
41 <div id="output-box" />
42 </div>
43 </div>
23 </template> 44 </template>
24 <script> 45 <script>
25 import 'dart:async'; 46 import 'dart:async';
26 import 'dart:core'; 47 import 'dart:core';
27 import 'dart:sky'; 48 import 'dart:sky';
28 import 'package:mojo/services/terminal/public/interfaces/terminal_client.mojom.d art' as terminal; 49 import 'package:mojo/services/terminal/public/interfaces/terminal_client.mojom.d art' as terminal;
29 import 'package:sky/framework/embedder.dart'; 50 import 'package:sky/framework/embedder.dart';
30 import 'terminal_display.dart'; 51 import 'terminal_display.dart';
31 import 'terminal_file_impl.dart'; 52 import 'terminal_file_impl.dart';
32 53
33 // Implements the <terminal> element, which implements a "terminal display". Has 54 // Implements the <terminal> element, which implements a "terminal display". Has
34 // an |url| attribute, whose value should be a Mojo app that provides the 55 // an |url| attribute, whose value should be a Mojo app that provides the
35 // |terminal.TerminalClient| service. 56 // |terminal.TerminalClient| service.
36 @Tagname('terminal') 57 @Tagname('terminal')
37 class TerminalDisplayImpl extends SkyElement implements TerminalDisplay { 58 class TerminalDisplayImpl extends SkyElement implements TerminalDisplay {
38 Element _control; 59 Element _inputBox;
60 Element _outputBox;
61 int _maxLines;
39 62
40 // Queue of unconsumed input (keystrokes), with the head at index 0. 63 // Queue of unconsumed input (keystrokes), with the head at index 0.
41 // Keystrokes end up here if there's no reader (i.e., |getChar()|) pending, 64 // Keystrokes end up here if there's no reader (i.e., |getChar()|) pending,
42 // i.e., if |_readerQueue| is empty. Invariant: At most one of |_inputQueue| 65 // i.e., if |_readerQueue| is empty. Invariant: At most one of |_inputQueue|
43 // and |_readerQueue| may be nonempty at any given time. 66 // and |_readerQueue| may be nonempty at any given time.
44 List<int> _inputQueue; 67 List<int> _inputQueue;
45 68
46 // Queue of things waiting for input, with the head at index 0. If a keystroke 69 // Queue of things waiting for input, with the head at index 0. If a keystroke
47 // is received and this is nonempty, the head is given that keystroke (and 70 // is received and this is nonempty, the head is given that keystroke (and
48 // dequeued). 71 // dequeued).
49 List<Completer<int>> _readerQueue; 72 List<Completer<int>> _readerQueue;
50 73
51 TerminalDisplayImpl() 74 TerminalDisplayImpl()
52 : _inputQueue = new List<int>(), 75 : _inputQueue = new List<int>(),
53 _readerQueue = new List<Completer<int>>() { 76 _readerQueue = new List<Completer<int>>() {
54 } 77 }
55 78
56 void shadowRootReady() { 79 void shadowRootReady() {
57 _control = shadowRoot.getElementById('control'); 80 _inputBox = shadowRoot.getElementById('input-box');
58 _control.addEventListener('keydown', _handleKeyDown); 81 _inputBox.addEventListener('keydown', _handleKeyDown);
59 _control.addEventListener('keypress', _handleKeyPress); 82 _inputBox.addEventListener('keypress', _handleKeyPress);
83 _inputBox.addEventListener('wheel', _handleWheel);
84 _outputBox = shadowRoot.getElementById('output-box');
85
86 // Hack to allow |_newLine()| to work.
87 _maxLines = 100;
60 88
61 // Initialize with the first line. 89 // Initialize with the first line.
62 _newLine(); 90 _newLine();
63 91
92 // Actually compute the maximum number of lines.
93 // TODO(vtl): Recompute on resize.
94 _maxLines = _outputBox.clientHeight ~/ _outputBox.firstChild.offsetHeight;
95
64 var url = getAttribute('url'); 96 var url = getAttribute('url');
65 if (url != null) { 97 if (url != null) {
66 connect(url); 98 connect(url);
67 } 99 }
68 } 100 }
69 101
70 void _handleKeyDown(KeyboardEvent event) { 102 void _handleKeyDown(KeyboardEvent event) {
71 // TODO(vtl): In general, our key handling is a total hack (due in part to 103 // TODO(vtl): In general, our key handling is a total hack (due in part to
72 // sky's keyboard support being incomplete) -- e.g., we shouldn't have to 104 // sky's keyboard support being incomplete) -- e.g., we shouldn't have to
73 // make our div contenteditable. We have to intercept backspace (^H) here, 105 // make our div contenteditable. We have to intercept backspace (^H) here,
74 // since we won't actually get a keypress event for it. (Possibly, we should 106 // since we won't actually get a keypress event for it. (Possibly, we should
75 // only handle keydown instead of keypress, but then we'd have to handle 107 // only handle keydown instead of keypress, but then we'd have to handle
76 // shift, etc. ourselves.) 108 // shift, etc. ourselves.)
77 if (event.key == 8) { 109 if (event.key == 8) {
78 _enqueueChar(8); 110 _enqueueChar(8);
79 event.preventDefault(); 111 event.preventDefault();
80 } 112 }
81 } 113 }
82 114
83 void _handleKeyPress(KeyboardEvent event) { 115 void _handleKeyPress(KeyboardEvent event) {
84 _enqueueChar(event.charCode); 116 if (event.charCode != 0) {
117 _enqueueChar(event.charCode);
118 }
85 event.preventDefault(); 119 event.preventDefault();
86 } 120 }
87 121
122 void _handleWheel(WheelEvent event) {
123 _outputBox.dispatchEvent(event);
124 }
125
88 void _enqueueChar(int charCode) { 126 void _enqueueChar(int charCode) {
89 // TODO(vtl): Add "echo" mode; do |putChar(event.charCode);| if echo is on. 127 // TODO(vtl): Add "echo" mode; do |putChar(event.charCode);| if echo is on.
90 128
91 if (_readerQueue.isEmpty) { 129 if (_readerQueue.isEmpty) {
92 _inputQueue.add(charCode); 130 _inputQueue.add(charCode);
93 } else { 131 } else {
94 _readerQueue.removeAt(0).complete(charCode); 132 _readerQueue.removeAt(0).complete(charCode);
95 } 133 }
96 } 134 }
97 135
98 void _backspace() { 136 void _backspace() {
99 var oldText = _control.lastChild.textContent; 137 var oldText = _outputBox.lastChild.textContent;
100 if (oldText.length > 0) { 138 if (oldText.length > 0) {
101 _control.lastChild.textContent = oldText.substring(0, oldText.length - 1); 139 _outputBox.lastChild.textContent = oldText.substring(0,
140 oldText.length - 1);
102 } 141 }
103 } 142 }
104 143
105 void _newLine() { 144 void _newLine() {
106 var line = document.createElement('div'); 145 var line = document.createElement('div');
107 line.setAttribute('class', 'line'); 146 line.setAttribute('class', 'line');
108 _control.appendChild(line); 147 _outputBox.appendChild(line);
148
149 // Scroll if necessary.
150 var children = _outputBox.getChildNodes();
151 if (children.length > _maxLines) {
152 children = new List.from(children.skip(children.length - _maxLines));
153 _outputBox.setChildren(children);
154 }
109 } 155 }
110 156
111 void _clear() { 157 void _clear() {
112 while (_control.firstChild != null) { 158 _outputBox.setChildren([]);
113 _control.firstChild.remove();
114 }
115 _newLine(); 159 _newLine();
116 } 160 }
117 161
118 void connect(String url) { 162 void connect(String url) {
119 var terminalClient = new terminal.TerminalClientProxy.unbound(); 163 var terminalClient = new terminal.TerminalClientProxy.unbound();
120 embedder.connectToService(url, terminalClient); 164 embedder.connectToService(url, terminalClient);
121 terminalClient.ptr.connectToTerminal(new TerminalFileImpl(this).stub); 165 terminalClient.ptr.connectToTerminal(new TerminalFileImpl(this).stub);
122 terminalClient.close(); 166 terminalClient.close();
123 } 167 }
124 168
125 void putString(String s) { 169 void putString(String s) {
126 for (var i = 0; i < s.length; i++) { 170 for (var i = 0; i < s.length; i++) {
127 putChar(s.codeUnitAt(i)); 171 putChar(s.codeUnitAt(i));
128 } 172 }
129 } 173 }
130 174
131 // |TerminalDisplay| implementation: 175 // |TerminalDisplay| implementation:
132 176
133 @override 177 @override
134 void putChar(int byte) { 178 void putChar(int byte) {
135 // Fast-path for printable chars. 179 // Fast-path for printable chars.
136 if (byte >= 32) { 180 if (byte >= 32) {
137 _control.lastChild.textContent += new String.fromCharCode(byte); 181 _outputBox.lastChild.textContent += new String.fromCharCode(byte);
138 return; 182 return;
139 } 183 }
140 184
141 switch (byte) { 185 switch (byte) {
142 case 8: // BS (^H). 186 case 8: // BS (^H).
143 _backspace(); 187 _backspace();
144 break; 188 break;
145 case 10: // LF ('\n'). 189 case 10: // LF ('\n').
146 _newLine(); // TODO(vtl): LF and CR should be separated. 190 _newLine(); // TODO(vtl): LF and CR should be separated.
147 break; 191 break;
(...skipping 17 matching lines...) Expand all
165 209
166 var completer = new Completer<int>(); 210 var completer = new Completer<int>();
167 _readerQueue.add(completer); 211 _readerQueue.add(completer);
168 return completer.future; 212 return completer.future;
169 } 213 }
170 } 214 }
171 215
172 _init(script) => register(script, TerminalDisplayImpl); 216 _init(script) => register(script, TerminalDisplayImpl);
173 </script> 217 </script>
174 </sky-element> 218 </sky-element>
OLDNEW
« no previous file with comments | « examples/dart/netcat/main.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698