| 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.main; | 5 library trydart.main; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
| 10 import 'dart:uri'; | 10 import 'dart:uri'; |
| 11 | 11 |
| 12 import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' sh
ow StringScanner, EOF_TOKEN; | 12 import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' |
| 13 import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' as
scanner; | 13 show |
| 14 StringScanner, |
| 15 EOF_TOKEN; |
| 16 |
| 17 import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' |
| 18 as scanner; |
| 14 | 19 |
| 15 import 'decoration.dart'; | 20 import 'decoration.dart'; |
| 16 import 'themes.dart'; | 21 import 'themes.dart'; |
| 17 | 22 |
| 18 @lazy import 'compiler_isolate.dart'; | 23 @lazy import 'compiler_isolate.dart'; |
| 19 | 24 |
| 20 const lazy = const DeferredLibrary('compiler_isolate'); | 25 const lazy = const DeferredLibrary('compiler_isolate'); |
| 21 | 26 |
| 22 var inputPre; | 27 var inputPre; |
| 23 var outputDiv; | 28 var outputDiv; |
| 24 var hackDiv; | 29 var hackDiv; |
| 25 var outputFrame; | 30 var outputFrame; |
| 26 var compilerTimer; | 31 var compilerTimer; |
| 27 var compilerPort; | 32 var compilerPort; |
| 28 var observer; | 33 var observer; |
| 29 var cacheStatusElement; | 34 var cacheStatusElement; |
| 30 bool alwaysRunInWorker = window.localStorage['alwaysRunInWorker'] == 'true'; | 35 bool alwaysRunInWorker = window.localStorage['alwaysRunInWorker'] == 'true'; |
| 31 bool verboseCompiler = window.localStorage['verboseCompiler'] == 'true'; | 36 bool verboseCompiler = window.localStorage['verboseCompiler'] == 'true'; |
| 32 bool minified = window.localStorage['minified'] == 'true'; | 37 bool minified = window.localStorage['minified'] == 'true'; |
| 33 bool onlyAnalyze = window.localStorage['onlyAnalyze'] == 'true'; | 38 bool onlyAnalyze = window.localStorage['onlyAnalyze'] == 'true'; |
| 34 String codeFont = ((x) => x == null ? '' : x)(window.localStorage['codeFont']); | 39 final String rawCodeFont = window.localStorage['codeFont']; |
| 40 String codeFont = rawCodeFont == null ? '' : rawCodeFont; |
| 35 String currentSample = window.localStorage['currentSample']; | 41 String currentSample = window.localStorage['currentSample']; |
| 36 Theme currentTheme = Theme.named(window.localStorage['theme']); | 42 Theme currentTheme = Theme.named(window.localStorage['theme']); |
| 37 bool applyingSettings = false; | 43 bool applyingSettings = false; |
| 38 | 44 |
| 39 const String INDENT = '\u{a0}\u{a0}'; | 45 const String INDENT = '\u{a0}\u{a0}'; |
| 40 | 46 |
| 41 onKeyUp(KeyboardEvent e) { | 47 onKeyUp(KeyboardEvent e) { |
| 42 if (e.keyCode == 13) { | 48 if (e.keyCode == 13) { |
| 43 e.preventDefault(); | 49 e.preventDefault(); |
| 44 DomSelection selection = window.getSelection(); | 50 DomSelection selection = window.getSelection(); |
| 45 if (selection.isCollapsed && selection.anchorNode is Text) { | 51 if (selection.isCollapsed && selection.anchorNode is Text) { |
| 46 Text text = selection.anchorNode; | 52 Text text = selection.anchorNode; |
| 47 int offset = selection.anchorOffset; | 53 int offset = selection.anchorOffset; |
| 48 text.insertData(offset, '\n'); | 54 text.insertData(offset, '\n'); |
| 49 selection.collapse(text, offset + 1); | 55 selection.collapse(text, offset + 1); |
| 50 } | 56 } |
| 51 } | 57 } |
| 52 // This is a hack to get Safari to send mutation events on contenteditable. | 58 // This is a hack to get Safari to send mutation events on contenteditable. |
| 53 var newDiv = new DivElement(); | 59 var newDiv = new DivElement(); |
| 54 hackDiv.replaceWith(newDiv); | 60 hackDiv.replaceWith(newDiv); |
| 55 hackDiv = newDiv; | 61 hackDiv = newDiv; |
| 56 } | 62 } |
| 57 | 63 |
| 58 bool isMalformedInput = false; | 64 bool isMalformedInput = false; |
| 59 String currentSource = ""; | 65 String currentSource = ""; |
| 60 | 66 |
| 67 // TODO(ahe): This method should be cleaned up. It is too large. |
| 61 onMutation(List<MutationRecord> mutations, MutationObserver observer) { | 68 onMutation(List<MutationRecord> mutations, MutationObserver observer) { |
| 62 scheduleCompilation(); | 69 scheduleCompilation(); |
| 63 | 70 |
| 64 for (Element element in inputPre.queryAll('a[class="diagnostic"]>span')) { | 71 for (Element element in inputPre.queryAll('a[class="diagnostic"]>span')) { |
| 65 element.remove(); | 72 element.remove(); |
| 66 } | 73 } |
| 67 // Discard clean-up mutations. | 74 // Discard clean-up mutations. |
| 68 observer.takeRecords(); | 75 observer.takeRecords(); |
| 69 | 76 |
| 70 DomSelection selection = window.getSelection(); | 77 DomSelection selection = window.getSelection(); |
| 71 | 78 |
| 72 while (!mutations.isEmpty) { | 79 while (!mutations.isEmpty) { |
| 73 for (MutationRecord record in mutations) { | 80 for (MutationRecord record in mutations) { |
| 74 String type = record.type; | 81 String type = record.type; |
| 75 switch (type) { | 82 switch (type) { |
| 76 | 83 |
| 77 case 'characterData': | 84 case 'characterData': |
| 78 | 85 |
| 79 bool hasSelection = false; | 86 bool hasSelection = false; |
| 80 int offset = selection.anchorOffset; | 87 int offset = selection.anchorOffset; |
| 81 if (selection.isCollapsed && selection.anchorNode == record.target) { | 88 if (selection.isCollapsed && selection.anchorNode == record.target) { |
| 82 hasSelection = true; | 89 hasSelection = true; |
| 83 } | 90 } |
| 84 var parent = record.target.parentNode; | 91 var parent = record.target.parentNode; |
| 85 if (parent != inputPre) { | 92 if (parent != inputPre) { |
| 86 inlineChildren(parent); | 93 inlineChildren(parent); |
| 87 } | 94 } |
| 88 if (hasSelection) { | 95 if (hasSelection) { |
| 89 selection.collapse(record.target, offset); | 96 selection.collapse(record.target, offset); |
| 90 } | 97 } |
| 91 break; | 98 break; |
| 92 | 99 |
| 93 default: | 100 default: |
| 94 if (!record.addedNodes.isEmpty) { | 101 if (!record.addedNodes.isEmpty) { |
| 95 for (var node in record.addedNodes) { | 102 for (var node in record.addedNodes) { |
| 96 | 103 |
| 97 if (node.nodeType != Node.ELEMENT_NODE) continue; | 104 if (node.nodeType != Node.ELEMENT_NODE) continue; |
| 98 | 105 |
| 99 if (node is BRElement) { | 106 if (node is BRElement) { |
| 100 if (selection.anchorNode != node) { | 107 if (selection.anchorNode != node) { |
| 101 node.replaceWith(new Text('\n')); | 108 node.replaceWith(new Text('\n')); |
| 109 } |
| 110 } else { |
| 111 var parent = node.parentNode; |
| 112 if (parent == null) continue; |
| 113 var nodes = new List.from(node.nodes); |
| 114 var style = node.getComputedStyle(); |
| 115 if (style.display != 'inline') { |
| 116 var previous = node.previousNode; |
| 117 if (previous is Text) { |
| 118 previous.appendData('\n'); |
| 119 } else { |
| 120 parent.insertBefore(new Text('\n'), node); |
| 121 } |
| 122 } |
| 123 for (Node child in nodes) { |
| 124 child.remove(); |
| 125 parent.insertBefore(child, node); |
| 126 } |
| 127 node.remove(); |
| 102 } | 128 } |
| 103 } else { | |
| 104 var parent = node.parentNode; | |
| 105 if (parent == null) continue; | |
| 106 var nodes = new List.from(node.nodes); | |
| 107 var style = node.getComputedStyle(); | |
| 108 if (style.display != 'inline') { | |
| 109 var previous = node.previousNode; | |
| 110 if (previous is Text) { | |
| 111 previous.appendData('\n'); | |
| 112 } else { | |
| 113 parent.insertBefore(new Text('\n'), node); | |
| 114 } | |
| 115 } | |
| 116 for (Node child in nodes) { | |
| 117 child.remove(); | |
| 118 parent.insertBefore(child, node); | |
| 119 } | |
| 120 node.remove(); | |
| 121 } | 129 } |
| 122 } | 130 } |
| 123 } | |
| 124 } | 131 } |
| 125 } | 132 } |
| 126 mutations = observer.takeRecords(); | 133 mutations = observer.takeRecords(); |
| 127 } | 134 } |
| 128 | 135 |
| 129 if (!inputPre.nodes.isEmpty && inputPre.nodes.last is Text) { | 136 if (!inputPre.nodes.isEmpty && inputPre.nodes.last is Text) { |
| 130 Text text = inputPre.nodes.last; | 137 Text text = inputPre.nodes.last; |
| 131 if (!text.text.endsWith('\n')) { | 138 if (!text.text.endsWith('\n')) { |
| 132 text.appendData('\n'); | 139 text.appendData('\n'); |
| 133 } | 140 } |
| 134 } | 141 } |
| 135 | 142 |
| 136 int offset = 0; | 143 int offset = 0; |
| 137 int anchorOffset = 0; | 144 int anchorOffset = 0; |
| 138 bool hasSelection = false; | 145 bool hasSelection = false; |
| 139 Node anchorNode = selection.anchorNode; | 146 Node anchorNode = selection.anchorNode; |
| 147 // TODO(ahe): Try to share walk4 methods. |
| 140 void walk4(Node node) { | 148 void walk4(Node node) { |
| 141 // TODO(ahe): Use TreeWalker when that is exposed. | 149 // TODO(ahe): Use TreeWalker when that is exposed. |
| 142 // function textNodesUnder(root){ | 150 // function textNodesUnder(root){ |
| 143 // var n, a=[], walk=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,n
ull,false); | 151 // var n, a=[], walk=document.createTreeWalker( |
| 152 // root,NodeFilter.SHOW_TEXT,null,false); |
| 144 // while(n=walk.nextNode()) a.push(n); | 153 // while(n=walk.nextNode()) a.push(n); |
| 145 // return a; | 154 // return a; |
| 146 // } | 155 // } |
| 147 int type = node.nodeType; | 156 int type = node.nodeType; |
| 148 if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) { | 157 if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) { |
| 149 if (anchorNode == node) { | 158 if (anchorNode == node) { |
| 150 hasSelection = true; | 159 hasSelection = true; |
| 151 anchorOffset = selection.anchorOffset + offset; | 160 anchorOffset = selection.anchorOffset + offset; |
| 152 return; | 161 return; |
| 153 } | 162 } |
| 154 offset += node.length; | 163 offset += node.length; |
| 155 } | 164 } |
| 156 | 165 |
| 157 var child = node.$dom_firstChild; | 166 var child = node.$dom_firstChild; |
| 158 while(child != null) { | 167 while (child != null) { |
| 159 walk4(child); | 168 walk4(child); |
| 160 if (hasSelection) return; | 169 if (hasSelection) return; |
| 161 child = child.nextNode; | 170 child = child.nextNode; |
| 162 } | 171 } |
| 163 } | 172 } |
| 164 if (selection.isCollapsed) { | 173 if (selection.isCollapsed) { |
| 165 walk4(inputPre); | 174 walk4(inputPre); |
| 166 } | 175 } |
| 167 | 176 |
| 168 currentSource = inputPre.text; | 177 currentSource = inputPre.text; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 child = child.nextNode; | 273 child = child.nextNode; |
| 265 } | 274 } |
| 266 } | 275 } |
| 267 walk4(inputPre); | 276 walk4(inputPre); |
| 268 | 277 |
| 269 if (!foundNode) { | 278 if (!foundNode) { |
| 270 outputDiv.appendText('$message\n'); | 279 outputDiv.appendText('$message\n'); |
| 271 } | 280 } |
| 272 | 281 |
| 273 observer.takeRecords(); | 282 observer.takeRecords(); |
| 274 observer.observe(inputPre, childList: true, characterData: true, subtree: true
); | 283 observer.observe( |
| 284 inputPre, childList: true, characterData: true, subtree: true); |
| 275 } | 285 } |
| 276 | 286 |
| 277 void inlineChildren(Element element) { | 287 void inlineChildren(Element element) { |
| 278 if (element == null) return; | 288 if (element == null) return; |
| 279 var parent = element.parentNode; | 289 var parent = element.parentNode; |
| 280 if (parent == null) return; | 290 if (parent == null) return; |
| 281 for (Node child in new List.from(element.nodes)) { | 291 for (Node child in new List.from(element.nodes)) { |
| 282 child.remove(); | 292 child.remove(); |
| 283 parent.insertBefore(child, element); | 293 parent.insertBefore(child, element); |
| 284 } | 294 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 | 366 |
| 357 void dispose() { | 367 void dispose() { |
| 358 if (worker != null) worker.terminate(); | 368 if (worker != null) worker.terminate(); |
| 359 objectUrls.forEach(Url.revokeObjectUrl); | 369 objectUrls.forEach(Url.revokeObjectUrl); |
| 360 } | 370 } |
| 361 | 371 |
| 362 onMessage(message, _) { | 372 onMessage(message, _) { |
| 363 String kind = message is String ? message : message[0]; | 373 String kind = message is String ? message : message[0]; |
| 364 var data = (message is List && message.length == 2) ? message[1] : null; | 374 var data = (message is List && message.length == 2) ? message[1] : null; |
| 365 switch (kind) { | 375 switch (kind) { |
| 366 case 'done': return onDone(data); | 376 case 'done': return onDone(data); |
| 367 case 'url': return onUrl(data); | 377 case 'url': return onUrl(data); |
| 368 case 'code': return onCode(data); | 378 case 'code': return onCode(data); |
| 369 case 'diagnostic': return onDiagnostic(data); | 379 case 'diagnostic': return onDiagnostic(data); |
| 370 case 'crash': return onCrash(data); | 380 case 'crash': return onCrash(data); |
| 371 case 'failed': return onFail(data); | 381 case 'failed': return onFail(data); |
| 372 case 'dart:html': return onDartHtml(data); | 382 case 'dart:html': return onDartHtml(data); |
| 373 default: | 383 default: |
| 374 throw ['Unknown message kind', message]; | 384 throw ['Unknown message kind', message]; |
| 375 } | 385 } |
| 376 } | 386 } |
| 377 | 387 |
| 378 onDartHtml(_) { | 388 onDartHtml(_) { |
| 379 usesDartHtml = true; | 389 usesDartHtml = true; |
| 380 } | 390 } |
| 381 | 391 |
| 382 onFail(_) { | 392 onFail(_) { |
| 383 clear(); | 393 clear(); |
| 384 consolePrint('Compilation failed'); | 394 consolePrint('Compilation failed'); |
| (...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 buildCheckBox(String text, bool defaultValue, void action(Event e)) { | 898 buildCheckBox(String text, bool defaultValue, void action(Event e)) { |
| 889 var checkBox = new CheckboxInputElement() | 899 var checkBox = new CheckboxInputElement() |
| 890 ..defaultChecked = defaultValue | 900 ..defaultChecked = defaultValue |
| 891 ..onChange.listen(action); | 901 ..onChange.listen(action); |
| 892 return new LabelElement() | 902 return new LabelElement() |
| 893 ..classes.add('checkbox') | 903 ..classes.add('checkbox') |
| 894 ..append(checkBox) | 904 ..append(checkBox) |
| 895 ..appendText(' $text'); | 905 ..appendText(' $text'); |
| 896 } | 906 } |
| 897 | 907 |
| 908 // TODO(ahe): Build abstraction for flags/options. |
| 898 fieldSet.append( | 909 fieldSet.append( |
| 899 buildCheckBox( | 910 buildCheckBox( |
| 900 'Always run in Worker thread.', alwaysRunInWorker, | 911 'Always run in Worker thread.', alwaysRunInWorker, |
| 901 (Event e) { alwaysRunInWorker = e.target.checked; })); | 912 (Event e) { alwaysRunInWorker = e.target.checked; })); |
| 902 | 913 |
| 903 fieldSet.append( | 914 fieldSet.append( |
| 904 buildCheckBox( | 915 buildCheckBox( |
| 905 'Verbose compiler output.', verboseCompiler, | 916 'Verbose compiler output.', verboseCompiler, |
| 906 (Event e) { verboseCompiler = e.target.checked; })); | 917 (Event e) { verboseCompiler = e.target.checked; })); |
| 907 | 918 |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1258 } | 1269 } |
| 1259 | 1270 |
| 1260 .center { | 1271 .center { |
| 1261 display: block; | 1272 display: block; |
| 1262 margin: 0px auto; | 1273 margin: 0px auto; |
| 1263 text-align: center; | 1274 text-align: center; |
| 1264 } | 1275 } |
| 1265 """; | 1276 """; |
| 1266 | 1277 |
| 1267 '''; | 1278 '''; |
| OLD | NEW |