Repository: zeppelin
Updated Branches:
  refs/heads/master cc0839efd -> ecb688f45


[ZEPPELIN-2460] Highlight active line in editor

### What is this PR for?

Highlight active line.

### What type of PR is it?
[Improvement]

### Todos
* [x] - Added ui-ace option
* [x] - Fix css for paragraph control not to be overrided by active line

### What is the Jira issue?

[ZEPPELIN-2460](https://issues.apache.org/jira/browse/ZEPPELIN-2460)

### How should this be tested?

1. Build: `mvn clean package -DskipTests; ./bin/zeppelin-daemon.sh restart`
2. Open a note and write some text.

### Screenshots (if appropriate)

![2460_active_line](https://cloud.githubusercontent.com/assets/4968473/26279598/de38b114-3df2-11e7-9d3a-f0d4f59b8cd1.gif)

### Questions:
* Does the licenses files need update? - NO
* Is there breaking changes for older versions? - NO
* Does this needs documentation? - NO

Author: 1ambda <[email protected]>

Closes #2356 from 1ambda/ZEPPELIN-2460/highlight-active-line and squashes the 
following commits:

2809093 [1ambda] fix: xpath for select, checkbox DOM
087942b [1ambda] fix: Use ng-if for title
e60f9a2 [1ambda] feat: Display title, control in the same line
bfa2fed [1ambda] fix: Set active line when note is created
ade9179 [1ambda] fix: Use blue-light color for active line
0366948 [1ambda] fix: Show single active line in a note
dfcb8aa [1ambda] fix: Control setting CSS not to overwrite active line
6424db5 [1ambda] feat: Highlight active line in editor


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

Branch: refs/heads/master
Commit: ecb688f45397be8c2e879663908b95c8a35964ec
Parents: cc0839e
Author: 1ambda <[email protected]>
Authored: Mon May 22 08:14:25 2017 +0900
Committer: Lee moon soo <[email protected]>
Committed: Sun May 28 09:34:12 2017 +0900

----------------------------------------------------------------------
 .../integration/ParagraphActionsIT.java         | 16 ++++----
 .../src/app/notebook/notebook.controller.js     |  6 ++-
 .../notebook/paragraph/paragraph-control.html   |  7 ++--
 .../notebook/paragraph/paragraph.controller.js  |  9 +++--
 .../src/app/notebook/paragraph/paragraph.css    | 35 +++++++++--------
 .../src/app/notebook/paragraph/paragraph.html   | 41 +++++++++++---------
 .../components/editor/ace.editor.directive.html |  5 +--
 7 files changed, 64 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ecb688f4/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
 
b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
index add23ac..414460b 100644
--- 
a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
+++ 
b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
@@ -253,7 +253,6 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
     } catch (Exception e) {
       handleException("Exception in ParagraphActionsIT while 
testDisableParagraphRunButton ", e);
     }
-
   }
 
   @Test
@@ -263,7 +262,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
     }
     try {
       String xpathToRunOnSelectionChangeCheckbox = getParagraphXPath(1) + 
"//ul/li/form/input[contains(@ng-checked, 'true')]";
-      String xpathToDropdownMenu = getParagraphXPath(1) + "//select";
+      String xpathToDropdownMenu = "(" + (getParagraphXPath(1) + 
"//select)[2]");
       String xpathToResultText = getParagraphXPath(1) + 
"//div[contains(@id,\"_html\")]";
 
       createNewNote();
@@ -593,7 +592,8 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
               CoreMatchers.equalTo("Howdy "));
 
-      Select dropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[1]"))));
+      Select dropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[2]"))));
+
       dropDownMenu.selectByVisibleText("Alice");
       collector.checkThat("After selection in drop down menu, output should 
display the newly selected option",
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
@@ -602,7 +602,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
       driver.findElement(By.xpath(getParagraphXPath(1) + 
"//span[@class='icon-settings']")).click();
       clickAndWait(By.xpath(getParagraphXPath(1) + 
"//ul/li/form/input[contains(@ng-checked, 'true')]"));
 
-      Select sameDropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[1]"))));
+      Select sameDropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[2]"))));
       sameDropDownMenu.selectByVisibleText("Bob");
       collector.checkThat("After 'Run on selection change' checkbox is 
unchecked, the paragraph should not run if selecting a different option",
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
@@ -632,7 +632,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
               CoreMatchers.containsString("Greetings han and leia and luke"));
 
-      WebElement firstCheckbox = driver.findElement(By.xpath("(" + 
getParagraphXPath(1) + "//input[@type='checkbox'])[1]"));
+      WebElement firstCheckbox = driver.findElement(By.xpath("(" + 
getParagraphXPath(1) + "//input[@type='checkbox'])[2]"));
       firstCheckbox.click();
       collector.checkThat("After unchecking one of the boxes, we can see the 
newly updated output without the option we unchecked",
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
@@ -641,7 +641,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
       driver.findElement(By.xpath(getParagraphXPath(1) + 
"//span[@class='icon-settings']")).click();
       clickAndWait(By.xpath(getParagraphXPath(1) + 
"//ul/li/form/input[contains(@ng-checked, 'true')]"));
 
-      WebElement secondCheckbox = driver.findElement(By.xpath("(" + 
getParagraphXPath(1) + "//input[@type='checkbox'])[2]"));
+      WebElement secondCheckbox = driver.findElement(By.xpath("(" + 
getParagraphXPath(1) + "//input[@type='checkbox'])[3]"));
       secondCheckbox.click();
       collector.checkThat("After 'Run on selection change' checkbox is 
unchecked, the paragraph should not run if check box state is modified",
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
@@ -676,7 +676,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
               CoreMatchers.equalTo("Howdy \nHowdy "));
 
-      Select dropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[1]"))));
+      Select dropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[2]"))));
       dropDownMenu.selectByVisibleText("Apple");
       collector.checkThat("After selection in drop down menu, output should 
display the new option we selected",
               driver.findElement(By.xpath(getParagraphXPath(1) + 
"//div[contains(@class, 'text plainTextContent')]")).getText(),
@@ -685,7 +685,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
       driver.findElement(By.xpath(getParagraphXPath(1) + 
"//span[@class='icon-settings']")).click();
       clickAndWait(By.xpath(getParagraphXPath(1) + 
"//ul/li/form/input[contains(@ng-checked, 'true')]"));
 
-      Select sameDropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[2]"))));
+      Select sameDropDownMenu = new Select(driver.findElement(By.xpath("(" + 
(getParagraphXPath(1) + "//select)[3]"))));
       sameDropDownMenu.selectByVisibleText("Earth");
       waitForParagraph(1, "FINISHED");
       collector.checkThat("After 'Run on selection change' checkbox is 
unchecked, the paragraph should not run if selecting a different option",

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ecb688f4/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 3944326..a512664 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -469,10 +469,12 @@ function NotebookCtrl ($scope, $route, $routeParams, 
$location, $rootScope,
 
   let addPara = function (paragraph, index) {
     $scope.note.paragraphs.splice(index, 0, paragraph)
-    _.each($scope.note.paragraphs, function (para) {
+    $scope.note.paragraphs.map(para => {
       if (para.id === paragraph.id) {
         para.focus = true
-        $scope.$broadcast('focusParagraph', para.id, 0, false)
+
+        // we need `$timeout` since angular DOM might not be initialized
+        $timeout(() => { $scope.$broadcast('focusParagraph', para.id, 0, 
false) })
       }
     })
   }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ecb688f4/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html 
b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
index 222b3b3..5523609 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
@@ -44,11 +44,12 @@ limitations under the License.
 
   <!-- Run / Cancel button -->
   <span ng-if="!revisionView">
-    <span class="icon-control-play" style="cursor:pointer;color:#3071A9" 
tooltip-placement="top" uib-tooltip="Run this paragraph (Shift+Enter)"
+    <span class="icon-control-play" style="cursor:pointer;color:#3071A9"
+          tooltip-placement="top" uib-tooltip="Run this paragraph 
(Shift+Enter)"
           ng-click="runParagraphFromButton(getEditorValue())"
           ng-show="paragraph.status!='RUNNING' && paragraph.status!='PENDING' 
&& paragraph.config.enabled"></span>
-    <span class="icon-control-pause" style="cursor:pointer;color:#CD5C5C" 
tooltip-placement="top"
-          uib-tooltip="Cancel (Ctrl+{{ (isMac ? 'Option' : 'Alt') }}+C)"
+    <span class="icon-control-pause" style="cursor:pointer;color:#CD5C5C"
+          tooltip-placement="top" uib-tooltip="Cancel (Ctrl+{{ (isMac ? 
'Option' : 'Alt') }}+C)"
           ng-click="cancelParagraph(paragraph)"
           ng-show="paragraph.status=='RUNNING' || 
paragraph.status=='PENDING'"></span>
     <span ng-show="paragraph.runtimeInfos.jobUrl.length == 1">

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ecb688f4/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 e333084..00be23e 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
@@ -647,10 +647,10 @@ function ParagraphCtrl ($scope, $rootScope, $route, 
$window, $routeParams, $loca
       $scope.editor.renderer.setShowGutter($scope.paragraph.config.lineNumbers)
       $scope.editor.setShowFoldWidgets(false)
       $scope.editor.setHighlightActiveLine(false)
-      $scope.editor.setHighlightGutterLine(false)
       $scope.editor.getSession().setUseWrapMode(true)
       $scope.editor.setTheme('ace/theme/chrome')
       $scope.editor.setReadOnly($scope.isRunning($scope.paragraph))
+      $scope.editor.setHighlightActiveLine($scope.paragraphFocused)
 
       if ($scope.paragraphFocused) {
         let prefix = '%' + getInterpreterName($scope.paragraph.text)
@@ -853,8 +853,11 @@ function ParagraphCtrl ($scope, $rootScope, $route, 
$window, $routeParams, $loca
     }
   }
 
-  const handleFocus = function (value, isDigestPass) {
-    $scope.paragraphFocused = value
+  const handleFocus = function (focused, isDigestPass) {
+    $scope.paragraphFocused = focused
+
+    if ($scope.editor) { $scope.editor.setHighlightActiveLine(focused) }
+
     if (isDigestPass === false || isDigestPass === undefined) {
       // Protect against error in case digest is already running
       $timeout(function () {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ecb688f4/zeppelin-web/src/app/notebook/paragraph/paragraph.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.css 
b/zeppelin-web/src/app/notebook/paragraph/paragraph.css
index b17acf7..1a5e992 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.css
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.css
@@ -113,7 +113,6 @@
   display: none;
   float: right;
   color: #999;
-  margin-top: -9px;
   margin-right: 0;
   position: absolute;
   clear: both;
@@ -175,18 +174,12 @@
 }
 
 .paragraph .control {
-  background: rgba(255,255,255,0.85);
+  display: inline-block;
   float: right;
+  background: rgba(255,255,255,0.85);
   color: #999;
-  margin-top: 1px;
-  margin-right: 5px;
-  position: absolute;
-  clear: both;
-  right: 15px;
-  top: 16px;
-  text-align: right;
   font-size: 12px;
-  padding: 4px;
+  margin-top: 5px;
 }
 
 .paragraph .control li {
@@ -275,8 +268,11 @@ table.table-shortcut {
 */
 
 .paragraph .title {
-  margin: 0;
+  display: inline-block;
+  float: left;
   font-size: 12px;
+  margin-bottom: 7px;
+  min-height: 24px;
 }
 
 .paragraph .title div {
@@ -370,10 +366,22 @@ table.table-shortcut {
   direction: ltr;
 }
 
+/** set highlight line color */
+#main .ace-chrome .ace_marker-layer .ace_active-line {
+  background: rgba(114, 127, 222, 0.08);
+}
+
+/** hide not focused cursors */
 .ace_hidden-cursors {
   opacity: 0;
 }
 
+/** set cursor color */
+#main .emacs-mode .ace_cursor {
+  background: #C0C0C0!important;
+  border: none !important;
+}
+
 .ace_text-input, .ace_gutter, .ace_layer,
 .emacs-mode, .ace_text-layer, .ace_cursor-layer,
 .ace_cursor, .ace_scrollbar {
@@ -384,11 +392,6 @@ table.table-shortcut {
  opacity: 0 !important;
 }
 
-#main .emacs-mode .ace_cursor {
-  background: #C0C0C0!important;
-  border: none !important;
-}
-
 /*
   Table Display CSS
 */

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ecb688f4/zeppelin-web/src/app/notebook/paragraph/paragraph.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.html 
b/zeppelin-web/src/app/notebook/paragraph/paragraph.html
index 0de5e64..367d3e7 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.html
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.html
@@ -15,24 +15,29 @@ limitations under the License.
 <div id="{{paragraph.id}}_container"
      ng-class="{'paragraph': !asIframe, 'paragraphAsIframe': asIframe}">
 
-  <div ng-if="paragraph.config.title"
-       id="{{paragraph.id}}_title"
-       ng-controller="ElasticInputCtrl as input"
-       class="title">
-    <input type="text"
-           pu-elastic-input
-           style="min-width: 400px; max-width: 80%;"
-           placeholder="Untitled"
-           ng-model="paragraph.title"
-           ng-if="input.showEditor"
-           ng-escape="input.showEditor = false; paragraph.title = oldTitle;"
-           ng-blur="setTitle(paragraph); input.showEditor = false"
-           ng-enter="setTitle(paragraph); input.showEditor = false"
-           focus-if="input.showEditor" />
-    <div ng-click="input.showEditor = !asIframe && !viewOnly && !revisionView; 
oldTitle = paragraph.title;"
-         ng-show="!input.showEditor"
-         ng-bind-html="paragraph.title || 'Untitled'">
+  <div>
+    <div ng-if="paragraph.config.title"
+         id="{{paragraph.id}}_title"
+         ng-controller="ElasticInputCtrl as input"
+         class="title">
+      <input type="text"
+             pu-elastic-input
+             style="min-width: 400px; max-width: 80%;"
+             placeholder="Untitled"
+             ng-model="paragraph.title"
+             ng-if="input.showEditor"
+             ng-escape="input.showEditor = false; paragraph.title = oldTitle;"
+             ng-blur="setTitle(paragraph); input.showEditor = false"
+             ng-enter="setTitle(paragraph); input.showEditor = false"
+             focus-if="input.showEditor" />
+      <div ng-click="input.showEditor = !asIframe && !viewOnly && 
!revisionView; oldTitle = paragraph.title;"
+           ng-show="!input.showEditor"
+           ng-bind-html="paragraph.title || 'Untitled'">
+      </div>
     </div>
+
+    <div ng-include 
src="'app/notebook/paragraph/paragraph-control.html'"></div>
+    <div style="display: inline-block; clear: both;"></div>
   </div>
 
   <div>
@@ -63,8 +68,6 @@ limitations under the License.
     </div>
   </div>
 
-  <div ng-include src="'app/notebook/paragraph/paragraph-control.html'"></div>
-
   <div ng-if="!asIframe" class="paragraphFooter">
     <div ng-show="!paragraph.config.tableHide && !viewOnly"
          id="{{paragraph.id}}_executionTime"

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ecb688f4/zeppelin-web/src/components/editor/ace.editor.directive.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/editor/ace.editor.directive.html 
b/zeppelin-web/src/components/editor/ace.editor.directive.html
index 4729e4b..1c0a1f0 100644
--- a/zeppelin-web/src/components/editor/ace.editor.directive.html
+++ b/zeppelin-web/src/components/editor/ace.editor.directive.html
@@ -13,10 +13,7 @@ limitations under the License.
 -->
 
 <div class="editor"
-     ui-ace="{
-               onLoad : onLoad,
-               require : ['ace/ext/language_tools']
-             }"
+     ui-ace="{ onLoad : onLoad, require : ['ace/ext/language_tools'] }"
      ng-model="paragraph.text"
      ng-class="{'paragraph-disable': paragraph.status == 'RUNNING' || 
paragraph.status == 'PENDING' || revisionView === true,
            'paragraph-text--dirty' : dirtyText !== originalText && dirtyText 
!== undefined}">

Reply via email to