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 trydart.interaction_manager; | 5 library trydart.interaction_manager; |
6 | 6 |
7 import 'dart:html'; | 7 import 'dart:html'; |
8 | 8 |
9 import 'dart:convert' show | 9 import 'dart:convert' show |
10 JSON; | 10 JSON; |
11 | 11 |
12 import 'dart:math' show | 12 import 'dart:math' show |
13 max, | 13 max, |
14 min; | 14 min; |
15 | 15 |
16 import 'dart:async' show | |
17 Future; | |
18 | |
16 import 'package:compiler/implementation/scanner/scannerlib.dart' | 19 import 'package:compiler/implementation/scanner/scannerlib.dart' |
17 show | 20 show |
18 EOF_TOKEN, | 21 EOF_TOKEN, |
19 StringScanner, | 22 StringScanner, |
20 Token; | 23 Token; |
21 | 24 |
22 import 'package:compiler/implementation/source_file.dart' show | 25 import 'package:compiler/implementation/source_file.dart' show |
23 StringSourceFile; | 26 StringSourceFile; |
24 | 27 |
25 import 'compilation.dart' show | 28 import 'compilation.dart' show |
26 scheduleCompilation; | 29 scheduleCompilation; |
27 | 30 |
28 import 'ui.dart' show | 31 import 'ui.dart' show |
29 currentTheme, | 32 currentTheme, |
30 hackDiv, | 33 hackDiv, |
31 mainEditorPane, | 34 mainEditorPane, |
32 observer, | 35 observer, |
33 outputDiv; | 36 outputDiv; |
34 | 37 |
35 import 'decoration.dart' show | 38 import 'decoration.dart' show |
36 CodeCompletionDecoration, | 39 CodeCompletionDecoration, |
37 Decoration, | 40 Decoration, |
38 DiagnosticDecoration, | 41 DiagnosticDecoration, |
39 error, | 42 error, |
40 info, | 43 info, |
41 warning; | 44 warning; |
42 | 45 |
43 import 'html_to_text.dart' show | 46 import 'html_to_text.dart' show |
44 htmlToText; | 47 htmlToText; |
48 | |
49 import 'compilation_unit.dart' show | |
50 CompilationUnit; | |
51 | |
45 import 'editor.dart' as editor; | 52 import 'editor.dart' as editor; |
46 | 53 |
47 import 'mock.dart' as mock; | 54 import 'mock.dart' as mock; |
48 | 55 |
49 import 'settings.dart' as settings; | 56 import 'settings.dart' as settings; |
50 | 57 |
51 /** | 58 /** |
52 * UI interaction manager for the entire application. | 59 * UI interaction manager for the entire application. |
53 */ | 60 */ |
54 abstract class InteractionManager { | 61 abstract class InteractionManager { |
(...skipping 15 matching lines...) Expand all Loading... | |
70 | 77 |
71 InteractionManager.internal(); | 78 InteractionManager.internal(); |
72 | 79 |
73 void onInput(Event event); | 80 void onInput(Event event); |
74 | 81 |
75 void onKeyUp(KeyboardEvent event); | 82 void onKeyUp(KeyboardEvent event); |
76 | 83 |
77 void onMutation(List<MutationRecord> mutations, MutationObserver observer); | 84 void onMutation(List<MutationRecord> mutations, MutationObserver observer); |
78 | 85 |
79 void onSelectionChange(Event event); | 86 void onSelectionChange(Event event); |
87 | |
88 /// Called when the content of a CompilationUnit changed. | |
89 void onCompilationUnitChanged(CompilationUnit unit); | |
90 | |
91 Future<List<String>> projectFileNames(); | |
92 | |
93 /// Called when the user selected a new project file. | |
94 void onProjectFileSelected(String projectFile); | |
80 } | 95 } |
81 | 96 |
97 | |
82 /** | 98 /** |
83 * State machine for UI interactions. | 99 * State machine for UI interactions. |
84 */ | 100 */ |
85 class InteractionContext extends InteractionManager { | 101 class InteractionContext extends InteractionManager { |
86 InteractionState state; | 102 InteractionState state; |
87 | 103 |
104 final Map<String, CompilationUnit> projectFiles = <String, CompilationUnit>{}; | |
105 | |
106 CompilationUnit currentCompilationUnit = new CompilationUnit('fake', ''); | |
107 | |
88 InteractionContext() | 108 InteractionContext() |
89 : super.internal() { | 109 : super.internal() { |
90 state = new InitialState(this); | 110 state = new InitialState(this); |
91 } | 111 } |
92 | 112 |
93 void onInput(Event event) => state.onInput(event); | 113 void onInput(Event event) => state.onInput(event); |
94 | 114 |
95 void onKeyUp(KeyboardEvent event) => state.onKeyUp(event); | 115 void onKeyUp(KeyboardEvent event) => state.onKeyUp(event); |
96 | 116 |
97 void onMutation(List<MutationRecord> mutations, MutationObserver observer) { | 117 void onMutation(List<MutationRecord> mutations, MutationObserver observer) { |
98 return state.onMutation(mutations, observer); | 118 return state.onMutation(mutations, observer); |
99 } | 119 } |
100 | 120 |
101 void onSelectionChange(Event event) => state.onSelectionChange(event); | 121 void onSelectionChange(Event event) => state.onSelectionChange(event); |
122 | |
123 void onCompilationUnitChanged(CompilationUnit unit) { | |
124 return state.onCompilationUnitChanged(unit); | |
125 } | |
126 | |
127 Future<List<String>> projectFileNames() => state.projectFileNames(); | |
128 | |
129 void onProjectFileSelected(String projectFile) { | |
130 return state.onProjectFileSelected(projectFile); | |
131 } | |
102 } | 132 } |
103 | 133 |
104 abstract class InteractionState implements InteractionManager { | 134 abstract class InteractionState implements InteractionManager { |
105 void onStateChanged(InteractionState previous) { | 135 void onStateChanged(InteractionState previous) { |
106 print('State change ${previous.runtimeType} -> ${runtimeType}.'); | 136 print('State change ${previous.runtimeType} -> ${runtimeType}.'); |
107 } | 137 } |
108 } | 138 } |
109 | 139 |
110 class InitialState extends InteractionState { | 140 class InitialState extends InteractionState { |
111 final InteractionContext context; | 141 final InteractionContext context; |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 while (child != null) { | 256 while (child != null) { |
227 walk4(child); | 257 walk4(child); |
228 if (hasSelection) return; | 258 if (hasSelection) return; |
229 child = child.nextNode; | 259 child = child.nextNode; |
230 } | 260 } |
231 } | 261 } |
232 if (selection.isCollapsed) { | 262 if (selection.isCollapsed) { |
233 walk4(mainEditorPane); | 263 walk4(mainEditorPane); |
234 } | 264 } |
235 | 265 |
236 editor.currentSource = mainEditorPane.text; | 266 String currentText = mainEditorPane.text; |
267 context.currentCompilationUnit.content = currentText; | |
237 mainEditorPane.nodes.clear(); | 268 mainEditorPane.nodes.clear(); |
238 mainEditorPane.appendText(editor.currentSource); | 269 mainEditorPane.appendText(currentText); |
239 if (hasSelection) { | 270 if (hasSelection) { |
240 selection.collapse(mainEditorPane.firstChild, anchorOffset); | 271 selection.collapse(mainEditorPane.firstChild, anchorOffset); |
241 } | 272 } |
242 | 273 |
243 editor.isMalformedInput = false; | 274 editor.isMalformedInput = false; |
244 for (var n in new List.from(mainEditorPane.nodes)) { | 275 for (var n in new List.from(mainEditorPane.nodes)) { |
245 if (n is! Text) continue; | 276 if (n is! Text) continue; |
246 Text node = n; | 277 Text node = n; |
247 String text = node.text; | 278 String text = node.text; |
248 | 279 |
(...skipping 24 matching lines...) Expand all Loading... | |
273 selectionOffset -= str.length; | 304 selectionOffset -= str.length; |
274 selection.collapse(after, selectionOffset); | 305 selection.collapse(after, selectionOffset); |
275 } else { | 306 } else { |
276 selection.collapse(str, selectionOffset); | 307 selection.collapse(str, selectionOffset); |
277 } | 308 } |
278 } | 309 } |
279 node = after; | 310 node = after; |
280 } | 311 } |
281 } | 312 } |
282 | 313 |
283 window.localStorage['currentSource'] = editor.currentSource; | |
284 print('Saved source'); | |
285 | |
286 // Discard highlighting mutations. | 314 // Discard highlighting mutations. |
287 observer.takeRecords(); | 315 observer.takeRecords(); |
288 } | 316 } |
289 | 317 |
290 void onSelectionChange(Event event) { | 318 void onSelectionChange(Event event) { |
291 } | 319 } |
292 | 320 |
293 void onStateChanged(InteractionState previous) { | 321 void onStateChanged(InteractionState previous) { |
294 super.onStateChanged(previous); | 322 super.onStateChanged(previous); |
295 scheduleCompilation(); | 323 scheduleCompilation(); |
296 } | 324 } |
325 | |
326 void onCompilationUnitChanged(CompilationUnit unit) { | |
327 if (unit == context.currentCompilationUnit) { | |
328 window.localStorage['currentSource'] = unit.content; | |
329 print('Saved source'); | |
330 scheduleCompilation(); | |
331 } else { | |
332 print("Unexpected change to compilation unit '${unit.name}'."); | |
333 } | |
334 } | |
335 | |
336 Future<List<String>> projectFileNames() { | |
337 return getString('project?list').then((String response) { | |
338 return new List<String>.from(JSON.decode(response)); | |
339 }); | |
340 } | |
341 | |
342 void onProjectFileSelected(String projectFile) { | |
343 // Disable editing. | |
344 mainEditorPane.contentEditable = 'false'; | |
lukechurch
2014/03/27 16:08:23
If I read the code below correctly, it's going to
ahe
2014/03/27 23:32:34
Good idea.
| |
345 | |
346 CompilationUnit unit = context.projectFiles[projectFile]; | |
347 Future<CompilationUnit> future; | |
348 if (unit != null) { | |
349 // This project file had been fetched already. | |
350 future = new Future<CompilationUnit>.value(unit); | |
351 } else { | |
352 // This project file has to be fetched. | |
353 future = getString('project/$projectFile').then((String text) { | |
354 CompilationUnit unit = context.projectFiles[projectFile]; | |
355 if (unit == null) { | |
356 // Only create a new unit if the value hadn't arrived already. | |
357 unit = new CompilationUnit(projectFile, text); | |
358 context.projectFiles[projectFile] = unit; | |
359 } | |
360 return unit; | |
361 }); | |
362 } | |
363 future.then((CompilationUnit unit) { | |
364 mainEditorPane | |
365 ..contentEditable = 'true' | |
366 ..nodes.clear(); | |
367 observer.takeRecords(); // Discard mutations. | |
368 | |
369 // Install the code, which will trigger a call to onMutation. | |
370 mainEditorPane.appendText(unit.content); | |
371 }); | |
372 } | |
373 } | |
374 | |
375 Future<String> getString(uri) { | |
376 return new Future<String>.sync(() => HttpRequest.getString('$uri')); | |
297 } | 377 } |
298 | 378 |
299 class PendingInputState extends InitialState { | 379 class PendingInputState extends InitialState { |
300 PendingInputState(InteractionContext context) | 380 PendingInputState(InteractionContext context) |
301 : super(context); | 381 : super(context); |
302 | 382 |
303 void onInput(Event event) { | 383 void onInput(Event event) { |
304 // Do nothing. | 384 // Do nothing. |
305 } | 385 } |
306 | 386 |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
593 event.getModifierState("Fn") || | 673 event.getModifierState("Fn") || |
594 event.getModifierState("Meta") || | 674 event.getModifierState("Meta") || |
595 event.getModifierState("NumLock") || | 675 event.getModifierState("NumLock") || |
596 event.getModifierState("ScrollLock") || | 676 event.getModifierState("ScrollLock") || |
597 event.getModifierState("Scroll") || | 677 event.getModifierState("Scroll") || |
598 event.getModifierState("Win") || | 678 event.getModifierState("Win") || |
599 event.getModifierState("Shift") || | 679 event.getModifierState("Shift") || |
600 event.getModifierState("SymbolLock") || | 680 event.getModifierState("SymbolLock") || |
601 event.getModifierState("OS"); | 681 event.getModifierState("OS"); |
602 } | 682 } |
OLD | NEW |