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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: dart/site/try/leap.dart
diff --git a/dart/site/try/leap.dart b/dart/site/try/leap.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1828aa873d57e273f334bc11054bd005f97ddb95
--- /dev/null
+++ b/dart/site/try/leap.dart
@@ -0,0 +1,1267 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library trydart.main;
+
+import 'dart:async';
+import 'dart:html';
+import 'dart:isolate';
+import 'dart:uri';
+
+import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' show StringScanner, EOF_TOKEN;
kasperl 2014/01/07 07:18:43 Long lines.
ahe 2014/01/07 14:06:23 Done.
+import '../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' as scanner;
+
+import 'decoration.dart';
+import 'themes.dart';
+
+@lazy import 'compiler_isolate.dart';
+
+const lazy = const DeferredLibrary('compiler_isolate');
+
+var inputPre;
+var outputDiv;
+var hackDiv;
+var outputFrame;
+var compilerTimer;
+var compilerPort;
+var observer;
+var cacheStatusElement;
+bool alwaysRunInWorker = window.localStorage['alwaysRunInWorker'] == 'true';
+bool verboseCompiler = window.localStorage['verboseCompiler'] == 'true';
+bool minified = window.localStorage['minified'] == 'true';
+bool onlyAnalyze = window.localStorage['onlyAnalyze'] == 'true';
+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.
+String currentSample = window.localStorage['currentSample'];
+Theme currentTheme = Theme.named(window.localStorage['theme']);
+bool applyingSettings = false;
+
+const String INDENT = '\u{a0}\u{a0}';
+
+onKeyUp(KeyboardEvent e) {
+ if (e.keyCode == 13) {
+ e.preventDefault();
+ DomSelection selection = window.getSelection();
+ if (selection.isCollapsed && selection.anchorNode is Text) {
+ Text text = selection.anchorNode;
+ int offset = selection.anchorOffset;
+ text.insertData(offset, '\n');
+ selection.collapse(text, offset + 1);
+ }
+ }
+ // This is a hack to get Safari to send mutation events on contenteditable.
+ var newDiv = new DivElement();
+ hackDiv.replaceWith(newDiv);
+ hackDiv = newDiv;
+}
+
+bool isMalformedInput = false;
+String currentSource = "";
+
+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.
+ scheduleCompilation();
+
+ for (Element element in inputPre.queryAll('a[class="diagnostic"]>span')) {
+ element.remove();
+ }
+ // Discard clean-up mutations.
+ observer.takeRecords();
+
+ DomSelection selection = window.getSelection();
+
+ while (!mutations.isEmpty) {
+ for (MutationRecord record in mutations) {
+ String type = record.type;
+ switch (type) {
+
+ 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
+
+ bool hasSelection = false;
+ int offset = selection.anchorOffset;
+ if (selection.isCollapsed && selection.anchorNode == record.target) {
+ hasSelection = true;
+ }
+ var parent = record.target.parentNode;
+ if (parent != inputPre) {
+ inlineChildren(parent);
+ }
+ if (hasSelection) {
+ selection.collapse(record.target, offset);
+ }
+ break;
+
+ default:
+ if (!record.addedNodes.isEmpty) {
+ for (var node in record.addedNodes) {
+
+ if (node.nodeType != Node.ELEMENT_NODE) continue;
+
+ if (node is BRElement) {
+ if (selection.anchorNode != node) {
+ node.replaceWith(new Text('\n'));
+ }
+ } else {
+ var parent = node.parentNode;
+ if (parent == null) continue;
+ var nodes = new List.from(node.nodes);
+ var style = node.getComputedStyle();
+ if (style.display != 'inline') {
+ var previous = node.previousNode;
+ if (previous is Text) {
+ previous.appendData('\n');
+ } else {
+ parent.insertBefore(new Text('\n'), node);
+ }
+ }
+ for (Node child in nodes) {
+ child.remove();
+ parent.insertBefore(child, node);
+ }
+ node.remove();
+ }
+ }
+ }
+ }
+ }
+ mutations = observer.takeRecords();
+ }
+
+ if (!inputPre.nodes.isEmpty && inputPre.nodes.last is Text) {
+ Text text = inputPre.nodes.last;
+ if (!text.text.endsWith('\n')) {
+ text.appendData('\n');
+ }
+ }
+
+ int offset = 0;
+ int anchorOffset = 0;
+ bool hasSelection = false;
+ Node anchorNode = selection.anchorNode;
+ void walk4(Node node) {
+ // TODO(ahe): Use TreeWalker when that is exposed.
+ // function textNodesUnder(root){
+ // var n, a=[], walk=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,null,false);
kasperl 2014/01/07 07:18:43 Long line.
ahe 2014/01/07 14:06:23 Done.
+ // while(n=walk.nextNode()) a.push(n);
+ // return a;
+ // }
+ int type = node.nodeType;
+ if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
+ if (anchorNode == node) {
+ hasSelection = true;
+ anchorOffset = selection.anchorOffset + offset;
+ return;
+ }
+ offset += node.length;
+ }
+
+ var child = node.$dom_firstChild;
+ while(child != null) {
kasperl 2014/01/07 07:18:43 DANGER. DANGER. You know the drill!
ahe 2014/01/07 14:06:23 Done.
+ walk4(child);
+ if (hasSelection) return;
+ child = child.nextNode;
+ }
+ }
+ if (selection.isCollapsed) {
+ walk4(inputPre);
+ }
+
+ currentSource = inputPre.text;
+ inputPre.nodes.clear();
+ inputPre.appendText(currentSource);
+ if (hasSelection) {
+ selection.collapse(inputPre.$dom_firstChild, anchorOffset);
+ }
+
+ isMalformedInput = false;
+ for (Node node in new List.from(inputPre.nodes)) {
+ if (node is! Text) continue;
+ String text = node.text;
+
+ var token = new StringScanner(text, includeComments: true).tokenize();
+ int offset = 0;
+ for (;token.kind != EOF_TOKEN; token = token.next) {
+ Decoration decoration = getDecoration(token);
+ if (decoration == null) continue;
+ bool hasSelection = false;
+ int selectionOffset = selection.anchorOffset;
+
+ if (selection.isCollapsed && selection.anchorNode == node) {
+ hasSelection = true;
+ selectionOffset = selection.anchorOffset;
+ }
+ int splitPoint = token.charOffset - offset;
+ Text str = node.splitText(splitPoint);
+ Text after = str.splitText(token.slowCharCount);
+ offset += splitPoint + token.slowCharCount;
+ inputPre.insertBefore(after, node.nextNode);
+ inputPre.insertBefore(decoration.applyTo(str), after);
+
+ if (hasSelection && selectionOffset > node.length) {
+ selectionOffset -= node.length;
+ if (selectionOffset > str.length) {
+ selectionOffset -= str.length;
+ selection.collapse(after, selectionOffset);
+ } else {
+ selection.collapse(str, selectionOffset);
+ }
+ }
+ node = after;
+ }
+ }
+
+ window.localStorage['currentSource'] = currentSource;
+
+ // Discard highlighting mutations.
+ observer.takeRecords();
+}
+
+addDiagnostic(String kind, String message, int begin, int end) {
+ observer.disconnect();
+ DomSelection selection = window.getSelection();
+ int offset = 0;
+ int anchorOffset = 0;
+ bool hasSelection = false;
+ Node anchorNode = selection.anchorNode;
+ bool foundNode = false;
+ 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.
+ // TODO(ahe): Use TreeWalker when that is exposed.
+ int type = node.nodeType;
+ if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
+ // print('walking: ${node.data}');
+ if (anchorNode == node) {
+ hasSelection = true;
+ anchorOffset = selection.anchorOffset + offset;
+ }
+ int newOffset = offset + node.length;
+ if (offset <= begin && begin < newOffset) {
+ hasSelection = node == anchorNode;
+ anchorOffset = selection.anchorOffset;
+ Node marker = new Text("");
+ node.replaceWith(marker);
+ // TODO(ahe): Don't highlight everything in the node. Find
+ // the relevant token.
+ if (kind == 'error') {
+ marker.replaceWith(diagnostic(node, error(message)));
+ } else if (kind == 'warning') {
+ marker.replaceWith(diagnostic(node, warning(message)));
+ } else {
+ marker.replaceWith(diagnostic(node, info(message)));
+ }
+ if (hasSelection) {
+ selection.collapse(node, anchorOffset);
+ }
+ foundNode = true;
+ return;
+ }
+ offset = newOffset;
+ } else if (type == Node.ELEMENT_NODE) {
+ if (node.classes.contains('alert')) return;
+ }
+
+ var child = node.$dom_firstChild;
+ while(child != null && !foundNode) {
+ walk4(child);
+ child = child.nextNode;
+ }
+ }
+ walk4(inputPre);
+
+ if (!foundNode) {
+ outputDiv.appendText('$message\n');
+ }
+
+ observer.takeRecords();
+ 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.
+}
+
+void inlineChildren(Element element) {
+ if (element == null) return;
+ var parent = element.parentNode;
+ if (parent == null) return;
+ for (Node child in new List.from(element.nodes)) {
+ child.remove();
+ parent.insertBefore(child, element);
+ }
+ element.remove();
+}
+
+int count = 0;
+
+void scheduleCompilation() {
+ if (applyingSettings) return;
+ if (compilerTimer != null) {
+ compilerTimer.cancel();
+ compilerTimer = null;
+ }
+ compilerTimer =
+ new Timer(const Duration(milliseconds: 500), startCompilation);
+}
+
+void startCompilation() {
+ if (compilerTimer != null) {
+ compilerTimer.cancel();
+ compilerTimer = null;
+ }
+
+ new CompilationProcess(currentSource, outputDiv).start();
+}
+
+class CompilationProcess {
+ final String source;
+ final Element console;
+ final ReceivePort receivePort = new ReceivePort();
+ bool isCleared = false;
+ bool isDone = false;
+ bool usesDartHtml = false;
+ Worker worker;
+ List<String> objectUrls = <String>[];
+
+ static CompilationProcess current;
+
+ CompilationProcess(this.source, this.console);
+
+ static bool shouldStartCompilation() {
+ if (compilerPort == null) return false;
+ if (isMalformedInput) return false;
+ if (current != null) return current.isDone;
+ return true;
+ }
+
+ void clear() {
+ if (verboseCompiler) return;
+ if (!isCleared) console.nodes.clear();
+ isCleared = true;
+ }
+
+ void start() {
+ if (!shouldStartCompilation()) {
+ receivePort.close();
+ if (!isMalformedInput) scheduleCompilation();
+ return;
+ }
+ if (current != null) current.dispose();
+ current = this;
+ console.nodes.clear();
+ var options = [];
+ if (verboseCompiler) options.add('--verbose');
+ if (minified) options.add('--minify');
+ if (onlyAnalyze) options.add('--analyze-only');
+ compilerPort.send(['options', options], receivePort.toSendPort());
+ console.appendHtml('<i class="icon-spinner icon-spin"></i>');
+ console.appendText(' Compiling Dart program...\n');
+ outputFrame.style.display = 'none';
+ receivePort.receive(onMessage);
+ compilerPort.send(source, receivePort.toSendPort());
+ }
+
+ void dispose() {
+ if (worker != null) worker.terminate();
+ objectUrls.forEach(Url.revokeObjectUrl);
+ }
+
+ onMessage(message, _) {
+ String kind = message is String ? message : message[0];
+ var data = (message is List && message.length == 2) ? message[1] : null;
+ switch (kind) {
+ 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.
+ case 'url': return onUrl(data);
+ case 'code': return onCode(data);
+ case 'diagnostic': return onDiagnostic(data);
+ case 'crash': return onCrash(data);
+ case 'failed': return onFail(data);
+ case 'dart:html': return onDartHtml(data);
+ default:
+ throw ['Unknown message kind', message];
+ }
+ }
+
+ onDartHtml(_) {
+ usesDartHtml = true;
+ }
+
+ onFail(_) {
+ clear();
+ consolePrint('Compilation failed');
+ }
+
+ onDone(_) {
+ isDone = true;
+ receivePort.close();
+ }
+
+ // This is called in browsers that support creating Object URLs in a
+ // web worker. For example, Chrome and Firefox 21.
+ onUrl(String url) {
+ objectUrls.add(url);
+ clear();
+ String wrapper =
+ 'function dartPrint(msg) { self.postMessage(msg); };'
+ 'self.importScripts("$url");';
+ var wrapperUrl =
+ Url.createObjectUrl(new Blob([wrapper], 'application/javascript'));
+ objectUrls.add(wrapperUrl);
+ void retryInIframe(_) {
+ var frame = makeOutputFrame(url);
+ outputFrame.replaceWith(frame);
+ outputFrame = frame;
+ }
+ void onError(String errorMessage) {
+ console.appendText(errorMessage);
+ console.appendText(' ');
+ console.append(buildButton('Try in iframe', retryInIframe));
+ console.appendText('\n');
+ }
+ if (usesDartHtml && !alwaysRunInWorker) {
+ retryInIframe(null);
+ } else {
+ runInWorker(wrapperUrl, onError);
+ }
+ }
+
+ // This is called in browsers that do not support creating Object
+ // URLs in a web worker. For example, Safari and Firefox < 21.
+ onCode(String code) {
+ clear();
+
+ void retryInIframe(_) {
+ // The obvious thing would be to call [makeOutputFrame], but
+ // Safari doesn't support access to Object URLs in an iframe.
+
+ var frame = new IFrameElement()
+ ..src = 'iframe.html'
+ ..style.width = '100%'
+ ..style.height = '0px'
+ ..seamless = false;
+ frame.onLoad.listen((_) {
+ frame.contentWindow.postMessage(['source', code], '*');
+ });
+ outputFrame.replaceWith(frame);
+ outputFrame = frame;
+ }
+
+ void onError(String errorMessage) {
+ console.appendText(errorMessage);
+ console.appendText(' ');
+ console.append(buildButton('Try in iframe', retryInIframe));
+ console.appendText('\n');
+ }
+
+ String codeWithPrint =
+ '$code\n'
+ 'function dartPrint(msg) { postMessage(msg); }\n';
+ var url =
+ Url.createObjectUrl(
+ new Blob([codeWithPrint], 'application/javascript'));
+ objectUrls.add(url);
+
+ if (usesDartHtml && !alwaysRunInWorker) {
+ retryInIframe(null);
+ } else {
+ runInWorker(url, onError);
+ }
+ }
+
+ void runInWorker(String url, void onError(String errorMessage)) {
+ worker = new Worker(url)
+ ..onMessage.listen((MessageEvent event) {
+ consolePrint(event.data);
+ })
+ ..onError.listen((ErrorEvent event) {
+ worker.terminate();
+ worker = null;
+ onError(event.message);
+ });
+ }
+
+ onDiagnostic(Map<String, dynamic> diagnostic) {
+ String kind = diagnostic['kind'];
+ String message = diagnostic['message'];
+ if (kind == 'verbose info') {
+ if (verboseCompiler) {
+ consolePrint(message);
+ }
+ return;
+ }
+ String uri = diagnostic['uri'];
+ if (uri == null) {
+ clear();
+ consolePrint(message);
+ return;
+ }
+ if (uri != 'memory:/main.dart') return;
+ if (currentSource != source) return;
+ int begin = diagnostic['begin'];
+ int end = diagnostic['end'];
+ if (begin == null) return;
+ addDiagnostic(kind, message, begin, end);
+ }
+
+ onCrash(data) {
+ consolePrint(data);
+ }
+
+ void consolePrint(message) {
+ console.appendText('$message\n');
+ }
+}
+
+Decoration getDecoration(scanner.Token token) {
+ String tokenValue = token.slowToString();
+ String tokenInfo = token.info.value.slowToString();
+ if (tokenInfo == 'string') return currentTheme.string;
+ // if (tokenInfo == 'identifier') return identifier;
+ if (tokenInfo == 'keyword') return currentTheme.keyword;
+ if (tokenInfo == 'comment') return currentTheme.singleLineComment;
+ if (tokenInfo == 'malformed input') {
+ isMalformedInput = true;
+ return new DiagnosticDecoration('error', tokenValue);
+ }
+ return null;
+}
+
+diagnostic(text, tip) {
+ if (text is String) {
+ text = new Text(text);
+ }
+ return new AnchorElement()
+ ..classes.add('diagnostic')
+ ..append(text)
+ ..append(tip);
+}
+
+img(src, width, height, alt) {
+ return new ImageElement(src: src, width: width, height: height)..alt = alt;
+}
+
+makeOutputFrame(String scriptUrl) {
+ final String outputHtml = '''
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>JavaScript output</title>
+<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
+</head>
+<body>
+<script type="application/javascript" src="$outputHelper"></script>
+<script type="application/javascript" src="$scriptUrl"></script>
+</body>
+</html>
+''';
+
+ return new IFrameElement()
+ ..src = Url.createObjectUrl(new Blob([outputHtml], "text/html"))
+ ..style.width = '100%'
+ ..style.height = '0px'
+ ..seamless = false;
+}
+
+const String HAS_NON_DOM_HTTP_REQUEST = 'spawnFunction supports HttpRequest';
+const String NO_NON_DOM_HTTP_REQUEST =
+ 'spawnFunction does not support HttpRequest';
+
+
+checkHttpRequest() {
+ port.receive((String uri, SendPort replyTo) {
+ try {
+ new HttpRequest();
+ replyTo.send(HAS_NON_DOM_HTTP_REQUEST);
+ } catch (e, trace) {
+ replyTo.send(NO_NON_DOM_HTTP_REQUEST);
+ }
+ port.close();
+ });
+}
+
+main() {
+ if (window.localStorage['currentSource'] == null) {
+ window.localStorage['currentSource'] = EXAMPLE_HELLO;
+ }
+
+ buildUI();
+ spawnFunction(checkHttpRequest).call('').then((reply) {
+ var compilerFuture;
+ if (reply == HAS_NON_DOM_HTTP_REQUEST) {
+ compilerFuture = spawnFunction(compilerIsolate);
+ } else {
+ compilerFuture = spawnDomFunction(compilerIsolate);
+ }
+ if (compilerFuture is! Future) {
+ compilerFuture = new Future.value(compilerFuture);
+ }
+ compilerFuture.then((port) {
+ String sdk = query('link[rel="dart-sdk"]').href;
+ print('Using Dart SDK: $sdk');
+ port.call(sdk).then((_) {
+ compilerPort = port;
+ onMutation([], observer);
+ });
+ });
+ });
+}
+
+buildButton(message, action) {
+ if (message is String) {
+ message = new Text(message);
+ }
+ return new ButtonElement()
+ ..onClick.listen(action)
+ ..append(message);
+}
+
+buildTab(message, id, action) {
+ if (message is String) {
+ message = new Text(message);
+ }
+
+ onClick(MouseEvent event) {
+ event.preventDefault();
+ Element e = event.target;
+ LIElement parent = e.parent;
+ parent.parent.query('li[class="active"]').classes.remove('active');
+ parent.classes.add('active');
+ action(event);
+ }
+
+ inspirationCallbacks[id] = action;
+
+ return new OptionElement()..append(message)..id = id;
+}
+
+Map<String, Function> inspirationCallbacks = new Map<String, Function>();
+
+void onInspirationChange(Event event) {
+ SelectElement select = event.target;
+ String id = select.queryAll('option')[select.selectedIndex].id;
+ Function action = inspirationCallbacks[id];
+ if (action != null) action(event);
+ outputFrame.style.display = 'none';
+}
+
+buildUI() {
+ window.localStorage['currentSample'] = '$currentSample';
+
+ var inspirationTabs = document.getElementById('inspiration');
+ var htmlGroup = new OptGroupElement()..label = 'HTML';
+ var benchmarkGroup = new OptGroupElement()..label = 'Benchmarks';
+ inspirationTabs.append(new OptionElement()..appendText('Pick an example'));
+ inspirationTabs.onChange.listen(onInspirationChange);
+ // inspirationTabs.classes.addAll(['nav', 'nav-tabs']);
+ inspirationTabs.append(buildTab('Hello, World!', 'EXAMPLE_HELLO', (_) {
+ inputPre
+ ..nodes.clear()
+ ..appendText(EXAMPLE_HELLO);
+ }));
+ inspirationTabs.append(buildTab('Fibonacci', 'EXAMPLE_FIBONACCI', (_) {
+ inputPre
+ ..nodes.clear()
+ ..appendText(EXAMPLE_FIBONACCI);
+ }));
+ inspirationTabs.append(htmlGroup);
+ inspirationTabs.append(benchmarkGroup);
+
+ htmlGroup.append(
+ buildTab('Hello, World!', 'EXAMPLE_HELLO_HTML', (_) {
+ inputPre
+ ..nodes.clear()
+ ..appendText(EXAMPLE_HELLO_HTML);
+ }));
+ htmlGroup.append(
+ buildTab('Fibonacci', 'EXAMPLE_FIBONACCI_HTML', (_) {
+ inputPre
+ ..nodes.clear()
+ ..appendText(EXAMPLE_FIBONACCI_HTML);
+ }));
+ htmlGroup.append(buildTab('Sunflower', 'EXAMPLE_SUNFLOWER', (_) {
+ inputPre
+ ..nodes.clear()
+ ..appendText(EXAMPLE_SUNFLOWER);
+ }));
+
+ benchmarkGroup.append(buildTab('DeltaBlue', 'BENCHMARK_DELTA_BLUE', (_) {
+ inputPre.contentEditable = 'false';
+ String deltaBlueUri = query('link[rel="benchmark-DeltaBlue"]').href;
+ String benchmarkBaseUri = query('link[rel="benchmark-base"]').href;
+ HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) {
+ HttpRequest.getString(deltaBlueUri).then((String deltaBlue) {
+ benchmarkBase = benchmarkBase.replaceFirst(
+ 'part of benchmark_harness;', '// part of benchmark_harness;');
+ deltaBlue = deltaBlue.replaceFirst(
+ "import 'package:benchmark_harness/benchmark_harness.dart';",
+ benchmarkBase);
+ inputPre
+ ..nodes.clear()
+ ..appendText(deltaBlue)
+ ..contentEditable = 'true';
+ });
+ });
+ }));
+
+ benchmarkGroup.append(buildTab('Richards', 'BENCHMARK_RICHARDS', (_) {
+ inputPre.contentEditable = 'false';
+ String richardsUri = query('link[rel="benchmark-Richards"]').href;
+ String benchmarkBaseUri = query('link[rel="benchmark-base"]').href;
+ HttpRequest.getString(benchmarkBaseUri).then((String benchmarkBase) {
+ HttpRequest.getString(richardsUri).then((String richards) {
+ benchmarkBase = benchmarkBase.replaceFirst(
+ 'part of benchmark_harness;', '// part of benchmark_harness;');
+ richards = richards.replaceFirst(
+ "import 'package:benchmark_harness/benchmark_harness.dart';",
+ benchmarkBase);
+ inputPre
+ ..nodes.clear()
+ ..appendText(richards)
+ ..contentEditable = 'true';
+ });
+ });
+ }));
+
+ // TODO(ahe): Update currentSample. Or try switching to a drop-down menu.
+ var active = inspirationTabs.query('[id="$currentSample"]');
+ if (active == null) {
+ // inspirationTabs.query('li').classes.add('active');
+ }
+
+ (inputPre = new DivElement())
+ ..classes.add('well')
+ ..style.backgroundColor = currentTheme.background.color
+ ..style.color = currentTheme.foreground.color
+ ..style.overflow = 'auto'
+ ..style.whiteSpace = 'pre'
+ ..style.font = codeFont
+ ..spellcheck = false;
+
+ inputPre.contentEditable = 'true';
+ inputPre.onKeyDown.listen(onKeyUp);
+
+ var inputWrapper = new DivElement()
+ ..append(inputPre)
+ ..style.position = 'relative';
+
+ var inputHeader = new DivElement()..appendText('Code');
+
+ inputHeader.style
+ ..right = '3px'
+ ..top = '0px'
+ ..position = 'absolute';
+ inputWrapper.append(inputHeader);
+
+ outputFrame =
+ makeOutputFrame(
+ Url.createObjectUrl(new Blob([''], 'application/javascript')));
+
+ outputDiv = new PreElement();
+ outputDiv.style
+ ..backgroundColor = currentTheme.background.color
+ ..color = currentTheme.foreground.color
+ ..overflow = 'auto'
+ ..padding = '1em'
+ ..minHeight = '10em'
+ ..whiteSpace = 'pre-wrap';
+
+ var outputWrapper = new DivElement()
+ ..append(outputDiv)
+ ..style.position = 'relative';
+
+ var consoleHeader = new DivElement()..appendText('Console');
+
+ consoleHeader.style
+ ..right = '3px'
+ ..top = '0px'
+ ..position = 'absolute';
+ outputWrapper.append(consoleHeader);
+
+ hackDiv = new DivElement();
+
+ var saveButton = new ButtonElement()
+ ..onClick.listen((_) {
+ var blobUrl =
+ Url.createObjectUrl(new Blob([inputPre.text], 'text/plain'));
+ var save = new AnchorElement(href: blobUrl);
+ save.target = '_blank';
+ save.download = 'untitled.dart';
+ save.dispatchEvent(new Event.eventType('Event', 'click'));
+ })
+ ..style.position = 'absolute'
+ ..style.right = '0px'
+ ..appendText('Save');
+
+ cacheStatusElement = document.getElementById('appcache-status');
+ updateCacheStatus();
+
+ // TODO(ahe): Switch to two column layout so the console is on the right.
+ var section = document.query('article[class="homepage"]>section');
+
+ DivElement tryColumn = document.getElementById('try-dart-column');
+ DivElement runColumn = document.getElementById('run-dart-column');
+
+ tryColumn.append(inputWrapper);
+ outputFrame.style.display = 'none';
+ runColumn.append(outputFrame);
+ runColumn.append(outputWrapper);
+ runColumn.append(hackDiv);
+
+ var settingsElement = document.getElementById('settings');
+ settingsElement.onClick.listen(openSettings);
+
+ window.onMessage.listen((MessageEvent event) {
+ if (event.data is List) {
+ List message = event.data;
+ if (message.length > 0) {
+ switch (message[0]) {
+ case 'error':
+ Map diagnostics = message[1];
+ String url = diagnostics['url'];
+ outputDiv.appendText('${diagnostics["message"]}\n');
+ return;
+ case 'scrollHeight':
+ int scrollHeight = message[1];
+ if (scrollHeight > 0) {
+ outputFrame.style.height = '${scrollHeight}px';
+ }
+ return;
+ }
+ }
+ }
+ outputDiv.appendText('${event.data}\n');
+ });
+
+ observer = new MutationObserver(onMutation)
+ ..observe(inputPre, childList: true, characterData: true, subtree: true);
+
+ window.setImmediate(() {
+ inputPre.appendText(window.localStorage['currentSource']);
+ });
+
+ // You cannot install event handlers on window.applicationCache
+ // until the window has loaded. In dartium, that's later than this
+ // method is called.
+ window.onLoad.listen(onLoad);
+
+ // However, in dart2js, the window has already loaded, and onLoad is
+ // never called.
+ onLoad(null);
+}
+
+void openSettings(MouseEvent event) {
+ event.preventDefault();
+
+ var backdrop = new DivElement()..classes.add('modal-backdrop');
+ document.body.append(backdrop);
+
+ void updateCodeFont(Event e) {
+ codeFont = e.target.value;
+ inputPre.style.font = codeFont;
+ backdrop.style.opacity = '0.0';
+ }
+
+ void updateTheme(Event e) {
+ var select = e.target;
+ String theme = select.queryAll('option')[select.selectedIndex].text;
+ window.localStorage['theme'] = theme;
+ currentTheme = Theme.named(theme);
+
+ inputPre.style
+ ..backgroundColor = currentTheme.background.color
+ ..color = currentTheme.foreground.color;
+
+ outputDiv.style
+ ..backgroundColor = currentTheme.background.color
+ ..color = currentTheme.foreground.color;
+
+ backdrop.style.opacity = '0.0';
+
+ applyingSettings = true;
+ onMutation([], observer);
+ applyingSettings = false;
+ }
+
+
+ var body = document.getElementById('settings-body');
+
+ body.nodes.clear();
+
+ var form = new FormElement();
+ var fieldSet = new FieldSetElement();
+ body.append(form);
+ form.append(fieldSet);
+
+ buildCheckBox(String text, bool defaultValue, void action(Event e)) {
+ var checkBox = new CheckboxInputElement()
+ ..defaultChecked = defaultValue
+ ..onChange.listen(action);
+ return new LabelElement()
+ ..classes.add('checkbox')
+ ..append(checkBox)
+ ..appendText(' $text');
+ }
+
+ 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.
+ buildCheckBox(
+ 'Always run in Worker thread.', alwaysRunInWorker,
+ (Event e) { alwaysRunInWorker = e.target.checked; }));
+
+ fieldSet.append(
+ buildCheckBox(
+ 'Verbose compiler output.', verboseCompiler,
+ (Event e) { verboseCompiler = e.target.checked; }));
+
+ fieldSet.append(
+ buildCheckBox(
+ 'Generate compact (minified) JavaScript.', minified,
+ (Event e) { minified = e.target.checked; }));
+
+ fieldSet.append(
+ buildCheckBox(
+ 'Only analyze program.', onlyAnalyze,
+ (Event e) { onlyAnalyze = e.target.checked; }));
+
+ fieldSet.append(new LabelElement()..appendText('Code font:'));
+ var textInput = new TextInputElement();
+ textInput.classes.add('input-block-level');
+ if (codeFont != null && codeFont != '') {
+ textInput.value = codeFont;
+ }
+ textInput.placeholder = 'Enter a size and font, for example, 11pt monospace';
+ textInput.onChange.listen(updateCodeFont);
+ fieldSet.append(textInput);
+
+ fieldSet.append(new LabelElement()..appendText('Theme:'));
+ var themeSelector = new SelectElement();
+ themeSelector.classes.add('input-block-level');
+ for (Theme theme in THEMES) {
+ OptionElement option = new OptionElement()..appendText(theme.name);
+ if (theme == currentTheme) option.selected = true;
+ themeSelector.append(option);
+ }
+ themeSelector.onChange.listen(updateTheme);
+ fieldSet.append(themeSelector);
+
+ var dialog = document.getElementById('settings-dialog');
+
+ dialog.style.display = 'block';
+ dialog.classes.add('in');
+
+ onSubmit(Event event) {
+ event.preventDefault();
+
+ window.localStorage['alwaysRunInWorker'] = '$alwaysRunInWorker';
+ window.localStorage['verboseCompiler'] = '$verboseCompiler';
+ window.localStorage['minified'] = '$minified';
+ window.localStorage['onlyAnalyze'] = '$onlyAnalyze';
+ window.localStorage['codeFont'] = '$codeFont';
+
+ dialog.style.display = 'none';
+ dialog.classes.remove('in');
+ backdrop.remove();
+ }
+ form.onSubmit.listen(onSubmit);
+
+ var doneButton = document.getElementById('settings-done');
+ doneButton.onClick.listen(onSubmit);
+}
+
+/// Called when the window has finished loading.
+void onLoad(Event event) {
+ window.applicationCache.onUpdateReady.listen((_) => updateCacheStatus());
+ window.applicationCache.onCached.listen((_) => updateCacheStatus());
+ window.applicationCache.onChecking.listen((_) => updateCacheStatus());
+ window.applicationCache.onDownloading.listen((_) => updateCacheStatus());
+ window.applicationCache.onError.listen((_) => updateCacheStatus());
+ window.applicationCache.onNoUpdate.listen((_) => updateCacheStatus());
+ window.applicationCache.onObsolete.listen((_) => updateCacheStatus());
+ window.applicationCache.onProgress.listen(onCacheProgress);
+}
+
+onCacheProgress(ProgressEvent event) {
+ if (!event.lengthComputable) {
+ updateCacheStatus();
+ return;
+ }
+ cacheStatusElement.nodes.clear();
+ cacheStatusElement.appendText('Downloading SDK ');
+ var progress = '${event.loaded} of ${event.total}';
+ if (MeterElement.supported) {
+ cacheStatusElement.append(
+ new MeterElement()
+ ..appendText(progress)
+ ..min = 0
+ ..max = event.total
+ ..value = event.loaded);
+ } else {
+ cacheStatusElement.appendText(progress);
+ }
+}
+
+String cacheStatus() {
+ if (!ApplicationCache.supported) return 'offline not supported';
+ int status = window.applicationCache.status;
+ if (status == ApplicationCache.CHECKING) return 'Checking for updates';
+ if (status == ApplicationCache.DOWNLOADING) return 'Downloading SDK';
+ if (status == ApplicationCache.IDLE) return 'Try Dart! works offline';
+ if (status == ApplicationCache.OBSOLETE) return 'OBSOLETE';
+ if (status == ApplicationCache.UNCACHED) return 'offline not available';
+ if (status == ApplicationCache.UPDATEREADY) return 'SDK downloaded';
+ return '?';
+}
+
+void updateCacheStatus() {
+ cacheStatusElement.nodes.clear();
+ String status = window.applicationCache.status;
+ if (status == ApplicationCache.UPDATEREADY) {
+ cacheStatusElement.appendText('New version of Try Dart! ready: ');
+ cacheStatusElement.append(
+ new AnchorElement(href: '#')
+ ..appendText('Load')
+ ..onClick.listen((event) {
+ event.preventDefault();
+ window.applicationCache.swapCache();
+ window.location.reload();
+ }));
+ } else if (status == ApplicationCache.IDLE) {
+ cacheStatusElement.appendText(cacheStatus());
+ cacheStatusElement.classes.add('offlineyay');
+ new Timer(const Duration(seconds: 10), () {
+ cacheStatusElement.style.display = 'none';
+ });
+ } else {
+ cacheStatusElement.appendText(cacheStatus());
+ }
+}
+
+void compilerIsolate() {
+ lazy.load().then((_) => port.receive(compile));
+}
+
+final String outputHelper =
+ Url.createObjectUrl(new Blob([OUTPUT_HELPER], 'application/javascript'));
+
+const String EXAMPLE_HELLO = r'''
+// Go ahead and modify this example.
+
+var greeting = "Hello, World!";
+
+// Prints a greeting.
+void main() {
+ // The [print] function displays a message in the "Console" box.
+ // Try modifying the greeting above and watch the "Console" box change.
+ print(greeting);
+}
+''';
+
+const String EXAMPLE_HELLO_HTML = r'''
+// Go ahead and modify this example.
+
+import "dart:html";
+
+var greeting = "Hello, World!";
+
+// Displays a greeting.
+void main() {
+ // This example uses HTML to display the greeting and it will appear
+ // in a nested HTML frame (an iframe).
+ document.body.append(new HeadingElement.h1()..appendText(greeting));
+}
+''';
+
+const String EXAMPLE_FIBONACCI = r'''
+// Go ahead and modify this example.
+
+// Computes the nth Fibonacci number.
+int fibonacci(int n) {
+ if (n < 2) return n;
+ return fibonacci(n - 1) + fibonacci(n - 2);
+}
+
+// Prints a Fibonacci number.
+void main() {
+ int i = 20;
+ String message = "fibonacci($i) = ${fibonacci(i)}";
+ // Print the result in the "Console" box.
+ print(message);
+}
+''';
+
+const String EXAMPLE_FIBONACCI_HTML = r'''
+// Go ahead and modify this example.
+
+import "dart:html";
+
+// Computes the nth Fibonacci number.
+int fibonacci(int n) {
+ if (n < 2) return n;
+ return fibonacci(n - 1) + fibonacci(n - 2);
+}
+
+// Displays a Fibonacci number.
+void main() {
+ int i = 20;
+ String message = "fibonacci($i) = ${fibonacci(i)}";
+
+ // This example uses HTML to display the result and it will appear
+ // in a nested HTML frame (an iframe).
+ document.body.append(new HeadingElement.h1()..appendText(message));
+}
+''';
+
+const String OUTPUT_HELPER = r'''
+function dartPrint(msg) {
+ window.parent.postMessage(String(msg), "*");
+}
+
+function dartMainRunner(main) {
+ main();
+}
+
+window.onerror = function (message, url, lineNumber) {
+ window.parent.postMessage(
+ ["error", {message: message, url: url, lineNumber: lineNumber}], "*");
+};
+
+(function () {
+
+function postScrollHeight() {
+ window.parent.postMessage(["scrollHeight", document.documentElement.scrollHeight], "*");
+}
+
+var observer = new (window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver)(function(mutations) {
+ postScrollHeight()
+ window.setTimeout(postScrollHeight, 500);
+});
+
+observer.observe(
+ document.body,
+ { attributes: true,
+ childList: true,
+ characterData: true,
+ subtree: true });
+})();
+''';
+
+const String EXAMPLE_SUNFLOWER = '''
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library sunflower;
+
+import "dart:html";
+import "dart:math";
+
+const String ORANGE = "orange";
+const int SEED_RADIUS = 2;
+const int SCALE_FACTOR = 4;
+const num TAU = PI * 2;
+const int MAX_D = 300;
+const num centerX = MAX_D / 2;
+const num centerY = centerX;
+
+final InputElement slider = query("#slider");
+final Element notes = query("#notes");
+final num PHI = (sqrt(5) + 1) / 2;
+int seeds = 0;
+final CanvasRenderingContext2D context =
+ (query("#canvas") as CanvasElement).context2D;
+
+void main() {
+ document.head.append(new StyleElement()..appendText(STYLE));
+ document.body.innerHtml = BODY;
+ slider.onChange.listen((e) => draw());
+ draw();
+}
+
+/// Draw the complete figure for the current number of seeds.
+void draw() {
+ seeds = int.parse(slider.value);
+ context.clearRect(0, 0, MAX_D, MAX_D);
+ for (var i = 0; i < seeds; i++) {
+ final num theta = i * TAU / PHI;
+ final num r = sqrt(i) * SCALE_FACTOR;
+ drawSeed(centerX + r * cos(theta), centerY - r * sin(theta));
+ }
+ notes.text = "\${seeds} seeds";
+}
+
+/// Draw a small circle representing a seed centered at (x,y).
+void drawSeed(num x, num y) {
+ context..beginPath()
+ ..lineWidth = 2
+ ..fillStyle = ORANGE
+ ..strokeStyle = ORANGE
+ ..arc(x, y, SEED_RADIUS, 0, TAU, false)
+ ..fill()
+ ..closePath()
+ ..stroke();
+}
+
+const String MATH_PNG =
+ "https://dart.googlecode.com/svn/trunk/dart/samples/sunflower/web/math.png";
+const String BODY = """
+ <h1>drfibonacci\'s Sunflower Spectacular</h1>
+
+ <p>A canvas 2D demo.</p>
+
+ <div id="container">
+ <canvas id="canvas" width="300" height="300" class="center"></canvas>
+ <form class="center">
+ <input id="slider" type="range" max="1000" value="500"/>
+ </form>
+ <br/>
+ <img src="\$MATH_PNG" width="350px" height="42px" class="center">
+ </div>
+
+ <footer>
+ <p id="summary"> </p>
+ <p id="notes"> </p>
+ </footer>
+""";
+
+const String STYLE = r"""
+body {
+ background-color: #F8F8F8;
+ font-family: 'Open Sans', sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1.2em;
+ margin: 15px;
+}
+
+p {
+ color: #333;
+}
+
+#container {
+ width: 100%;
+ height: 400px;
+ position: relative;
+ border: 1px solid #ccc;
+ background-color: #fff;
+}
+
+#summary {
+ float: left;
+}
+
+#notes {
+ float: right;
+ width: 120px;
+ text-align: right;
+}
+
+.error {
+ font-style: italic;
+ color: red;
+}
+
+img {
+ border: 1px solid #ccc;
+ margin: auto;
+}
+
+.center {
+ display: block;
+ margin: 0px auto;
+ text-align: center;
+}
+""";
+
+''';

Powered by Google App Engine
This is Rietveld 408576698