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

Side by Side Diff: dart/site/try/leap.dart

Issue 125123002: try.dartlang.org version 5. (Closed) Base URL: /Users/ahe/Dart/all@master
Patch Set: Created 6 years, 11 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library trydart.main;
6
7 import 'dart:async';
8 import 'dart:html';
9 import 'dart:isolate';
10 import 'dart:uri';
11
12 import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' sh ow StringScanner, EOF_TOKEN;
kasperl 2014/01/07 07:18:43 Long lines.
ahe 2014/01/07 14:06:23 Done.
13 import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' as scanner;
14
15 import 'decoration.dart';
16 import 'themes.dart';
17
18 @lazy import 'compiler_isolate.dart';
19
20 const lazy = const DeferredLibrary('compiler_isolate');
21
22 var inputPre;
23 var outputDiv;
24 var hackDiv;
25 var outputFrame;
26 var compilerTimer;
27 var compilerPort;
28 var observer;
29 var cacheStatusElement;
30 bool alwaysRunInWorker = window.localStorage['alwaysRunInWorker'] == 'true';
31 bool verboseCompiler = window.localStorage['verboseCompiler'] == 'true';
32 bool minified = window.localStorage['minified'] == 'true';
33 bool onlyAnalyze = window.localStorage['onlyAnalyze'] == 'true';
34 String codeFont = ((x) => x == null ? '' : x)(window.localStorage['codeFont']);
kasperl 2014/01/07 07:18:43 Maybe just add an extra rawCodeFont variable? This
ahe 2014/01/07 14:06:23 Done.
35 String currentSample = window.localStorage['currentSample'];
36 Theme currentTheme = Theme.named(window.localStorage['theme']);
37 bool applyingSettings = false;
38
39 const String INDENT = '\u{a0}\u{a0}';
40
41 onKeyUp(KeyboardEvent e) {
42 if (e.keyCode == 13) {
43 e.preventDefault();
44 DomSelection selection = window.getSelection();
45 if (selection.isCollapsed && selection.anchorNode is Text) {
46 Text text = selection.anchorNode;
47 int offset = selection.anchorOffset;
48 text.insertData(offset, '\n');
49 selection.collapse(text, offset + 1);
50 }
51 }
52 // This is a hack to get Safari to send mutation events on contenteditable.
53 var newDiv = new DivElement();
54 hackDiv.replaceWith(newDiv);
55 hackDiv = newDiv;
56 }
57
58 bool isMalformedInput = false;
59 String currentSource = "";
60
61 onMutation(List<MutationRecord> mutations, MutationObserver observer) {
kasperl 2014/01/07 07:18:43 This method is very long. Maybe break it into a fe
ahe 2014/01/07 14:06:23 Totally agree. I'll add a TODO for now.
62 scheduleCompilation();
63
64 for (Element element in inputPre.queryAll('a[class="diagnostic"]>span')) {
65 element.remove();
66 }
67 // Discard clean-up mutations.
68 observer.takeRecords();
69
70 DomSelection selection = window.getSelection();
71
72 while (!mutations.isEmpty) {
73 for (MutationRecord record in mutations) {
74 String type = record.type;
75 switch (type) {
76
77 case 'characterData':
kasperl 2014/01/07 07:18:43 Indent cases.
ahe 2014/01/07 14:06:23 OK. That was hard: (setq my-dart-style '((c
78
79 bool hasSelection = false;
80 int offset = selection.anchorOffset;
81 if (selection.isCollapsed && selection.anchorNode == record.target) {
82 hasSelection = true;
83 }
84 var parent = record.target.parentNode;
85 if (parent != inputPre) {
86 inlineChildren(parent);
87 }
88 if (hasSelection) {
89 selection.collapse(record.target, offset);
90 }
91 break;
92
93 default:
94 if (!record.addedNodes.isEmpty) {
95 for (var node in record.addedNodes) {
96
97 if (node.nodeType != Node.ELEMENT_NODE) continue;
98
99 if (node is BRElement) {
100 if (selection.anchorNode != node) {
101 node.replaceWith(new Text('\n'));
102 }
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 }
122 }
123 }
124 }
125 }
126 mutations = observer.takeRecords();
127 }
128
129 if (!inputPre.nodes.isEmpty && inputPre.nodes.last is Text) {
130 Text text = inputPre.nodes.last;
131 if (!text.text.endsWith('\n')) {
132 text.appendData('\n');
133 }
134 }
135
136 int offset = 0;
137 int anchorOffset = 0;
138 bool hasSelection = false;
139 Node anchorNode = selection.anchorNode;
140 void walk4(Node node) {
141 // TODO(ahe): Use TreeWalker when that is exposed.
142 // function textNodesUnder(root){
143 // var n, a=[], walk=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,n ull,false);
kasperl 2014/01/07 07:18:43 Long line.
ahe 2014/01/07 14:06:23 Done.
144 // while(n=walk.nextNode()) a.push(n);
145 // return a;
146 // }
147 int type = node.nodeType;
148 if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
149 if (anchorNode == node) {
150 hasSelection = true;
151 anchorOffset = selection.anchorOffset + offset;
152 return;
153 }
154 offset += node.length;
155 }
156
157 var child = node.$dom_firstChild;
158 while(child != null) {
kasperl 2014/01/07 07:18:43 DANGER. DANGER. You know the drill!
ahe 2014/01/07 14:06:23 Done.
159 walk4(child);
160 if (hasSelection) return;
161 child = child.nextNode;
162 }
163 }
164 if (selection.isCollapsed) {
165 walk4(inputPre);
166 }
167
168 currentSource = inputPre.text;
169 inputPre.nodes.clear();
170 inputPre.appendText(currentSource);
171 if (hasSelection) {
172 selection.collapse(inputPre.$dom_firstChild, anchorOffset);
173 }
174
175 isMalformedInput = false;
176 for (Node node in new List.from(inputPre.nodes)) {
177 if (node is! Text) continue;
178 String text = node.text;
179
180 var token = new StringScanner(text, includeComments: true).tokenize();
181 int offset = 0;
182 for (;token.kind != EOF_TOKEN; token = token.next) {
183 Decoration decoration = getDecoration(token);
184 if (decoration == null) continue;
185 bool hasSelection = false;
186 int selectionOffset = selection.anchorOffset;
187
188 if (selection.isCollapsed && selection.anchorNode == node) {
189 hasSelection = true;
190 selectionOffset = selection.anchorOffset;
191 }
192 int splitPoint = token.charOffset - offset;
193 Text str = node.splitText(splitPoint);
194 Text after = str.splitText(token.slowCharCount);
195 offset += splitPoint + token.slowCharCount;
196 inputPre.insertBefore(after, node.nextNode);
197 inputPre.insertBefore(decoration.applyTo(str), after);
198
199 if (hasSelection && selectionOffset > node.length) {
200 selectionOffset -= node.length;
201 if (selectionOffset > str.length) {
202 selectionOffset -= str.length;
203 selection.collapse(after, selectionOffset);
204 } else {
205 selection.collapse(str, selectionOffset);
206 }
207 }
208 node = after;
209 }
210 }
211
212 window.localStorage['currentSource'] = currentSource;
213
214 // Discard highlighting mutations.
215 observer.takeRecords();
216 }
217
218 addDiagnostic(String kind, String message, int begin, int end) {
219 observer.disconnect();
220 DomSelection selection = window.getSelection();
221 int offset = 0;
222 int anchorOffset = 0;
223 bool hasSelection = false;
224 Node anchorNode = selection.anchorNode;
225 bool foundNode = false;
226 void walk4(Node node) {
kasperl 2014/01/07 07:18:43 Could this be refactored somehow? You have walk4 i
ahe 2014/01/07 14:06:23 This might be fixed by using TreeWalker.
227 // TODO(ahe): Use TreeWalker when that is exposed.
228 int type = node.nodeType;
229 if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
230 // print('walking: ${node.data}');
231 if (anchorNode == node) {
232 hasSelection = true;
233 anchorOffset = selection.anchorOffset + offset;
234 }
235 int newOffset = offset + node.length;
236 if (offset <= begin && begin < newOffset) {
237 hasSelection = node == anchorNode;
238 anchorOffset = selection.anchorOffset;
239 Node marker = new Text("");
240 node.replaceWith(marker);
241 // TODO(ahe): Don't highlight everything in the node. Find
242 // the relevant token.
243 if (kind == 'error') {
244 marker.replaceWith(diagnostic(node, error(message)));
245 } else if (kind == 'warning') {
246 marker.replaceWith(diagnostic(node, warning(message)));
247 } else {
248 marker.replaceWith(diagnostic(node, info(message)));
249 }
250 if (hasSelection) {
251 selection.collapse(node, anchorOffset);
252 }
253 foundNode = true;
254 return;
255 }
256 offset = newOffset;
257 } else if (type == Node.ELEMENT_NODE) {
258 if (node.classes.contains('alert')) return;
259 }
260
261 var child = node.$dom_firstChild;
262 while(child != null && !foundNode) {
263 walk4(child);
264 child = child.nextNode;
265 }
266 }
267 walk4(inputPre);
268
269 if (!foundNode) {
270 outputDiv.appendText('$message\n');
271 }
272
273 observer.takeRecords();
274 observer.observe(inputPre, childList: true, characterData: true, subtree: true );
kasperl 2014/01/07 07:18:43 Long line.
ahe 2014/01/07 14:06:23 Done.
275 }
276
277 void inlineChildren(Element element) {
278 if (element == null) return;
279 var parent = element.parentNode;
280 if (parent == null) return;
281 for (Node child in new List.from(element.nodes)) {
282 child.remove();
283 parent.insertBefore(child, element);
284 }
285 element.remove();
286 }
287
288 int count = 0;
289
290 void scheduleCompilation() {
291 if (applyingSettings) return;
292 if (compilerTimer != null) {
293 compilerTimer.cancel();
294 compilerTimer = null;
295 }
296 compilerTimer =
297 new Timer(const Duration(milliseconds: 500), startCompilation);
298 }
299
300 void startCompilation() {
301 if (compilerTimer != null) {
302 compilerTimer.cancel();
303 compilerTimer = null;
304 }
305
306 new CompilationProcess(currentSource, outputDiv).start();
307 }
308
309 class CompilationProcess {
310 final String source;
311 final Element console;
312 final ReceivePort receivePort = new ReceivePort();
313 bool isCleared = false;
314 bool isDone = false;
315 bool usesDartHtml = false;
316 Worker worker;
317 List<String> objectUrls = <String>[];
318
319 static CompilationProcess current;
320
321 CompilationProcess(this.source, this.console);
322
323 static bool shouldStartCompilation() {
324 if (compilerPort == null) return false;
325 if (isMalformedInput) return false;
326 if (current != null) return current.isDone;
327 return true;
328 }
329
330 void clear() {
331 if (verboseCompiler) return;
332 if (!isCleared) console.nodes.clear();
333 isCleared = true;
334 }
335
336 void start() {
337 if (!shouldStartCompilation()) {
338 receivePort.close();
339 if (!isMalformedInput) scheduleCompilation();
340 return;
341 }
342 if (current != null) current.dispose();
343 current = this;
344 console.nodes.clear();
345 var options = [];
346 if (verboseCompiler) options.add('--verbose');
347 if (minified) options.add('--minify');
348 if (onlyAnalyze) options.add('--analyze-only');
349 compilerPort.send(['options', options], receivePort.toSendPort());
350 console.appendHtml('<i class="icon-spinner icon-spin"></i>');
351 console.appendText(' Compiling Dart program...\n');
352 outputFrame.style.display = 'none';
353 receivePort.receive(onMessage);
354 compilerPort.send(source, receivePort.toSendPort());
355 }
356
357 void dispose() {
358 if (worker != null) worker.terminate();
359 objectUrls.forEach(Url.revokeObjectUrl);
360 }
361
362 onMessage(message, _) {
363 String kind = message is String ? message : message[0];
364 var data = (message is List && message.length == 2) ? message[1] : null;
365 switch (kind) {
366 case 'done': return onDone(data);
kasperl 2014/01/07 07:18:43 I'd indent all the cases.
ahe 2014/01/07 14:06:23 Done.
367 case 'url': return onUrl(data);
368 case 'code': return onCode(data);
369 case 'diagnostic': return onDiagnostic(data);
370 case 'crash': return onCrash(data);
371 case 'failed': return onFail(data);
372 case 'dart:html': return onDartHtml(data);
373 default:
374 throw ['Unknown message kind', message];
375 }
376 }
377
378 onDartHtml(_) {
379 usesDartHtml = true;
380 }
381
382 onFail(_) {
383 clear();
384 consolePrint('Compilation failed');
385 }
386
387 onDone(_) {
388 isDone = true;
389 receivePort.close();
390 }
391
392 // This is called in browsers that support creating Object URLs in a
393 // web worker. For example, Chrome and Firefox 21.
394 onUrl(String url) {
395 objectUrls.add(url);
396 clear();
397 String wrapper =
398 'function dartPrint(msg) { self.postMessage(msg); };'
399 'self.importScripts("$url");';
400 var wrapperUrl =
401 Url.createObjectUrl(new Blob([wrapper], 'application/javascript'));
402 objectUrls.add(wrapperUrl);
403 void retryInIframe(_) {
404 var frame = makeOutputFrame(url);
405 outputFrame.replaceWith(frame);
406 outputFrame = frame;
407 }
408 void onError(String errorMessage) {
409 console.appendText(errorMessage);
410 console.appendText(' ');
411 console.append(buildButton('Try in iframe', retryInIframe));
412 console.appendText('\n');
413 }
414 if (usesDartHtml && !alwaysRunInWorker) {
415 retryInIframe(null);
416 } else {
417 runInWorker(wrapperUrl, onError);
418 }
419 }
420
421 // This is called in browsers that do not support creating Object
422 // URLs in a web worker. For example, Safari and Firefox < 21.
423 onCode(String code) {
424 clear();
425
426 void retryInIframe(_) {
427 // The obvious thing would be to call [makeOutputFrame], but
428 // Safari doesn't support access to Object URLs in an iframe.
429
430 var frame = new IFrameElement()
431 ..src = 'iframe.html'
432 ..style.width = '100%'
433 ..style.height = '0px'
434 ..seamless = false;
435 frame.onLoad.listen((_) {
436 frame.contentWindow.postMessage(['source', code], '*');
437 });
438 outputFrame.replaceWith(frame);
439 outputFrame = frame;
440 }
441
442 void onError(String errorMessage) {
443 console.appendText(errorMessage);
444 console.appendText(' ');
445 console.append(buildButton('Try in iframe', retryInIframe));
446 console.appendText('\n');
447 }
448
449 String codeWithPrint =
450 '$code\n'
451 'function dartPrint(msg) { postMessage(msg); }\n';
452 var url =
453 Url.createObjectUrl(
454 new Blob([codeWithPrint], 'application/javascript'));
455 objectUrls.add(url);
456
457 if (usesDartHtml && !alwaysRunInWorker) {
458 retryInIframe(null);
459 } else {
460 runInWorker(url, onError);
461 }
462 }
463
464 void runInWorker(String url, void onError(String errorMessage)) {
465 worker = new Worker(url)
466 ..onMessage.listen((MessageEvent event) {
467 consolePrint(event.data);
468 })
469 ..onError.listen((ErrorEvent event) {
470 worker.terminate();
471 worker = null;
472 onError(event.message);
473 });
474 }
475
476 onDiagnostic(Map<String, dynamic> diagnostic) {
477 String kind = diagnostic['kind'];
478 String message = diagnostic['message'];
479 if (kind == 'verbose info') {
480 if (verboseCompiler) {
481 consolePrint(message);
482 }
483 return;
484 }
485 String uri = diagnostic['uri'];
486 if (uri == null) {
487 clear();
488 consolePrint(message);
489 return;
490 }
491 if (uri != 'memory:/main.dart') return;
492 if (currentSource != source) return;
493 int begin = diagnostic['begin'];
494 int end = diagnostic['end'];
495 if (begin == null) return;
496 addDiagnostic(kind, message, begin, end);
497 }
498
499 onCrash(data) {
500 consolePrint(data);
501 }
502
503 void consolePrint(message) {
504 console.appendText('$message\n');
505 }
506 }
507
508 Decoration getDecoration(scanner.Token token) {
509 String tokenValue = token.slowToString();
510 String tokenInfo = token.info.value.slowToString();
511 if (tokenInfo == 'string') return currentTheme.string;
512 // if (tokenInfo == 'identifier') return identifier;
513 if (tokenInfo == 'keyword') return currentTheme.keyword;
514 if (tokenInfo == 'comment') return currentTheme.singleLineComment;
515 if (tokenInfo == 'malformed input') {
516 isMalformedInput = true;
517 return new DiagnosticDecoration('error', tokenValue);
518 }
519 return null;
520 }
521
522 diagnostic(text, tip) {
523 if (text is String) {
524 text = new Text(text);
525 }
526 return new AnchorElement()
527 ..classes.add('diagnostic')
528 ..append(text)
529 ..append(tip);
530 }
531
532 img(src, width, height, alt) {
533 return new ImageElement(src: src, width: width, height: height)..alt = alt;
534 }
535
536 makeOutputFrame(String scriptUrl) {
537 final String outputHtml = '''
538 <!DOCTYPE html>
539 <html lang="en">
540 <head>
541 <title>JavaScript output</title>
542 <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
543 </head>
544 <body>
545 <script type="application/javascript" src="$outputHelper"></script>
546 <script type="application/javascript" src="$scriptUrl"></script>
547 </body>
548 </html>
549 ''';
550
551 return new IFrameElement()
552 ..src = Url.createObjectUrl(new Blob([outputHtml], "text/html"))
553 ..style.width = '100%'
554 ..style.height = '0px'
555 ..seamless = false;
556 }
557
558 const String HAS_NON_DOM_HTTP_REQUEST = 'spawnFunction supports HttpRequest';
559 const String NO_NON_DOM_HTTP_REQUEST =
560 'spawnFunction does not support HttpRequest';
561
562
563 checkHttpRequest() {
564 port.receive((String uri, SendPort replyTo) {
565 try {
566 new HttpRequest();
567 replyTo.send(HAS_NON_DOM_HTTP_REQUEST);
568 } catch (e, trace) {
569 replyTo.send(NO_NON_DOM_HTTP_REQUEST);
570 }
571 port.close();
572 });
573 }
574
575 main() {
576 if (window.localStorage['currentSource'] == null) {
577 window.localStorage['currentSource'] = EXAMPLE_HELLO;
578 }
579
580 buildUI();
581 spawnFunction(checkHttpRequest).call('').then((reply) {
582 var compilerFuture;
583 if (reply == HAS_NON_DOM_HTTP_REQUEST) {
584 compilerFuture = spawnFunction(compilerIsolate);
585 } else {
586 compilerFuture = spawnDomFunction(compilerIsolate);
587 }
588 if (compilerFuture is! Future) {
589 compilerFuture = new Future.value(compilerFuture);
590 }
591 compilerFuture.then((port) {
592 String sdk = query('link[rel="dart-sdk"]').href;
593 print('Using Dart SDK: $sdk');
594 port.call(sdk).then((_) {
595 compilerPort = port;
596 onMutation([], observer);
597 });
598 });
599 });
600 }
601
602 buildButton(message, action) {
603 if (message is String) {
604 message = new Text(message);
605 }
606 return new ButtonElement()
607 ..onClick.listen(action)
608 ..append(message);
609 }
610
611 buildTab(message, id, action) {
612 if (message is String) {
613 message = new Text(message);
614 }
615
616 onClick(MouseEvent event) {
617 event.preventDefault();
618 Element e = event.target;
619 LIElement parent = e.parent;
620 parent.parent.query('li[class="active"]').classes.remove('active');
621 parent.classes.add('active');
622 action(event);
623 }
624
625 inspirationCallbacks[id] = action;
626
627 return new OptionElement()..append(message)..id = id;
628 }
629
630 Map<String, Function> inspirationCallbacks = new Map<String, Function>();
631
632 void onInspirationChange(Event event) {
633 SelectElement select = event.target;
634 String id = select.queryAll('option')[select.selectedIndex].id;
635 Function action = inspirationCallbacks[id];
636 if (action != null) action(event);
637 outputFrame.style.display = 'none';
638 }
639
640 buildUI() {
641 window.localStorage['currentSample'] = '$currentSample';
642
643 var inspirationTabs = document.getElementById('inspiration');
644 var htmlGroup = new OptGroupElement()..label = 'HTML';
645 var benchmarkGroup = new OptGroupElement()..label = 'Benchmarks';
646 inspirationTabs.append(new OptionElement()..appendText('Pick an example'));
647 inspirationTabs.onChange.listen(onInspirationChange);
648 // inspirationTabs.classes.addAll(['nav', 'nav-tabs']);
649 inspirationTabs.append(buildTab('Hello, World!', 'EXAMPLE_HELLO', (_) {
650 inputPre
651 ..nodes.clear()
652 ..appendText(EXAMPLE_HELLO);
653 }));
654 inspirationTabs.append(buildTab('Fibonacci', 'EXAMPLE_FIBONACCI', (_) {
655 inputPre
656 ..nodes.clear()
657 ..appendText(EXAMPLE_FIBONACCI);
658 }));
659 inspirationTabs.append(htmlGroup);
660 inspirationTabs.append(benchmarkGroup);
661
662 htmlGroup.append(
663 buildTab('Hello, World!', 'EXAMPLE_HELLO_HTML', (_) {
664 inputPre
665 ..nodes.clear()
666 ..appendText(EXAMPLE_HELLO_HTML);
667 }));
668 htmlGroup.append(
669 buildTab('Fibonacci', 'EXAMPLE_FIBONACCI_HTML', (_) {
670 inputPre
671 ..nodes.clear()
672 ..appendText(EXAMPLE_FIBONACCI_HTML);
673 }));
674 htmlGroup.append(buildTab('Sunflower', 'EXAMPLE_SUNFLOWER', (_) {
675 inputPre
676 ..nodes.clear()
677 ..appendText(EXAMPLE_SUNFLOWER);
678 }));
679
680 benchmarkGroup.append(buildTab('DeltaBlue', 'BENCHMARK_DELTA_BLUE', (_) {
681 inputPre.contentEditable = 'false';
682 String deltaBlueUri = query('link[rel="benchmark-DeltaBlue"]').href;
683 String benchmarkBaseUri = query('link[rel="benchmark-base"]').href;
684 HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) {
685 HttpRequest.getString(deltaBlueUri).then((String deltaBlue) {
686 benchmarkBase = benchmarkBase.replaceFirst(
687 'part of benchmark_harness;', '// part of benchmark_harness;');
688 deltaBlue = deltaBlue.replaceFirst(
689 "import 'package:benchmark_harness/benchmark_harness.dart';",
690 benchmarkBase);
691 inputPre
692 ..nodes.clear()
693 ..appendText(deltaBlue)
694 ..contentEditable = 'true';
695 });
696 });
697 }));
698
699 benchmarkGroup.append(buildTab('Richards', 'BENCHMARK_RICHARDS', (_) {
700 inputPre.contentEditable = 'false';
701 String richardsUri = query('link[rel="benchmark-Richards"]').href;
702 String benchmarkBaseUri = query('link[rel="benchmark-base"]').href;
703 HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) {
704 HttpRequest.getString(richardsUri).then((String richards) {
705 benchmarkBase = benchmarkBase.replaceFirst(
706 'part of benchmark_harness;', '// part of benchmark_harness;');
707 richards = richards.replaceFirst(
708 "import 'package:benchmark_harness/benchmark_harness.dart';",
709 benchmarkBase);
710 inputPre
711 ..nodes.clear()
712 ..appendText(richards)
713 ..contentEditable = 'true';
714 });
715 });
716 }));
717
718 // TODO(ahe): Update currentSample. Or try switching to a drop-down menu.
719 var active = inspirationTabs.query('[id="$currentSample"]');
720 if (active == null) {
721 // inspirationTabs.query('li').classes.add('active');
722 }
723
724 (inputPre = new DivElement())
725 ..classes.add('well')
726 ..style.backgroundColor = currentTheme.background.color
727 ..style.color = currentTheme.foreground.color
728 ..style.overflow = 'auto'
729 ..style.whiteSpace = 'pre'
730 ..style.font = codeFont
731 ..spellcheck = false;
732
733 inputPre.contentEditable = 'true';
734 inputPre.onKeyDown.listen(onKeyUp);
735
736 var inputWrapper = new DivElement()
737 ..append(inputPre)
738 ..style.position = 'relative';
739
740 var inputHeader = new DivElement()..appendText('Code');
741
742 inputHeader.style
743 ..right = '3px'
744 ..top = '0px'
745 ..position = 'absolute';
746 inputWrapper.append(inputHeader);
747
748 outputFrame =
749 makeOutputFrame(
750 Url.createObjectUrl(new Blob([''], 'application/javascript')));
751
752 outputDiv = new PreElement();
753 outputDiv.style
754 ..backgroundColor = currentTheme.background.color
755 ..color = currentTheme.foreground.color
756 ..overflow = 'auto'
757 ..padding = '1em'
758 ..minHeight = '10em'
759 ..whiteSpace = 'pre-wrap';
760
761 var outputWrapper = new DivElement()
762 ..append(outputDiv)
763 ..style.position = 'relative';
764
765 var consoleHeader = new DivElement()..appendText('Console');
766
767 consoleHeader.style
768 ..right = '3px'
769 ..top = '0px'
770 ..position = 'absolute';
771 outputWrapper.append(consoleHeader);
772
773 hackDiv = new DivElement();
774
775 var saveButton = new ButtonElement()
776 ..onClick.listen((_) {
777 var blobUrl =
778 Url.createObjectUrl(new Blob([inputPre.text], 'text/plain'));
779 var save = new AnchorElement(href: blobUrl);
780 save.target = '_blank';
781 save.download = 'untitled.dart';
782 save.dispatchEvent(new Event.eventType('Event', 'click'));
783 })
784 ..style.position = 'absolute'
785 ..style.right = '0px'
786 ..appendText('Save');
787
788 cacheStatusElement = document.getElementById('appcache-status');
789 updateCacheStatus();
790
791 // TODO(ahe): Switch to two column layout so the console is on the right.
792 var section = document.query('article[class="homepage"]>section');
793
794 DivElement tryColumn = document.getElementById('try-dart-column');
795 DivElement runColumn = document.getElementById('run-dart-column');
796
797 tryColumn.append(inputWrapper);
798 outputFrame.style.display = 'none';
799 runColumn.append(outputFrame);
800 runColumn.append(outputWrapper);
801 runColumn.append(hackDiv);
802
803 var settingsElement = document.getElementById('settings');
804 settingsElement.onClick.listen(openSettings);
805
806 window.onMessage.listen((MessageEvent event) {
807 if (event.data is List) {
808 List message = event.data;
809 if (message.length > 0) {
810 switch (message[0]) {
811 case 'error':
812 Map diagnostics = message[1];
813 String url = diagnostics['url'];
814 outputDiv.appendText('${diagnostics["message"]}\n');
815 return;
816 case 'scrollHeight':
817 int scrollHeight = message[1];
818 if (scrollHeight > 0) {
819 outputFrame.style.height = '${scrollHeight}px';
820 }
821 return;
822 }
823 }
824 }
825 outputDiv.appendText('${event.data}\n');
826 });
827
828 observer = new MutationObserver(onMutation)
829 ..observe(inputPre, childList: true, characterData: true, subtree: true);
830
831 window.setImmediate(() {
832 inputPre.appendText(window.localStorage['currentSource']);
833 });
834
835 // You cannot install event handlers on window.applicationCache
836 // until the window has loaded. In dartium, that's later than this
837 // method is called.
838 window.onLoad.listen(onLoad);
839
840 // However, in dart2js, the window has already loaded, and onLoad is
841 // never called.
842 onLoad(null);
843 }
844
845 void openSettings(MouseEvent event) {
846 event.preventDefault();
847
848 var backdrop = new DivElement()..classes.add('modal-backdrop');
849 document.body.append(backdrop);
850
851 void updateCodeFont(Event e) {
852 codeFont = e.target.value;
853 inputPre.style.font = codeFont;
854 backdrop.style.opacity = '0.0';
855 }
856
857 void updateTheme(Event e) {
858 var select = e.target;
859 String theme = select.queryAll('option')[select.selectedIndex].text;
860 window.localStorage['theme'] = theme;
861 currentTheme = Theme.named(theme);
862
863 inputPre.style
864 ..backgroundColor = currentTheme.background.color
865 ..color = currentTheme.foreground.color;
866
867 outputDiv.style
868 ..backgroundColor = currentTheme.background.color
869 ..color = currentTheme.foreground.color;
870
871 backdrop.style.opacity = '0.0';
872
873 applyingSettings = true;
874 onMutation([], observer);
875 applyingSettings = false;
876 }
877
878
879 var body = document.getElementById('settings-body');
880
881 body.nodes.clear();
882
883 var form = new FormElement();
884 var fieldSet = new FieldSetElement();
885 body.append(form);
886 form.append(fieldSet);
887
888 buildCheckBox(String text, bool defaultValue, void action(Event e)) {
889 var checkBox = new CheckboxInputElement()
890 ..defaultChecked = defaultValue
891 ..onChange.listen(action);
892 return new LabelElement()
893 ..classes.add('checkbox')
894 ..append(checkBox)
895 ..appendText(' $text');
896 }
897
898 fieldSet.append(
kasperl 2014/01/07 07:18:43 Maybe it would make sense to have an abstraction o
ahe 2014/01/07 14:06:23 Added TODO.
899 buildCheckBox(
900 'Always run in Worker thread.', alwaysRunInWorker,
901 (Event e) { alwaysRunInWorker = e.target.checked; }));
902
903 fieldSet.append(
904 buildCheckBox(
905 'Verbose compiler output.', verboseCompiler,
906 (Event e) { verboseCompiler = e.target.checked; }));
907
908 fieldSet.append(
909 buildCheckBox(
910 'Generate compact (minified) JavaScript.', minified,
911 (Event e) { minified = e.target.checked; }));
912
913 fieldSet.append(
914 buildCheckBox(
915 'Only analyze program.', onlyAnalyze,
916 (Event e) { onlyAnalyze = e.target.checked; }));
917
918 fieldSet.append(new LabelElement()..appendText('Code font:'));
919 var textInput = new TextInputElement();
920 textInput.classes.add('input-block-level');
921 if (codeFont != null && codeFont != '') {
922 textInput.value = codeFont;
923 }
924 textInput.placeholder = 'Enter a size and font, for example, 11pt monospace';
925 textInput.onChange.listen(updateCodeFont);
926 fieldSet.append(textInput);
927
928 fieldSet.append(new LabelElement()..appendText('Theme:'));
929 var themeSelector = new SelectElement();
930 themeSelector.classes.add('input-block-level');
931 for (Theme theme in THEMES) {
932 OptionElement option = new OptionElement()..appendText(theme.name);
933 if (theme == currentTheme) option.selected = true;
934 themeSelector.append(option);
935 }
936 themeSelector.onChange.listen(updateTheme);
937 fieldSet.append(themeSelector);
938
939 var dialog = document.getElementById('settings-dialog');
940
941 dialog.style.display = 'block';
942 dialog.classes.add('in');
943
944 onSubmit(Event event) {
945 event.preventDefault();
946
947 window.localStorage['alwaysRunInWorker'] = '$alwaysRunInWorker';
948 window.localStorage['verboseCompiler'] = '$verboseCompiler';
949 window.localStorage['minified'] = '$minified';
950 window.localStorage['onlyAnalyze'] = '$onlyAnalyze';
951 window.localStorage['codeFont'] = '$codeFont';
952
953 dialog.style.display = 'none';
954 dialog.classes.remove('in');
955 backdrop.remove();
956 }
957 form.onSubmit.listen(onSubmit);
958
959 var doneButton = document.getElementById('settings-done');
960 doneButton.onClick.listen(onSubmit);
961 }
962
963 /// Called when the window has finished loading.
964 void onLoad(Event event) {
965 window.applicationCache.onUpdateReady.listen((_) => updateCacheStatus());
966 window.applicationCache.onCached.listen((_) => updateCacheStatus());
967 window.applicationCache.onChecking.listen((_) => updateCacheStatus());
968 window.applicationCache.onDownloading.listen((_) => updateCacheStatus());
969 window.applicationCache.onError.listen((_) => updateCacheStatus());
970 window.applicationCache.onNoUpdate.listen((_) => updateCacheStatus());
971 window.applicationCache.onObsolete.listen((_) => updateCacheStatus());
972 window.applicationCache.onProgress.listen(onCacheProgress);
973 }
974
975 onCacheProgress(ProgressEvent event) {
976 if (!event.lengthComputable) {
977 updateCacheStatus();
978 return;
979 }
980 cacheStatusElement.nodes.clear();
981 cacheStatusElement.appendText('Downloading SDK ');
982 var progress = '${event.loaded} of ${event.total}';
983 if (MeterElement.supported) {
984 cacheStatusElement.append(
985 new MeterElement()
986 ..appendText(progress)
987 ..min = 0
988 ..max = event.total
989 ..value = event.loaded);
990 } else {
991 cacheStatusElement.appendText(progress);
992 }
993 }
994
995 String cacheStatus() {
996 if (!ApplicationCache.supported) return 'offline not supported';
997 int status = window.applicationCache.status;
998 if (status == ApplicationCache.CHECKING) return 'Checking for updates';
999 if (status == ApplicationCache.DOWNLOADING) return 'Downloading SDK';
1000 if (status == ApplicationCache.IDLE) return 'Try Dart! works offline';
1001 if (status == ApplicationCache.OBSOLETE) return 'OBSOLETE';
1002 if (status == ApplicationCache.UNCACHED) return 'offline not available';
1003 if (status == ApplicationCache.UPDATEREADY) return 'SDK downloaded';
1004 return '?';
1005 }
1006
1007 void updateCacheStatus() {
1008 cacheStatusElement.nodes.clear();
1009 String status = window.applicationCache.status;
1010 if (status == ApplicationCache.UPDATEREADY) {
1011 cacheStatusElement.appendText('New version of Try Dart! ready: ');
1012 cacheStatusElement.append(
1013 new AnchorElement(href: '#')
1014 ..appendText('Load')
1015 ..onClick.listen((event) {
1016 event.preventDefault();
1017 window.applicationCache.swapCache();
1018 window.location.reload();
1019 }));
1020 } else if (status == ApplicationCache.IDLE) {
1021 cacheStatusElement.appendText(cacheStatus());
1022 cacheStatusElement.classes.add('offlineyay');
1023 new Timer(const Duration(seconds: 10), () {
1024 cacheStatusElement.style.display = 'none';
1025 });
1026 } else {
1027 cacheStatusElement.appendText(cacheStatus());
1028 }
1029 }
1030
1031 void compilerIsolate() {
1032 lazy.load().then((_) => port.receive(compile));
1033 }
1034
1035 final String outputHelper =
1036 Url.createObjectUrl(new Blob([OUTPUT_HELPER], 'application/javascript'));
1037
1038 const String EXAMPLE_HELLO = r'''
1039 // Go ahead and modify this example.
1040
1041 var greeting = "Hello, World!";
1042
1043 // Prints a greeting.
1044 void main() {
1045 // The [print] function displays a message in the "Console" box.
1046 // Try modifying the greeting above and watch the "Console" box change.
1047 print(greeting);
1048 }
1049 ''';
1050
1051 const String EXAMPLE_HELLO_HTML = r'''
1052 // Go ahead and modify this example.
1053
1054 import "dart:html";
1055
1056 var greeting = "Hello, World!";
1057
1058 // Displays a greeting.
1059 void main() {
1060 // This example uses HTML to display the greeting and it will appear
1061 // in a nested HTML frame (an iframe).
1062 document.body.append(new HeadingElement.h1()..appendText(greeting));
1063 }
1064 ''';
1065
1066 const String EXAMPLE_FIBONACCI = r'''
1067 // Go ahead and modify this example.
1068
1069 // Computes the nth Fibonacci number.
1070 int fibonacci(int n) {
1071 if (n < 2) return n;
1072 return fibonacci(n - 1) + fibonacci(n - 2);
1073 }
1074
1075 // Prints a Fibonacci number.
1076 void main() {
1077 int i = 20;
1078 String message = "fibonacci($i) = ${fibonacci(i)}";
1079 // Print the result in the "Console" box.
1080 print(message);
1081 }
1082 ''';
1083
1084 const String EXAMPLE_FIBONACCI_HTML = r'''
1085 // Go ahead and modify this example.
1086
1087 import "dart:html";
1088
1089 // Computes the nth Fibonacci number.
1090 int fibonacci(int n) {
1091 if (n < 2) return n;
1092 return fibonacci(n - 1) + fibonacci(n - 2);
1093 }
1094
1095 // Displays a Fibonacci number.
1096 void main() {
1097 int i = 20;
1098 String message = "fibonacci($i) = ${fibonacci(i)}";
1099
1100 // This example uses HTML to display the result and it will appear
1101 // in a nested HTML frame (an iframe).
1102 document.body.append(new HeadingElement.h1()..appendText(message));
1103 }
1104 ''';
1105
1106 const String OUTPUT_HELPER = r'''
1107 function dartPrint(msg) {
1108 window.parent.postMessage(String(msg), "*");
1109 }
1110
1111 function dartMainRunner(main) {
1112 main();
1113 }
1114
1115 window.onerror = function (message, url, lineNumber) {
1116 window.parent.postMessage(
1117 ["error", {message: message, url: url, lineNumber: lineNumber}], "*");
1118 };
1119
1120 (function () {
1121
1122 function postScrollHeight() {
1123 window.parent.postMessage(["scrollHeight", document.documentElement.scrollHeig ht], "*");
1124 }
1125
1126 var observer = new (window.MutationObserver||window.WebKitMutationObserver||wind ow.MozMutationObserver)(function(mutations) {
1127 postScrollHeight()
1128 window.setTimeout(postScrollHeight, 500);
1129 });
1130
1131 observer.observe(
1132 document.body,
1133 { attributes: true,
1134 childList: true,
1135 characterData: true,
1136 subtree: true });
1137 })();
1138 ''';
1139
1140 const String EXAMPLE_SUNFLOWER = '''
1141 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
1142 // for details. All rights reserved. Use of this source code is governed by a
1143 // BSD-style license that can be found in the LICENSE file.
1144
1145 library sunflower;
1146
1147 import "dart:html";
1148 import "dart:math";
1149
1150 const String ORANGE = "orange";
1151 const int SEED_RADIUS = 2;
1152 const int SCALE_FACTOR = 4;
1153 const num TAU = PI * 2;
1154 const int MAX_D = 300;
1155 const num centerX = MAX_D / 2;
1156 const num centerY = centerX;
1157
1158 final InputElement slider = query("#slider");
1159 final Element notes = query("#notes");
1160 final num PHI = (sqrt(5) + 1) / 2;
1161 int seeds = 0;
1162 final CanvasRenderingContext2D context =
1163 (query("#canvas") as CanvasElement).context2D;
1164
1165 void main() {
1166 document.head.append(new StyleElement()..appendText(STYLE));
1167 document.body.innerHtml = BODY;
1168 slider.onChange.listen((e) => draw());
1169 draw();
1170 }
1171
1172 /// Draw the complete figure for the current number of seeds.
1173 void draw() {
1174 seeds = int.parse(slider.value);
1175 context.clearRect(0, 0, MAX_D, MAX_D);
1176 for (var i = 0; i < seeds; i++) {
1177 final num theta = i * TAU / PHI;
1178 final num r = sqrt(i) * SCALE_FACTOR;
1179 drawSeed(centerX + r * cos(theta), centerY - r * sin(theta));
1180 }
1181 notes.text = "\${seeds} seeds";
1182 }
1183
1184 /// Draw a small circle representing a seed centered at (x,y).
1185 void drawSeed(num x, num y) {
1186 context..beginPath()
1187 ..lineWidth = 2
1188 ..fillStyle = ORANGE
1189 ..strokeStyle = ORANGE
1190 ..arc(x, y, SEED_RADIUS, 0, TAU, false)
1191 ..fill()
1192 ..closePath()
1193 ..stroke();
1194 }
1195
1196 const String MATH_PNG =
1197 "https://dart.googlecode.com/svn/trunk/dart/samples/sunflower/web/math.png";
1198 const String BODY = """
1199 <h1>drfibonacci\'s Sunflower Spectacular</h1>
1200
1201 <p>A canvas 2D demo.</p>
1202
1203 <div id="container">
1204 <canvas id="canvas" width="300" height="300" class="center"></canvas>
1205 <form class="center">
1206 <input id="slider" type="range" max="1000" value="500"/>
1207 </form>
1208 <br/>
1209 <img src="\$MATH_PNG" width="350px" height="42px" class="center">
1210 </div>
1211
1212 <footer>
1213 <p id="summary"> </p>
1214 <p id="notes"> </p>
1215 </footer>
1216 """;
1217
1218 const String STYLE = r"""
1219 body {
1220 background-color: #F8F8F8;
1221 font-family: 'Open Sans', sans-serif;
1222 font-size: 14px;
1223 font-weight: normal;
1224 line-height: 1.2em;
1225 margin: 15px;
1226 }
1227
1228 p {
1229 color: #333;
1230 }
1231
1232 #container {
1233 width: 100%;
1234 height: 400px;
1235 position: relative;
1236 border: 1px solid #ccc;
1237 background-color: #fff;
1238 }
1239
1240 #summary {
1241 float: left;
1242 }
1243
1244 #notes {
1245 float: right;
1246 width: 120px;
1247 text-align: right;
1248 }
1249
1250 .error {
1251 font-style: italic;
1252 color: red;
1253 }
1254
1255 img {
1256 border: 1px solid #ccc;
1257 margin: auto;
1258 }
1259
1260 .center {
1261 display: block;
1262 margin: 0px auto;
1263 text-align: center;
1264 }
1265 """;
1266
1267 ''';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698