tour: add kill button to interface

Change-Id: I91087f40329ffce4787b5e0ec84b604a0b92b53b
Reviewed-on: https://go-review.googlesource.com/12377
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/static/css/app.css b/static/css/app.css
index 9eb6f33..2c5a125 100755
--- a/static/css/app.css
+++ b/static/css/app.css
@@ -208,11 +208,13 @@
 #file-menu .menu-button {
     float: right;
 }
-#run {
+#run, #kill {
     background-color: #375eab;
     color: #fff;
+    width: 40px;
+    text-align: center;
 }
-#run:hover:not(:active) {
+#run:hover:not(:active), #kill:hover:not(:active) {
     background-color: #fff;
     color: #375eab;
 }
diff --git a/static/js/controllers.js b/static/js/controllers.js
index 2156ae6..d4151a3 100755
--- a/static/js/controllers.js
+++ b/static/js/controllers.js
@@ -31,6 +31,7 @@
         $scope.lessonId = $routeParams.lessonId;
         $scope.curPage = parseInt($routeParams.pageNumber);
         $scope.curFile = 0;
+        $scope.job = null;
 
         $scope.nextPage = function() {
             $scope.gotoPage($scope.curPage + 1);
@@ -74,11 +75,18 @@
         $scope.run = function() {
             log('info', i18n.l('waiting'));
             var f = file();
-            run(f.Content, $('.output.active > pre')[0], {
+            $scope.job = run(f.Content, $('.output.active > pre')[0], {
                 path: f.Name
+            }, function() {
+                $scope.job = null;
+                $scope.$apply();
             });
         };
 
+        $scope.kill = function() {
+            if ($scope.job !== null) $scope.job.Kill();
+        };
+
         $scope.format = function() {
             log('info', i18n.l('waiting'));
             fmt(file().Content).then(
diff --git a/static/js/services.js b/static/js/services.js
index e045041..91a08c9 100755
--- a/static/js/services.js
+++ b/static/js/services.js
@@ -33,7 +33,7 @@
 // Running code
 factory('run', ['$window', 'editor',
     function(win, editor) {
-        var writeInterceptor = function(writer) {
+        var writeInterceptor = function(writer, done) {
             return function(write) {
                 if (write.Kind == 'stderr') {
                     var lines = write.Body.split('\n');
@@ -45,14 +45,15 @@
                     }
                 }
                 writer(write);
+                if (write.Kind == 'end') done();
             };
         };
-        return function(code, output, options) {
+        return function(code, output, options, done) {
             // PlaygroundOutput is defined in playground.js which is prepended
             // to the generated script.js in gotour/tour.go.
             // The next line removes the jshint warning.
             // global PlaygroundOutput
-            win.transport.Run(code, writeInterceptor(PlaygroundOutput(output)), options);
+            return win.transport.Run(code, writeInterceptor(PlaygroundOutput(output), done), options);
         };
     }
 ]).
diff --git a/static/partials/editor.html b/static/partials/editor.html
index 08a5a1f..529dd87 100644
--- a/static/partials/editor.html
+++ b/static/partials/editor.html
@@ -16,7 +16,7 @@
         <div id="left-side" class="relative-content">
             <div id="explorer" ng-class="{hidden: toc.lessons[lessonId].Pages[curPage-1].Files.length==0}">
                 <a class="menu-button" ng-repeat="f in toc.lessons[lessonId].Pages[curPage-1].Files" ng-click="openFile($index)" ng-class="{active: $index==curFile}">{{f.Name}}</a>
-                <a syntax-checkbox ng-class="{active: editor.syntax}" class="menu-button syntax-checkbox">Syntax</a> 
+                <a syntax-checkbox ng-class="{active: editor.syntax}" class="menu-button syntax-checkbox">Syntax</a>
             </div>
 
             <div class="relative-content" ng-class="{hidden: toc.lessons[lessonId].Pages[curPage-1].Files.length==0}">
@@ -35,7 +35,8 @@
                     <div class="relative-content">
                         <!--div id="file-menu" ng-controller="OutputCtrl"-->
                         <div id="file-menu">
-                            <a class="menu-button" id="run" ng-click="run()">Run</a>
+                            <a ng-show="job == null" class="menu-button" id="run" ng-click="run()">Run</a>
+                            <a ng-show="job != null" class="menu-button" id="kill" ng-click="kill()">Kill</a>
                             <a class="menu-button" id="format" ng-click="format()">Format</a>
                             <a class="menu-button" id="reset" ng-click="reset()">Reset</a>
                         </div>