You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mo...@apache.org on 2015/11/10 13:47:13 UTC

incubator-zeppelin git commit: ZEPPELIN-401 Improve autoscroll

Repository: incubator-zeppelin
Updated Branches:
  refs/heads/master f3de6cd7e -> 6ba4cf96a


ZEPPELIN-401 Improve autoscroll

Addresses https://issues.apache.org/jira/browse/ZEPPELIN-401

This PR improves autoscroll behavior when using keyboard navigation (up/down key)

* When cursor closes to edge of top/bottom of notebook, autoscroll triggers
* Autoscroll will scroll notebook to position cursor to the middle of browser window
* When last paragraph is executed, a new paragraph is inserted after. now notebook autoscrolls to newly inserted paragraph.

Author: Lee moon soo <mo...@apache.org>

This patch had conflicts when merged, resolved by
Committer: Lee moon soo <mo...@apache.org>

Closes #400 from Leemoonsoo/improve_scroll and squashes the following commits:

e1170b4 [Lee moon soo] Do not skip paragraph only hides result when move cursor
3d6a3e1 [Lee moon soo] fix style and condition for tail last paragraph
53d48ac [Lee moon soo] Remove unncessary console.log
9229bd2 [Lee moon soo] Uncomment cursor force positioning
46055f5 [Lee moon soo] Replace hardcoded value
71be96b [Lee moon soo] tail last paragraph
ca865fa [Lee moon soo] Moving focus of paragraph by keyboard reset cursor to the beginning (or ending) position of the editor
39108a0 [Lee moon soo] Scroll to cursor position


Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/6ba4cf96
Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/6ba4cf96
Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/6ba4cf96

Branch: refs/heads/master
Commit: 6ba4cf96aecad6a316d6c74f9a336a20585044c6
Parents: f3de6cd
Author: Lee moon soo <mo...@apache.org>
Authored: Sun Nov 8 21:00:26 2015 +0900
Committer: Lee moon soo <mo...@apache.org>
Committed: Tue Nov 10 21:47:27 2015 +0900

----------------------------------------------------------------------
 .../src/app/notebook/notebook.controller.js     |  8 +-
 .../notebook/paragraph/paragraph.controller.js  | 78 +++++++++++++++++++-
 2 files changed, 80 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/6ba4cf96/zeppelin-web/src/app/notebook/notebook.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js
index d8ee83f..dc986a9 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -313,8 +313,8 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
         }
       } else {
         var p = $scope.note.paragraphs[i];
-        if (!p.config.hide && !p.config.editorHide && !p.config.tableHide) {
-          $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id);
+        if (!p.config.hide && !p.config.editorHide) {
+          $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id, -1);
           break;
         }
       }
@@ -331,8 +331,8 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
         }
       } else {
         var p = $scope.note.paragraphs[i];
-        if (!p.config.hide && !p.config.editorHide && !p.config.tableHide) {
-          $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id);
+        if (!p.config.hide && !p.config.editorHide) {
+          $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id, 0);
           break;
         }
       }

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/6ba4cf96/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
index 63c30c4..0ba155f 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
@@ -167,6 +167,7 @@ angular.module('zeppelinWebApp')
       var oldGraphMode = $scope.getGraphMode();
       var newGraphMode = $scope.getGraphMode(data.paragraph);
       var resultRefreshed = (data.paragraph.dateFinished !== $scope.paragraph.dateFinished);
+      var statusChanged = (data.paragraph.status !== $scope.paragraph.status);
 
       //console.log("updateParagraph oldData %o, newData %o. type %o -> %o, mode %o -> %o", $scope.paragraph, data, oldType, newType, oldGraphMode, newGraphMode);
 
@@ -223,7 +224,14 @@ angular.module('zeppelinWebApp')
       } else if (newType === 'ANGULAR' && resultRefreshed) {
         $scope.renderAngular();
       }
+
+      if (statusChanged || resultRefreshed) {
+        // when last paragraph runs, zeppelin automatically appends new paragraph.
+        // this broadcast will focus to the newly inserted paragraph
+        $rootScope.$broadcast('scrollToCursor');
+      }
     }
+
   });
 
   $scope.isRunning = function() {
@@ -586,12 +594,15 @@ angular.module('zeppelinWebApp')
         } else {
           var numRows;
           var currentRow;
+
           if (keyCode === 38 || (keyCode === 80 && e.ctrlKey)) {  // UP
             numRows = $scope.editor.getSession().getLength();
             currentRow = $scope.editor.getCursorPosition().row;
             if (currentRow === 0) {
               // move focus to previous paragraph
               $scope.$emit('moveFocusToPreviousParagraph', $scope.paragraph.id);
+            } else {
+              $scope.scrollToCursor($scope.paragraph.id, -1);
             }
           } else if (keyCode === 40 || (keyCode === 78 && e.ctrlKey)) {  // DOWN
             numRows = $scope.editor.getSession().getLength();
@@ -599,6 +610,8 @@ angular.module('zeppelinWebApp')
             if (currentRow === numRows-1) {
               // move focus to next paragraph
               $scope.$emit('moveFocusToNextParagraph', $scope.paragraph.id);
+            } else {
+              $scope.scrollToCursor($scope.paragraph.id, 1);
             }
           }
         }
@@ -615,6 +628,54 @@ angular.module('zeppelinWebApp')
     editor.resize();
   };
 
+  $rootScope.$on('scrollToCursor', function(event) {
+    $scope.scrollToCursor($scope.paragraph.id, 0);
+  });
+
+  /** scrollToCursor if it is necessary
+   * when cursor touches scrollTriggerEdgeMargin from the top (or bottom) of the screen, it autoscroll to place cursor around 1/3 of screen height from the top (or bottom)
+   * paragraphId : paragraph that has active cursor
+   * lastCursorMove : 1(down), 0, -1(up) last cursor move event
+   **/
+  $scope.scrollToCursor = function(paragraphId, lastCursorMove) {
+    if (!$scope.editor.isFocused()) {
+     // only make sense when editor is focused
+     return;
+    }
+    var lineHeight = $scope.editor.renderer.lineHeight;
+    var headerHeight = 103; // menubar, notebook titlebar
+    var scrollTriggerEdgeMargin = 50;
+    
+    var documentHeight = angular.element(document).height();
+    var windowHeight = angular.element(window).height();  // actual viewport height
+
+    var scrollPosition = angular.element(document).scrollTop();
+    var editorPosition = angular.element('#'+paragraphId+'_editor').offset();
+    var position = $scope.editor.getCursorPosition();
+    var lastCursorPosition = $scope.editor.renderer.$cursorLayer.getPixelPosition(position, true);
+
+    var calculatedCursorPosition = editorPosition.top + lastCursorPosition.top + 16*lastCursorMove;
+
+    var scrollTargetPos;
+    if (calculatedCursorPosition < scrollPosition + headerHeight + scrollTriggerEdgeMargin) {
+      scrollTargetPos = calculatedCursorPosition - headerHeight - ((windowHeight-headerHeight)/3);
+      if (scrollTargetPos < 0) {
+        scrollTargetPos = 0;
+      }
+    } else if(calculatedCursorPosition > scrollPosition + scrollTriggerEdgeMargin + windowHeight - headerHeight) {
+      scrollTargetPos = calculatedCursorPosition - headerHeight - ((windowHeight-headerHeight)*2/3);
+
+      if (scrollTargetPos > documentHeight) {
+        scrollTargetPos = documentHeight;
+      }
+    }
+    angular.element('body').scrollTo(scrollTargetPos, {duration:200});
+  };
+
+  var setEditorHeight = function(id, height) {
+    angular.element('#' + id).height(height.toString() + 'px');
+  };
+
   $scope.getEditorValue = function() {
     return $scope.editor.getValue();
   };
@@ -653,10 +714,23 @@ angular.module('zeppelinWebApp')
     }
   });
 
-  $scope.$on('focusParagraph', function(event, paragraphId) {
+  $scope.$on('focusParagraph', function(event, paragraphId, cursorPos) {
     if ($scope.paragraph.id === paragraphId) {
+      // focus editor
       $scope.editor.focus();
-      $('body').scrollTo('#'+paragraphId+'_editor', 300, {offset:-60});
+
+      // move cursor to the first row (or the last row)
+      var row;
+      if (cursorPos >= 0) {
+        row = cursorPos;
+        var column = 0;
+        $scope.editor.gotoLine(row, 0);
+      } else {
+        row = $scope.editor.session.getLength() - 1;
+        $scope.editor.gotoLine(row + 1, 0);
+      }
+
+      $scope.scrollToCursor($scope.paragraph.id, 0);
     }
   });