| 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 trydart.ui; | 5 library trydart.ui; |
| 6 | 6 |
| 7 import 'dart:html'; | 7 import 'dart:html'; |
| 8 | 8 |
| 9 import 'dart:async' show | 9 import 'dart:async' show |
| 10 Future, |
| 11 Timer, |
| 10 scheduleMicrotask; | 12 scheduleMicrotask; |
| 11 | 13 |
| 14 import 'dart:convert' show JSON; |
| 15 |
| 12 import 'cache.dart' show | 16 import 'cache.dart' show |
| 13 onLoad, | 17 onLoad, |
| 14 updateCacheStatus; | 18 updateCacheStatus; |
| 15 | 19 |
| 16 import 'editor.dart' show | 20 import 'interaction_manager.dart' show InteractionManager; |
| 17 onKeyUp, | |
| 18 onMutation; | |
| 19 | 21 |
| 20 import 'run.dart' show | 22 import 'run.dart' show |
| 21 makeOutputFrame; | 23 makeOutputFrame; |
| 22 | 24 |
| 23 import 'themes.dart' show | 25 import 'themes.dart' show |
| 24 THEMES, | 26 THEMES, |
| 25 Theme; | 27 Theme; |
| 26 | 28 |
| 27 import 'samples.dart' show | 29 import 'samples.dart' show |
| 28 EXAMPLE_FIBONACCI, | 30 EXAMPLE_FIBONACCI, |
| 29 EXAMPLE_FIBONACCI_HTML, | 31 EXAMPLE_FIBONACCI_HTML, |
| 30 EXAMPLE_HELLO, | 32 EXAMPLE_HELLO, |
| 31 EXAMPLE_HELLO_HTML, | 33 EXAMPLE_HELLO_HTML, |
| 32 EXAMPLE_SUNFLOWER; | 34 EXAMPLE_SUNFLOWER; |
| 33 | 35 |
| 36 import 'settings.dart'; |
| 37 |
| 38 import 'user_option.dart'; |
| 39 |
| 40 import 'messages.dart' show messages; |
| 41 |
| 42 // TODO(ahe): Make internal to buildUI once all interactions have been moved to |
| 43 // the manager. |
| 44 InteractionManager interaction; |
| 45 |
| 34 DivElement inputPre; | 46 DivElement inputPre; |
| 35 PreElement outputDiv; | 47 PreElement outputDiv; |
| 36 DivElement hackDiv; | 48 DivElement hackDiv; |
| 37 IFrameElement outputFrame; | 49 IFrameElement outputFrame; |
| 38 MutationObserver observer; | 50 MutationObserver observer; |
| 39 SpanElement cacheStatusElement; | 51 SpanElement cacheStatusElement; |
| 40 bool alwaysRunInWorker = window.localStorage['alwaysRunInWorker'] == 'true'; | 52 Theme currentTheme = Theme.named(theme); |
| 41 bool verboseCompiler = window.localStorage['verboseCompiler'] == 'true'; | |
| 42 bool minified = window.localStorage['minified'] == 'true'; | |
| 43 bool onlyAnalyze = window.localStorage['onlyAnalyze'] == 'true'; | |
| 44 final String rawCodeFont = window.localStorage['codeFont']; | |
| 45 String codeFont = rawCodeFont == null ? '' : rawCodeFont; | |
| 46 String currentSample = window.localStorage['currentSample']; | |
| 47 Theme currentTheme = Theme.named(window.localStorage['theme']); | |
| 48 bool applyingSettings = false; | |
| 49 | 53 |
| 50 buildButton(message, action) { | 54 buildButton(message, action) { |
| 51 if (message is String) { | 55 if (message is String) { |
| 52 message = new Text(message); | 56 message = new Text(message); |
| 53 } | 57 } |
| 54 return new ButtonElement() | 58 return new ButtonElement() |
| 55 ..onClick.listen(action) | 59 ..onClick.listen(action) |
| 56 ..append(message); | 60 ..append(message); |
| 57 } | 61 } |
| 58 | 62 |
| 59 buildTab(message, id, action) { | 63 buildTab(message, id, action) { |
| 60 if (message is String) { | 64 if (message is String) { |
| 61 message = new Text(message); | 65 message = new Text(message); |
| 62 } | 66 } |
| 63 | 67 |
| 64 onClick(MouseEvent event) { | 68 onClick(MouseEvent event) { |
| 65 event.preventDefault(); | 69 event.preventDefault(); |
| 66 Element e = event.target; | 70 Element e = event.target; |
| 67 LIElement parent = e.parent; | 71 LIElement parent = e.parent; |
| 68 parent.parent.query('li[class="active"]').classes.remove('active'); | 72 parent.parent.querySelector('li[class="active"]').classes.remove('active'); |
| 69 parent.classes.add('active'); | 73 parent.classes.add('active'); |
| 70 action(event); | 74 action(event); |
| 71 } | 75 } |
| 72 | 76 |
| 73 inspirationCallbacks[id] = action; | 77 codeCallbacks[id] = action; |
| 74 | 78 |
| 75 return new OptionElement()..append(message)..id = id; | 79 return new OptionElement()..append(message)..id = id; |
| 76 } | 80 } |
| 77 | 81 |
| 78 Map<String, Function> inspirationCallbacks = new Map<String, Function>(); | 82 Map<String, Function> codeCallbacks = new Map<String, Function>(); |
| 79 | 83 |
| 80 void onInspirationChange(Event event) { | 84 void onCodeChange(Event event) { |
| 81 SelectElement select = event.target; | 85 SelectElement select = event.target; |
| 82 String id = select.queryAll('option')[select.selectedIndex].id; | 86 String id = select.querySelectorAll('option')[select.selectedIndex].id; |
| 83 Function action = inspirationCallbacks[id]; | 87 Function action = codeCallbacks[id]; |
| 84 if (action != null) action(event); | 88 if (action != null) action(event); |
| 85 outputFrame.style.display = 'none'; | 89 outputFrame.style.display = 'none'; |
| 86 } | 90 } |
| 87 | 91 |
| 88 buildUI() { | 92 buildUI() { |
| 93 interaction = new InteractionManager(); |
| 94 |
| 89 window.localStorage['currentSample'] = '$currentSample'; | 95 window.localStorage['currentSample'] = '$currentSample'; |
| 90 | 96 |
| 91 var inspirationTabs = document.getElementById('inspiration'); | 97 buildCode(interaction); |
| 92 var htmlGroup = new OptGroupElement()..label = 'HTML'; | |
| 93 var benchmarkGroup = new OptGroupElement()..label = 'Benchmarks'; | |
| 94 inspirationTabs.append(new OptionElement()..appendText('Pick an example')); | |
| 95 inspirationTabs.onChange.listen(onInspirationChange); | |
| 96 // inspirationTabs.classes.addAll(['nav', 'nav-tabs']); | |
| 97 inspirationTabs.append(buildTab('Hello, World!', 'EXAMPLE_HELLO', (_) { | |
| 98 inputPre | |
| 99 ..nodes.clear() | |
| 100 ..appendText(EXAMPLE_HELLO); | |
| 101 })); | |
| 102 inspirationTabs.append(buildTab('Fibonacci', 'EXAMPLE_FIBONACCI', (_) { | |
| 103 inputPre | |
| 104 ..nodes.clear() | |
| 105 ..appendText(EXAMPLE_FIBONACCI); | |
| 106 })); | |
| 107 inspirationTabs.append(htmlGroup); | |
| 108 // TODO(ahe): Restore benchmarks. | |
| 109 // inspirationTabs.append(benchmarkGroup); | |
| 110 | |
| 111 htmlGroup.append( | |
| 112 buildTab('Hello, World!', 'EXAMPLE_HELLO_HTML', (_) { | |
| 113 inputPre | |
| 114 ..nodes.clear() | |
| 115 ..appendText(EXAMPLE_HELLO_HTML); | |
| 116 })); | |
| 117 htmlGroup.append( | |
| 118 buildTab('Fibonacci', 'EXAMPLE_FIBONACCI_HTML', (_) { | |
| 119 inputPre | |
| 120 ..nodes.clear() | |
| 121 ..appendText(EXAMPLE_FIBONACCI_HTML); | |
| 122 })); | |
| 123 htmlGroup.append(buildTab('Sunflower', 'EXAMPLE_SUNFLOWER', (_) { | |
| 124 inputPre | |
| 125 ..nodes.clear() | |
| 126 ..appendText(EXAMPLE_SUNFLOWER); | |
| 127 })); | |
| 128 | |
| 129 benchmarkGroup.append(buildTab('DeltaBlue', 'BENCHMARK_DELTA_BLUE', (_) { | |
| 130 inputPre.contentEditable = 'false'; | |
| 131 LinkElement link = query('link[rel="benchmark-DeltaBlue"]'); | |
| 132 String deltaBlueUri = link.href; | |
| 133 link = query('link[rel="benchmark-base"]'); | |
| 134 String benchmarkBaseUri = link.href; | |
| 135 HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) { | |
| 136 HttpRequest.getString(deltaBlueUri).then((String deltaBlue) { | |
| 137 benchmarkBase = benchmarkBase.replaceFirst( | |
| 138 'part of benchmark_harness;', '// part of benchmark_harness;'); | |
| 139 deltaBlue = deltaBlue.replaceFirst( | |
| 140 "import 'package:benchmark_harness/benchmark_harness.dart';", | |
| 141 benchmarkBase); | |
| 142 inputPre | |
| 143 ..nodes.clear() | |
| 144 ..appendText(deltaBlue) | |
| 145 ..contentEditable = 'true'; | |
| 146 }); | |
| 147 }); | |
| 148 })); | |
| 149 | |
| 150 benchmarkGroup.append(buildTab('Richards', 'BENCHMARK_RICHARDS', (_) { | |
| 151 inputPre.contentEditable = 'false'; | |
| 152 LinkElement link = query('link[rel="benchmark-Richards"]'); | |
| 153 String richardsUri = link.href; | |
| 154 link = query('link[rel="benchmark-base"]'); | |
| 155 String benchmarkBaseUri = link.href; | |
| 156 HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) { | |
| 157 HttpRequest.getString(richardsUri).then((String richards) { | |
| 158 benchmarkBase = benchmarkBase.replaceFirst( | |
| 159 'part of benchmark_harness;', '// part of benchmark_harness;'); | |
| 160 richards = richards.replaceFirst( | |
| 161 "import 'package:benchmark_harness/benchmark_harness.dart';", | |
| 162 benchmarkBase); | |
| 163 inputPre | |
| 164 ..nodes.clear() | |
| 165 ..appendText(richards) | |
| 166 ..contentEditable = 'true'; | |
| 167 }); | |
| 168 }); | |
| 169 })); | |
| 170 | |
| 171 // TODO(ahe): Update currentSample. Or try switching to a drop-down menu. | |
| 172 var active = inspirationTabs.query('[id="$currentSample"]'); | |
| 173 if (active == null) { | |
| 174 // inspirationTabs.query('li').classes.add('active'); | |
| 175 } | |
| 176 | 98 |
| 177 (inputPre = new DivElement()) | 99 (inputPre = new DivElement()) |
| 178 ..classes.add('well') | 100 ..classes.add('well') |
| 179 ..style.backgroundColor = currentTheme.background.color | 101 ..style.backgroundColor = currentTheme.background.color |
| 180 ..style.color = currentTheme.foreground.color | 102 ..style.color = currentTheme.foreground.color |
| 181 ..style.overflow = 'auto' | 103 ..style.overflow = 'visible' |
| 182 ..style.whiteSpace = 'pre' | 104 ..style.whiteSpace = 'pre' |
| 183 ..style.font = codeFont | 105 ..style.font = codeFont |
| 184 ..spellcheck = false; | 106 ..spellcheck = false; |
| 185 | 107 |
| 186 inputPre.contentEditable = 'true'; | 108 inputPre |
| 187 inputPre.onKeyDown.listen(onKeyUp); | 109 ..contentEditable = 'true' |
| 110 ..onKeyDown.listen(interaction.onKeyUp) |
| 111 ..onInput.listen(interaction.onInput); |
| 112 |
| 113 document.onSelectionChange.listen(interaction.onSelectionChange); |
| 188 | 114 |
| 189 var inputWrapper = new DivElement() | 115 var inputWrapper = new DivElement() |
| 190 ..append(inputPre) | 116 ..append(inputPre) |
| 191 ..style.position = 'relative'; | 117 ..style.position = 'relative'; |
| 192 | 118 |
| 193 var inputHeader = new DivElement()..appendText('Code'); | 119 var inputHeader = new DivElement()..appendText('Code'); |
| 194 | 120 |
| 195 inputHeader.style | 121 inputHeader.style |
| 196 ..right = '3px' | 122 ..right = '3px' |
| 197 ..top = '0px' | 123 ..top = '0px' |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 save.download = 'untitled.dart'; | 160 save.download = 'untitled.dart'; |
| 235 save.dispatchEvent(new Event.eventType('Event', 'click')); | 161 save.dispatchEvent(new Event.eventType('Event', 'click')); |
| 236 }) | 162 }) |
| 237 ..style.position = 'absolute' | 163 ..style.position = 'absolute' |
| 238 ..style.right = '0px' | 164 ..style.right = '0px' |
| 239 ..appendText('Save'); | 165 ..appendText('Save'); |
| 240 | 166 |
| 241 cacheStatusElement = document.getElementById('appcache-status'); | 167 cacheStatusElement = document.getElementById('appcache-status'); |
| 242 updateCacheStatus(); | 168 updateCacheStatus(); |
| 243 | 169 |
| 244 // TODO(ahe): Switch to two column layout so the console is on the right. | 170 var section = document.querySelector('article[class="homepage"]>section'); |
| 245 var section = document.query('article[class="homepage"]>section'); | |
| 246 | 171 |
| 247 DivElement tryColumn = document.getElementById('try-dart-column'); | 172 DivElement tryColumn = document.getElementById('try-dart-column'); |
| 248 DivElement runColumn = document.getElementById('run-dart-column'); | 173 DivElement runColumn = document.getElementById('run-dart-column'); |
| 249 | 174 |
| 250 tryColumn.append(inputWrapper); | 175 tryColumn.append(inputWrapper); |
| 251 outputFrame.style.display = 'none'; | 176 outputFrame.style.display = 'none'; |
| 252 runColumn.append(outputFrame); | 177 runColumn.append(outputFrame); |
| 253 runColumn.append(outputWrapper); | 178 runColumn.append(outputWrapper); |
| 254 runColumn.append(hackDiv); | 179 runColumn.append(hackDiv); |
| 255 | 180 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 271 if (scrollHeight > 0) { | 196 if (scrollHeight > 0) { |
| 272 outputFrame.style.height = '${scrollHeight}px'; | 197 outputFrame.style.height = '${scrollHeight}px'; |
| 273 } | 198 } |
| 274 return; | 199 return; |
| 275 } | 200 } |
| 276 } | 201 } |
| 277 } | 202 } |
| 278 outputDiv.appendText('${event.data}\n'); | 203 outputDiv.appendText('${event.data}\n'); |
| 279 }); | 204 }); |
| 280 | 205 |
| 281 observer = new MutationObserver(onMutation) | 206 observer = new MutationObserver(interaction.onMutation) |
| 282 ..observe(inputPre, childList: true, characterData: true, subtree: true); | 207 ..observe(inputPre, childList: true, characterData: true, subtree: true); |
| 283 | 208 |
| 284 scheduleMicrotask(() { | 209 scheduleMicrotask(() { |
| 285 inputPre.appendText(window.localStorage['currentSource']); | 210 inputPre.appendText(window.localStorage['currentSource']); |
| 286 }); | 211 }); |
| 287 | 212 |
| 288 // You cannot install event handlers on window.applicationCache | 213 // You cannot install event handlers on window.applicationCache |
| 289 // until the window has loaded. In dartium, that's later than this | 214 // until the window has loaded. In dartium, that's later than this |
| 290 // method is called. | 215 // method is called. |
| 291 window.onLoad.listen(onLoad); | 216 window.onLoad.listen(onLoad); |
| 292 | 217 |
| 293 // However, in dart2js, the window has already loaded, and onLoad is | 218 // However, in dart2js, the window has already loaded, and onLoad is |
| 294 // never called. | 219 // never called. |
| 295 onLoad(null); | 220 onLoad(null); |
| 296 } | 221 } |
| 297 | 222 |
| 223 buildCode(InteractionManager interaction) { |
| 224 var codePicker = |
| 225 document.getElementById('code-picker') |
| 226 ..style.visibility = 'hidden' |
| 227 ..onChange.listen(onCodeChange); |
| 228 var htmlGroup = new OptGroupElement()..label = 'HTML'; |
| 229 var benchmarkGroup = new OptGroupElement()..label = 'Benchmarks'; |
| 230 |
| 231 new Future(() => HttpRequest.getString('project?list').then( |
| 232 (String response) { |
| 233 OptionElement none = new OptionElement() |
| 234 ..appendText('--') |
| 235 ..disabled = true; |
| 236 codePicker.append(none); |
| 237 for (String projectFile in JSON.decode(response)) { |
| 238 codePicker.append(buildTab(projectFile, projectFile, (_) { |
| 239 inputPre.contentEditable = 'false'; |
| 240 HttpRequest.getString('project/$projectFile').then((String text) { |
| 241 inputPre |
| 242 ..contentEditable = 'true' |
| 243 ..nodes.clear(); |
| 244 observer.takeRecords(); |
| 245 inputPre.appendText(text); |
| 246 }); |
| 247 })); |
| 248 } |
| 249 codePicker.style.visibility = 'visible'; |
| 250 codePicker.selectedIndex = 0; |
| 251 })).catchError((error) { |
| 252 codePicker.style.visibility = 'visible'; |
| 253 print(error); |
| 254 OptionElement none = new OptionElement() |
| 255 ..appendText('Pick an example') |
| 256 ..disabled = true; |
| 257 codePicker.append(none); |
| 258 |
| 259 // codePicker.classes.addAll(['nav', 'nav-tabs']); |
| 260 codePicker.append(buildTab('Hello, World!', 'EXAMPLE_HELLO', (_) { |
| 261 inputPre |
| 262 ..nodes.clear() |
| 263 ..appendText(EXAMPLE_HELLO); |
| 264 })); |
| 265 codePicker.append(buildTab('Fibonacci', 'EXAMPLE_FIBONACCI', (_) { |
| 266 inputPre |
| 267 ..nodes.clear() |
| 268 ..appendText(EXAMPLE_FIBONACCI); |
| 269 })); |
| 270 codePicker.append(htmlGroup); |
| 271 // TODO(ahe): Restore benchmarks. |
| 272 // codePicker.append(benchmarkGroup); |
| 273 |
| 274 htmlGroup.append( |
| 275 buildTab('Hello, World!', 'EXAMPLE_HELLO_HTML', (_) { |
| 276 inputPre |
| 277 ..nodes.clear() |
| 278 ..appendText(EXAMPLE_HELLO_HTML); |
| 279 })); |
| 280 htmlGroup.append( |
| 281 buildTab('Fibonacci', 'EXAMPLE_FIBONACCI_HTML', (_) { |
| 282 inputPre |
| 283 ..nodes.clear() |
| 284 ..appendText(EXAMPLE_FIBONACCI_HTML); |
| 285 })); |
| 286 htmlGroup.append(buildTab('Sunflower', 'EXAMPLE_SUNFLOWER', (_) { |
| 287 inputPre |
| 288 ..nodes.clear() |
| 289 ..appendText(EXAMPLE_SUNFLOWER); |
| 290 })); |
| 291 |
| 292 benchmarkGroup.append(buildTab('DeltaBlue', 'BENCHMARK_DELTA_BLUE', (_) { |
| 293 inputPre.contentEditable = 'false'; |
| 294 LinkElement link = querySelector('link[rel="benchmark-DeltaBlue"]'); |
| 295 String deltaBlueUri = link.href; |
| 296 link = querySelector('link[rel="benchmark-base"]'); |
| 297 String benchmarkBaseUri = link.href; |
| 298 HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) { |
| 299 HttpRequest.getString(deltaBlueUri).then((String deltaBlue) { |
| 300 benchmarkBase = benchmarkBase.replaceFirst( |
| 301 'part of benchmark_harness;', '// part of benchmark_harness;'); |
| 302 deltaBlue = deltaBlue.replaceFirst( |
| 303 "import 'package:benchmark_harness/benchmark_harness.dart';", |
| 304 benchmarkBase); |
| 305 inputPre |
| 306 ..nodes.clear() |
| 307 ..appendText(deltaBlue) |
| 308 ..contentEditable = 'true'; |
| 309 }); |
| 310 }); |
| 311 })); |
| 312 |
| 313 benchmarkGroup.append(buildTab('Richards', 'BENCHMARK_RICHARDS', (_) { |
| 314 inputPre.contentEditable = 'false'; |
| 315 LinkElement link = querySelector('link[rel="benchmark-Richards"]'); |
| 316 String richardsUri = link.href; |
| 317 link = querySelector('link[rel="benchmark-base"]'); |
| 318 String benchmarkBaseUri = link.href; |
| 319 HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) { |
| 320 HttpRequest.getString(richardsUri).then((String richards) { |
| 321 benchmarkBase = benchmarkBase.replaceFirst( |
| 322 'part of benchmark_harness;', '// part of benchmark_harness;'); |
| 323 richards = richards.replaceFirst( |
| 324 "import 'package:benchmark_harness/benchmark_harness.dart';", |
| 325 benchmarkBase); |
| 326 inputPre |
| 327 ..nodes.clear() |
| 328 ..appendText(richards) |
| 329 ..contentEditable = 'true'; |
| 330 }); |
| 331 }); |
| 332 })); |
| 333 |
| 334 codePicker.selectedIndex = 0; |
| 335 }); |
| 336 } |
| 337 |
| 338 num settingsHeight = 0; |
| 339 |
| 298 void openSettings(MouseEvent event) { | 340 void openSettings(MouseEvent event) { |
| 299 event.preventDefault(); | 341 event.preventDefault(); |
| 300 | 342 |
| 301 var backdrop = new DivElement()..classes.add('modal-backdrop'); | 343 if (settingsHeight != 0) { |
| 302 document.body.append(backdrop); | 344 var dialog = document.getElementById('settings-dialog'); |
| 345 if (dialog.getBoundingClientRect().height > 0) { |
| 346 dialog.style.height = '0px'; |
| 347 } else { |
| 348 dialog.style.height = '${settingsHeight}px'; |
| 349 } |
| 350 return; |
| 351 } |
| 303 | 352 |
| 304 void updateCodeFont(Event e) { | 353 void updateCodeFont(Event e) { |
| 305 TextInputElement target = e.target; | 354 TextInputElement target = e.target; |
| 306 codeFont = target.value; | 355 codeFont = target.value; |
| 307 inputPre.style.font = codeFont; | 356 inputPre.style.font = codeFont; |
| 308 backdrop.style.opacity = '0.0'; | |
| 309 } | 357 } |
| 310 | 358 |
| 311 void updateTheme(Event e) { | 359 void updateTheme(Event e) { |
| 312 var select = e.target; | 360 var select = e.target; |
| 313 String theme = select.queryAll('option')[select.selectedIndex].text; | 361 String theme = select.queryAll('option')[select.selectedIndex].text; |
| 314 window.localStorage['theme'] = theme; | 362 window.localStorage['theme'] = theme; |
| 315 currentTheme = Theme.named(theme); | 363 currentTheme = Theme.named(theme); |
| 316 | 364 |
| 317 inputPre.style | 365 inputPre.style |
| 318 ..backgroundColor = currentTheme.background.color | 366 ..backgroundColor = currentTheme.background.color |
| 319 ..color = currentTheme.foreground.color; | 367 ..color = currentTheme.foreground.color; |
| 320 | 368 |
| 321 outputDiv.style | 369 outputDiv.style |
| 322 ..backgroundColor = currentTheme.background.color | 370 ..backgroundColor = currentTheme.background.color |
| 323 ..color = currentTheme.foreground.color; | 371 ..color = currentTheme.foreground.color; |
| 324 | 372 |
| 325 backdrop.style.opacity = '0.0'; | 373 bool oldCompilationPaused = compilationPaused; |
| 326 | 374 compilationPaused = true; |
| 327 applyingSettings = true; | 375 interaction.onMutation([], observer); |
| 328 onMutation([], observer); | 376 compilationPaused = false; |
| 329 applyingSettings = false; | |
| 330 } | 377 } |
| 331 | 378 |
| 332 | |
| 333 var body = document.getElementById('settings-body'); | 379 var body = document.getElementById('settings-body'); |
| 334 | 380 |
| 335 body.nodes.clear(); | 381 body.nodes.clear(); |
| 336 | 382 |
| 337 var form = new FormElement(); | 383 var form = new FormElement(); |
| 338 var fieldSet = new FieldSetElement(); | 384 var fieldSet = new FieldSetElement(); |
| 339 body.append(form); | 385 body.append(form); |
| 340 form.append(fieldSet); | 386 form.append(fieldSet); |
| 341 | 387 |
| 342 buildCheckBox(String text, bool defaultValue, void action(Event e)) { | 388 bool isChecked(CheckboxInputElement checkBox) => checkBox.checked; |
| 343 var checkBox = new CheckboxInputElement() | 389 |
| 344 // TODO(ahe): Used to be ..defaultChecked = defaultValue | 390 String messageFor(UserOption option) { |
| 345 ..checked = defaultValue | 391 var message = messages[option.name]; |
| 346 ..onChange.listen(action); | 392 if (message is List) message = message[0]; |
| 347 return new LabelElement() | 393 return (message == null) ? option.name : message; |
| 394 } |
| 395 |
| 396 String placeHolderFor(UserOption option) { |
| 397 var message = messages[option.name]; |
| 398 if (message is! List) return ''; |
| 399 message = message[1]; |
| 400 return (message == null) ? '' : message; |
| 401 } |
| 402 |
| 403 void addBooleanOption(BooleanUserOption option) { |
| 404 CheckboxInputElement checkBox = new CheckboxInputElement() |
| 405 ..checked = option.value |
| 406 ..onChange.listen((Event e) { option.value = isChecked(e.target); }); |
| 407 |
| 408 LabelElement label = new LabelElement() |
| 348 ..classes.add('checkbox') | 409 ..classes.add('checkbox') |
| 349 ..append(checkBox) | 410 ..append(checkBox) |
| 350 ..appendText(' $text'); | 411 ..appendText(' ${messageFor(option)}'); |
| 412 |
| 413 fieldSet.append(label); |
| 351 } | 414 } |
| 352 | 415 |
| 353 bool isChecked(CheckboxInputElement checkBox) => checkBox.checked; | 416 void addStringOption(StringUserOption option) { |
| 417 fieldSet.append(new LabelElement()..appendText(messageFor(option))); |
| 418 var textInput = new TextInputElement(); |
| 419 textInput.classes.add('input-block-level'); |
| 420 String value = option.value; |
| 421 if (!value.isEmpty) { |
| 422 textInput.value = value; |
| 423 } |
| 424 textInput.placeholder = placeHolderFor(option);; |
| 425 textInput.onChange.listen(updateCodeFont); |
| 426 fieldSet.append(textInput); |
| 427 } |
| 354 | 428 |
| 355 // TODO(ahe): Build abstraction for flags/options. | 429 void addThemeOption(StringUserOption option) { |
| 356 fieldSet.append( | 430 fieldSet.append(new LabelElement()..appendText('Theme:')); |
| 357 buildCheckBox( | 431 var themeSelector = new SelectElement(); |
| 358 'Always run in Worker thread.', alwaysRunInWorker, | 432 themeSelector.classes.add('input-block-level'); |
| 359 (Event e) { alwaysRunInWorker = isChecked(e.target); })); | 433 for (Theme theme in THEMES) { |
| 434 OptionElement option = new OptionElement()..appendText(theme.name); |
| 435 if (theme == currentTheme) option.selected = true; |
| 436 themeSelector.append(option); |
| 437 } |
| 438 themeSelector.onChange.listen(updateTheme); |
| 439 fieldSet.append(themeSelector); |
| 440 } |
| 360 | 441 |
| 361 fieldSet.append( | 442 for (UserOption option in options) { |
| 362 buildCheckBox( | 443 if (option.isHidden) continue; |
| 363 'Verbose compiler output.', verboseCompiler, | 444 if (option.name == 'theme') { |
| 364 (Event e) { verboseCompiler = isChecked(e.target); })); | 445 addThemeOption(option); |
| 365 | 446 } else if (option is BooleanUserOption) { |
| 366 fieldSet.append( | 447 addBooleanOption(option); |
| 367 buildCheckBox( | 448 } else if (option is StringUserOption) { |
| 368 'Generate compact (minified) JavaScript.', minified, | 449 addStringOption(option); |
| 369 (Event e) { minified = isChecked(e.target); })); | 450 } |
| 370 | |
| 371 fieldSet.append( | |
| 372 buildCheckBox( | |
| 373 'Only analyze program.', onlyAnalyze, | |
| 374 (Event e) { onlyAnalyze = isChecked(e.target); })); | |
| 375 | |
| 376 fieldSet.append(new LabelElement()..appendText('Code font:')); | |
| 377 var textInput = new TextInputElement(); | |
| 378 textInput.classes.add('input-block-level'); | |
| 379 if (codeFont != null && codeFont != '') { | |
| 380 textInput.value = codeFont; | |
| 381 } | 451 } |
| 382 textInput.placeholder = 'Enter a size and font, for example, 11pt monospace'; | |
| 383 textInput.onChange.listen(updateCodeFont); | |
| 384 fieldSet.append(textInput); | |
| 385 | |
| 386 fieldSet.append(new LabelElement()..appendText('Theme:')); | |
| 387 var themeSelector = new SelectElement(); | |
| 388 themeSelector.classes.add('input-block-level'); | |
| 389 for (Theme theme in THEMES) { | |
| 390 OptionElement option = new OptionElement()..appendText(theme.name); | |
| 391 if (theme == currentTheme) option.selected = true; | |
| 392 themeSelector.append(option); | |
| 393 } | |
| 394 themeSelector.onChange.listen(updateTheme); | |
| 395 fieldSet.append(themeSelector); | |
| 396 | 452 |
| 397 var dialog = document.getElementById('settings-dialog'); | 453 var dialog = document.getElementById('settings-dialog'); |
| 398 | 454 |
| 399 dialog.style.display = 'block'; | 455 if (settingsHeight == 0) { |
| 400 dialog.classes.add('in'); | 456 settingsHeight = dialog.getBoundingClientRect().height; |
| 457 dialog.classes |
| 458 ..add('slider') |
| 459 ..remove('myhidden'); |
| 460 Timer.run(() { |
| 461 dialog.style.height = '${settingsHeight}px'; |
| 462 }); |
| 463 } else { |
| 464 dialog.style.height = '${settingsHeight}px'; |
| 465 } |
| 401 | 466 |
| 402 onSubmit(Event event) { | 467 onSubmit(Event event) { |
| 403 event.preventDefault(); | 468 event.preventDefault(); |
| 404 | 469 |
| 405 window.localStorage['alwaysRunInWorker'] = '$alwaysRunInWorker'; | 470 window.localStorage['alwaysRunInWorker'] = '$alwaysRunInWorker'; |
| 406 window.localStorage['verboseCompiler'] = '$verboseCompiler'; | 471 window.localStorage['verboseCompiler'] = '$verboseCompiler'; |
| 407 window.localStorage['minified'] = '$minified'; | 472 window.localStorage['minified'] = '$minified'; |
| 408 window.localStorage['onlyAnalyze'] = '$onlyAnalyze'; | 473 window.localStorage['onlyAnalyze'] = '$onlyAnalyze'; |
| 474 window.localStorage['enableDartMind'] = '$enableDartMind'; |
| 475 window.localStorage['compilationPaused'] = '$compilationPaused'; |
| 409 window.localStorage['codeFont'] = '$codeFont'; | 476 window.localStorage['codeFont'] = '$codeFont'; |
| 410 | 477 |
| 411 dialog.style.display = 'none'; | 478 dialog.style.height = '0px'; |
| 412 dialog.classes.remove('in'); | |
| 413 backdrop.remove(); | |
| 414 } | 479 } |
| 415 form.onSubmit.listen(onSubmit); | 480 form.onSubmit.listen(onSubmit); |
| 416 | 481 |
| 417 var doneButton = document.getElementById('settings-done'); | 482 var doneButton = document.getElementById('settings-done'); |
| 418 doneButton.onClick.listen(onSubmit); | 483 doneButton.onClick.listen(onSubmit); |
| 419 } | 484 } |
| OLD | NEW |