From 04b08da9af0c450d645ab7389d1467308cfc2db8 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 4 Mar 2013 21:27:36 +0100 Subject: Imported Upstream version 1.1~hg20130304 --- doc/play/fib.go | 4 +- doc/play/playground.js | 263 ++++++++++++++++++++++++++++--------------------- doc/play/sieve.go | 4 +- doc/play/solitaire.go | 14 +-- doc/play/tree.go | 4 +- 5 files changed, 165 insertions(+), 124 deletions(-) (limited to 'doc/play') diff --git a/doc/play/fib.go b/doc/play/fib.go index 42da9ce82..19e472102 100644 --- a/doc/play/fib.go +++ b/doc/play/fib.go @@ -1,5 +1,7 @@ package main +import "fmt" + // fib returns a function that returns // successive Fibonacci numbers. func fib() func() int { @@ -13,5 +15,5 @@ func fib() func() int { func main() { f := fib() // Function calls are evaluated left-to-right. - println(f(), f(), f(), f(), f()) + fmt.Println(f(), f(), f(), f(), f()) } diff --git a/doc/play/playground.js b/doc/play/playground.js index d7cc58d6e..709136627 100644 --- a/doc/play/playground.js +++ b/doc/play/playground.js @@ -3,23 +3,19 @@ // license that can be found in the LICENSE file. // opts is an object with these keys -// codeEl - code editor element -// outputEl - program output element -// runEl - run button element -// fmtEl - fmt button element (optional) -// shareEl - share button element (optional) -// shareURLEl - share URL text input element (optional) -// shareRedirect - base URL to redirect to on share (optional) -// preCompile - callback to mutate request data before compiling (optional) -// postCompile - callback to read response data after compiling (optional) -// simple - use plain textarea instead of CodeMirror. (optional) -// toysEl - select element with a list of toys. (optional) +// codeEl - code editor element +// outputEl - program output element +// runEl - run button element +// fmtEl - fmt button element (optional) +// shareEl - share button element (optional) +// shareURLEl - share URL text input element (optional) +// shareRedirect - base URL to redirect to on share (optional) +// toysEl - toys select element (optional) +// enableHistory - enable using HTML5 history API (optional) function playground(opts) { - var simple = opts['simple']; var code = $(opts['codeEl']); - var editor; - // autoindent helpers for simple mode. + // autoindent helpers. function insertTabs(n) { // find the selection start and end var start = code[0].selectionStart; @@ -49,12 +45,12 @@ function playground(opts) { } } setTimeout(function() { - insertTabs(tabs, 1); + insertTabs(tabs); }, 1); } function keyHandler(e) { - if (simple && e.keyCode == 9) { // tab + if (e.keyCode == 9) { // tab insertTabs(1); e.preventDefault(); return false; @@ -64,58 +60,19 @@ function playground(opts) { run(); e.preventDefault(); return false; - } else if (simple) { + } else { autoindent(e.target); } } return true; } - if (simple) { - code.unbind('keydown').bind('keydown', keyHandler); - } else { - editor = CodeMirror.fromTextArea( - code[0], - { - lineNumbers: true, - indentUnit: 8, - indentWithTabs: true, - onKeyEvent: function(editor, e) { keyHandler(e); } - } - ); - } + code.unbind('keydown').bind('keydown', keyHandler); var output = $(opts['outputEl']); - function clearErrors() { - if (!editor) { - return; - } - var lines = editor.lineCount(); - for (var i = 0; i < lines; i++) { - editor.setLineClass(i, null); - } - } - function highlightErrors(text) { - if (!editor) { - return; - } - var errorRe = /[a-z]+\.go:([0-9]+):/g; - var result; - while ((result = errorRe.exec(text)) != null) { - var line = result[1]*1-1; - editor.setLineClass(line, "errLine") - } - } function body() { - if (editor) { - return editor.getValue(); - } return $(opts['codeEl']).val(); } function setBody(text) { - if (editor) { - editor.setValue(text); - return; - } $(opts['codeEl']).val(text); } function origin(href) { @@ -126,24 +83,116 @@ function playground(opts) { '
Waiting for remote server...
' ); } - function setOutput(text, error) { + var playbackTimeout; + function playback(pre, events) { + function show(msg) { + // ^L clears the screen. + var msgs = msg.split("\x0c"); + if (msgs.length == 1) { + pre.text(pre.text() + msg); + return; + } + pre.text(msgs.pop()); + } + function next() { + if (events.length == 0) { + var exit = $(''); + exit.text("\nProgram exited."); + exit.appendTo(pre); + return; + } + var e = events.shift(); + if (e.Delay == 0) { + show(e.Message); + next(); + } else { + playbackTimeout = setTimeout(function() { + show(e.Message); + next(); + }, e.Delay / 1000000); + } + } + next(); + } + function stopPlayback() { + clearTimeout(playbackTimeout); + } + function setOutput(events, error) { + stopPlayback(); output.empty(); + $(".lineerror").removeClass("lineerror"); + + // Display errors. if (error) { output.addClass("error"); + var regex = /prog.go:([0-9]+)/g; + var r; + while (r = regex.exec(error)) { + $(".lines div").eq(r[1]-1).addClass("lineerror"); + } + $("
").text(error).appendTo(output);
+			return;
+		}
+
+		// Display image output.
+		if (events.length > 0 && events[0].Message.indexOf("IMAGE:") == 0) {
+			var out = "";
+			for (var i = 0; i < events.length; i++) {
+				out += events[i].Message;
+			}
+			var url = "data:image/png;base64," + out.substr(6);
+			$("").attr("src", url).appendTo(output);
+			return;
+		}
+
+		// Play back events.
+		if (events !== null) {
+			var pre = $("
").appendTo(output);
+			playback(pre, events);
+		}
+	}
+
+	var pushedEmpty = (window.location.pathname == "/");
+	function inputChanged() {
+		if (pushedEmpty) {
+			return;
 		}
-		$("
").text(text).appendTo(output);
+		pushedEmpty = true;
+
+		$(opts['shareURLEl']).hide();
+		window.history.pushState(null, "", "/");
+	}
+
+	function popState(e) {
+		if (e == null) {
+			return;
+		}
+
+		if (e && e.state && e.state.code) {
+			setBody(e.state.code);
+		}
+	}
+
+	var rewriteHistory = false;
+
+	if (window.history &&
+		window.history.pushState &&
+		window.addEventListener &&
+		opts['enableHistory']) {
+		rewriteHistory = true;
+		code[0].addEventListener('input', inputChanged);
+		window.addEventListener('popstate', popState)
 	}
 
 	var seq = 0;
 	function run() {
-		clearErrors();
 		loading();
 		seq++;
 		var cur = seq;
-		var data = {"body": body()};
-		if (opts['preCompile']) {
-			opts['preCompile'](data);
-		}
+		var data = {
+			"version": 2,
+			"body": body()
+		};
 		$.ajax("/compile", {
 			data: data,
 			type: "POST",
@@ -152,34 +201,19 @@ function playground(opts) {
 				if (seq != cur) {
 					return;
 				}
-				if (opts['postCompile']) {
-					opts['postCompile'](data);
-				}
 				if (!data) {
 					return;
 				}
-				if (data.compile_errors != "") {
-					setOutput(data.compile_errors, true);
-					highlightErrors(data.compile_errors);
-					return;
-				}
-				var out = ""+data.output;
-				if (out.indexOf("IMAGE:") == 0) {
-					var img = $("");
-					var url = "data:image/png;base64,";
-					url += out.substr(6)
-					img.attr("src", url);
-					output.empty().append(img);
+				if (data.Errors) {
+					setOutput(null, data.Errors);
 					return;
 				}
-				setOutput(out, false);
+				setOutput(data.Events, false);
 			},
-			error: function(xhr) {
-				var text = "Error communicating with remote server.";
-				if (xhr.status == 501) {
-					text = xhr.responseText;
-				}
-				output.addClass("error").text(text);
+			error: function() {
+				output.addClass("error").text(
+					"Error communicating with remote server."
+				);
 			}
 		});
 	}
@@ -193,29 +227,11 @@ function playground(opts) {
 			dataType: "json",
 			success: function(data) {
 				if (data.Error) {
-					setOutput(data.Error, true);
-					highlightErrors(data.Error);
+					setOutput(null, data.Error);
 					return;
 				}
 				setBody(data.Body);
-				setOutput("", false);
-			}
-		});
-	});
-
-	$(opts['toysEl']).bind('change', function() {
-		var toy = $(this).val();
-		loading();
-		$.ajax("/doc/play/"+toy, {
-			processData: false,
-			type: "GET",
-			complete: function(xhr) {
-				if (xhr.status != 200) {
-					setOutput("Server error; try again.", true);
-					return;
-				}
-				setBody(xhr.responseText);
-				setOutput("", false);
+				setOutput(null);
 			}
 		});
 	});
@@ -229,16 +245,13 @@ function playground(opts) {
 		$(opts['shareEl']).click(function() {
 			if (sharing) return;
 			sharing = true;
+			var sharingData = body();
 			$.ajax("/share", {
 				processData: false,
-				data: body(),
+				data: sharingData,
 				type: "POST",
 				complete: function(xhr) {
 					sharing = false;
-					if (xhr.status == 501) {
-						alert(xhr.responseText);
-						return;
-					}
 					if (xhr.status != 200) {
 						alert("Server error; try again.");
 						return;
@@ -247,13 +260,37 @@ function playground(opts) {
 						window.location = opts['shareRedirect'] + xhr.responseText;
 					}
 					if (shareURL) {
-						var url = origin(window.location) + "/p/" + xhr.responseText;
+						var path = "/p/" + xhr.responseText
+						var url = origin(window.location) + path;
 						shareURL.show().val(url).focus().select();
+
+						if (rewriteHistory) {
+							var historyData = {
+								"code": sharingData,
+							};
+							window.history.pushState(historyData, "", path);
+							pushedEmpty = false;
+						}
 					}
 				}
 			});
 		});
 	}
 
-	return editor;
+	if (opts['toysEl'] != null) {
+		$(opts['toysEl']).bind('change', function() {
+			var toy = $(this).val();
+			$.ajax("/doc/play/"+toy, {
+				processData: false,
+				type: "GET",
+				complete: function(xhr) {
+					if (xhr.status != 200) {
+						alert("Server error; try again.")
+						return;
+					}
+					setBody(xhr.responseText);
+				}
+			});
+		});
+	}
 }
diff --git a/doc/play/sieve.go b/doc/play/sieve.go
index 585507ac4..519093453 100644
--- a/doc/play/sieve.go
+++ b/doc/play/sieve.go
@@ -2,6 +2,8 @@
 
 package main
 
+import "fmt"
+
 // Send the sequence 2, 3, 4, ... to channel 'ch'.
 func Generate(ch chan<- int) {
 	for i := 2; ; i++ {
@@ -26,7 +28,7 @@ func main() {
 	go Generate(ch)      // Launch Generate goroutine.
 	for i := 0; i < 10; i++ {
 		prime := <-ch
-		print(prime, "\n")
+		fmt.Println(prime)
 		ch1 := make(chan int)
 		go Filter(ch, ch1, prime)
 		ch = ch1
diff --git a/doc/play/solitaire.go b/doc/play/solitaire.go
index 759d54281..15022aa19 100644
--- a/doc/play/solitaire.go
+++ b/doc/play/solitaire.go
@@ -28,7 +28,7 @@ var board = []rune(
 ...........
 `)
 
-// center is the position of the center hole if 
+// center is the position of the center hole if
 // there is a single one; otherwise it is -1.
 var center int
 
@@ -47,7 +47,7 @@ func init() {
 
 var moves int // number of times move is called
 
-// move tests if there is a peg at position pos that 
+// move tests if there is a peg at position pos that
 // can jump over another peg in direction dir. If the
 // move is valid, it is executed and move returns true.
 // Otherwise, move returns false.
@@ -69,11 +69,11 @@ func unmove(pos, dir int) {
 	board[pos+2*dir] = '○'
 }
 
-// solve tries to find a sequence of moves such that 
-// there is only one peg left at the end; if center is 
+// solve tries to find a sequence of moves such that
+// there is only one peg left at the end; if center is
 // >= 0, that last peg must be in the center position.
 // If a solution is found, solve prints the board after
-// each move in a backward fashion (i.e., the last 
+// each move in a backward fashion (i.e., the last
 // board position is printed first, all the way back to
 // the starting board position).
 func solve() bool {
@@ -89,7 +89,7 @@ func solve() bool {
 					// see if this new board has a solution
 					if solve() {
 						unmove(pos, dir)
-						println(string(board))
+						fmt.Println(string(board))
 						return true
 					}
 					unmove(pos, dir)
@@ -102,7 +102,7 @@ func solve() bool {
 	// tried each possible move
 	if n == 1 && (center < 0 || last == center) {
 		// there's only one peg left
-		println(string(board))
+		fmt.Println(string(board))
 		return true
 	}
 	// no solution found for this board
diff --git a/doc/play/tree.go b/doc/play/tree.go
index 5bcbf05a8..3790e6cda 100644
--- a/doc/play/tree.go
+++ b/doc/play/tree.go
@@ -2,7 +2,7 @@
 // express concurrent concepts, such as
 // this binary tree comparison.
 //
-// Trees may be of different shapes, 
+// Trees may be of different shapes,
 // but have the same contents. For example:
 //
 //        4               6
@@ -29,7 +29,7 @@ type Tree struct {
 	Right *Tree
 }
 
-// Walk traverses a tree depth-first, 
+// Walk traverses a tree depth-first,
 // sending each Value on a channel.
 func Walk(t *Tree, ch chan int) {
 	if t == nil {
-- 
cgit v1.2.3