zeppelin-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From b..@apache.org
Subject zeppelin git commit: [ZEPPELIN-1743] Use explicit arguments in functions in paragraph.controller.js
Date Wed, 07 Dec 2016 13:03:02 GMT
Repository: zeppelin
Updated Branches:
  refs/heads/master 8360dae2f -> ba87ad334


[ZEPPELIN-1743] Use explicit arguments in functions in paragraph.controller.js

### What is this PR for?
This is `paragraph.controller.js` maintenance PR. It refactors most functions in paragraph controller to accept explicit parameters instead of getting data from `$scope`. It is a first - simple and safe - step in making paragraph controller more maintainable.

### What type of PR is it?
Refactoring

### Todos
* [x] - Call functions explicitly with parameters when makes sense
* [x] - Do minor refactoring when makes sense

### What is the Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-1743

### How should this be tested?
Make sure that paragraph works as expected by interacting with it;

Author: felizbear <ilya@nflabs.com>

Closes #1714 from felizbear/fe-explicit-arguments and squashes the following commits:

3c4384f [felizbear] fix test
d178848 [felizbear] remove unused event listener runParagraph
4e7db8d [felizbear] make arguments explicit in scroll up / down util functions
98376e4 [felizbear] remove custom prototype string method startsWith in favor of indexOf
e65cc18 [felizbear] pass whole paragraph to commitParagraph
620a6e0 [felizbear] make arguments explicit in various util functions
a9ddba6 [felizbear] refactor getProgress
9af71a0 [felizbear] make arguments explicit in autoAdjustEditorHeight
40ca7d1 [felizbear] make arguments explicit in getEditorSetting
3315b3c [felizbear] make arguments explicit in aceChanged
ba9a429 [felizbear] make arguments explicit in toggleOutput
569368c [felizbear] remove unused function toggleGraphOption
41772ac [felizbear] make arguments explicit in changeColWidth
b44972a [felizbear] make arguments explicit in show / hide lineNumbers
58dcf3a [felizbear] make arguments explicit in show / hide / set title
83f3b0f [felizbear] make arguments explicit in various open / close editor / table nonsense functions
62cb81a [felizbear] make arguments explicit in open / close table
414fd9e [felizbear] make arguments explicit in toggleEditor
c383a2f [felizbear] make arguments explicit in clearParagraphOutput
d807e6e [felizbear] make arguments explicit in removeParagraph
7bbb7dc [felizbear] make arguments explicit in insertNew
e9e584e [felizbear] make arguments explicit for moveUp and moveDown
99d23cf [felizbear] make arguments explicit in run
20d66e5 [felizbear] make arguments explicit in toggleEnableDisable
c2939d0 [felizbear] make arguments explicit in saveParagraph
abe56ed [felizbear] make arguments explicit in cancelParagraph
d25060b [felizbear] make arguments explicit in isRunning
13d3140 [felizbear] make arguments explicit in initializeDefault


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

Branch: refs/heads/master
Commit: ba87ad33439e53c14741b2c23e9dc2b7a3813b2a
Parents: 8360dae
Author: felizbear <ilya@nflabs.com>
Authored: Mon Dec 5 20:17:57 2016 +0900
Committer: Alexander Bezzubov <bzz@apache.org>
Committed: Wed Dec 7 22:02:49 2016 +0900

----------------------------------------------------------------------
 .../integration/ParagraphActionsIT.java         |  28 +-
 .../src/app/notebook/notebook.controller.js     |  43 ++-
 .../notebook/paragraph/paragraph-control.html   |  28 +-
 .../notebook/paragraph/paragraph.controller.js  | 369 ++++++++-----------
 .../src/app/notebook/paragraph/paragraph.html   |   8 +-
 .../paragraph/result/result-results.html        |  62 ++++
 .../paragraph/result/result.controller.js       |   4 +-
 zeppelin-web/test/spec/controllers/paragraph.js |   2 +-
 8 files changed, 278 insertions(+), 266 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/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 634f65b..0fc29c0 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
@@ -74,7 +74,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
           oldNosOfParas,
           CoreMatchers.equalTo(1));
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
-      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='insertNew()']")).click();
+      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click=\"insertNew('below')\"]")).click();
       waitForParagraph(2, "READY");
       Integer newNosOfParas = driver.findElements(By.xpath("//div[@ng-controller=\"ParagraphCtrl\"]")).size();
       collector.checkThat("After Insert New (using Insert New button) :  number of  paragraph",
@@ -82,7 +82,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
           CoreMatchers.equalTo(newNosOfParas));
 
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
-      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='removeParagraph()']")).click();
+      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='removeParagraph(paragraph)']")).click();
       ZeppelinITUtils.sleep(1000, false);
       driver.findElement(By.xpath("//div[@class='modal-dialog'][contains(.,'delete this paragraph')]" +
           "//div[@class='modal-footer']//button[contains(.,'OK')]")).click();
@@ -142,7 +142,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
 
       waitForParagraph(1, "READY");
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
-      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='insertNew()']"))
+      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click=\"insertNew('below')\"]"))
           .click();
       waitForParagraph(2, "READY");
       Integer oldNosOfParas = driver.findElements(By.xpath
@@ -152,7 +152,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
           CoreMatchers.equalTo(2));
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
 
-      clickAndWait(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='removeParagraph()']"));
+      clickAndWait(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='removeParagraph(paragraph)']"));
 
       clickAndWait(By.xpath("//div[@class='modal-dialog'][contains(.,'delete this paragraph')" +
           "]//div[@class='modal-footer']//button[contains(.,'OK')]"));
@@ -182,7 +182,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
       setTextOfParagraph(1, "1");
 
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
-      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='insertNew()']")).click();
+      driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click=\"insertNew('below')\"]")).click();
 
 
       waitForParagraph(2, "READY");
@@ -197,7 +197,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
           CoreMatchers.equalTo("2"));
 
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
-      clickAndWait(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='moveDown()']"));
+      clickAndWait(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='moveDown(paragraph)']"));
 
       collector.checkThat("The paragraph1 value contains",
           driver.findElement(By.xpath(getParagraphXPath(1) + "//div[contains(@class, 'editor')]")).getText(),
@@ -207,7 +207,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
           CoreMatchers.equalTo("1"));
 
       driver.findElement(By.xpath(getParagraphXPath(2) + "//span[@class='icon-settings']")).click();
-      clickAndWait(By.xpath(getParagraphXPath(2) + "//ul/li/a[@ng-click='moveUp()']"));
+      clickAndWait(By.xpath(getParagraphXPath(2) + "//ul/li/a[@ng-click='moveUp(paragraph)']"));
 
       collector.checkThat("The paragraph1 value contains",
           driver.findElement(By.xpath(getParagraphXPath(1) + "//div[contains(@class, 'editor')]")).getText(),
@@ -236,7 +236,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
       setTextOfParagraph(1, "println (\"abcd\")");
 
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
-      clickAndWait(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='toggleEnableDisable()']"));
+      clickAndWait(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='toggleEnableDisable(paragraph)']"));
       collector.checkThat("The play button class was ",
           driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-control-play']")).isDisplayed(), CoreMatchers.equalTo(false)
       );
@@ -281,7 +281,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
           CoreMatchers.equalTo("abcd"));
       driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
       clickAndWait(By.xpath(getParagraphXPath(1) +
-          "//ul/li/a[@ng-click='clearParagraphOutput()']"));
+          "//ul/li/a[@ng-click='clearParagraphOutput(paragraph)']"));
       collector.checkThat("After Clear  Output field contains ",
           driver.findElements(By.xpath(xpathToOutputField)).size(),
           CoreMatchers.equalTo(0));
@@ -310,7 +310,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
         clickAndWait(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']"));
         String visibleText = newWidth.toString();
         new Select(driver.findElement(By.xpath(getParagraphXPath(1)
-            + "//ul/li/a/form/select[(@ng-change='changeColWidth()')]"))).selectByVisibleText(visibleText);
+            + "//ul/li/a/form/select[(@ng-model='paragraph.config.colWidth')]"))).selectByVisibleText(visibleText);
         collector.checkThat("New Width is : " + newWidth,
             driver.findElement(By.xpath("//div[contains(@class,'col-md-" + newWidth + "')]")).isDisplayed(),
             CoreMatchers.equalTo(true));
@@ -333,8 +333,8 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
 
       String xpathToTitle = getParagraphXPath(1) + "//div[contains(@class, 'title')]/div";
       String xpathToSettingIcon = getParagraphXPath(1) + "//span[@class='icon-settings']";
-      String xpathToShowTitle = getParagraphXPath(1) + "//ul/li/a[@ng-click='showTitle()']";
-      String xpathToHideTitle = getParagraphXPath(1) + "//ul/li/a[@ng-click='hideTitle()']";
+      String xpathToShowTitle = getParagraphXPath(1) + "//ul/li/a[@ng-show='!paragraph.config.title']";
+      String xpathToHideTitle = getParagraphXPath(1) + "//ul/li/a[@ng-show='paragraph.config.title']";
 
       ZeppelinITUtils.turnOffImplicitWaits(driver);
       Integer titleElems = driver.findElements(By.xpath(xpathToTitle)).size();
@@ -399,8 +399,8 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
 
       waitForParagraph(1, "READY");
       String xpathToLineNumberField = getParagraphXPath(1) + "//div[contains(@class, 'ace_gutter-layer')]";
-      String xpathToShowLineNumberButton = getParagraphXPath(1) + "//ul/li/a[@ng-click='showLineNumbers()']";
-      String xpathToHideLineNumberButton = getParagraphXPath(1) + "//ul/li/a[@ng-click='hideLineNumbers()']";
+      String xpathToShowLineNumberButton = getParagraphXPath(1) + "//ul/li/a[@ng-click='showLineNumbers(paragraph)']";
+      String xpathToHideLineNumberButton = getParagraphXPath(1) + "//ul/li/a[@ng-click='hideLineNumbers(paragraph)']";
 
       collector.checkThat("Before \"Show line number\" the Line Number is Enabled ",
           driver.findElement(By.xpath(xpathToLineNumberField)).isDisplayed(),

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/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 f078a31..e8a90d1 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -215,8 +215,11 @@
 
     $scope.saveNote = function() {
       if ($scope.note && $scope.note.paragraphs) {
-        _.forEach($scope.note.paragraphs, function(n, key) {
-          angular.element('#' + n.id + '_paragraphColumn_main').scope().saveParagraph();
+        _.forEach($scope.note.paragraphs, function(par) {
+          angular
+            .element('#' + par.id + '_paragraphColumn_main')
+            .scope()
+            .saveParagraph(par);
         });
         $scope.isNoteDirty = null;
       }
@@ -722,10 +725,10 @@
       connectedOnce = true;
     });
 
-    $scope.$on('moveParagraphUp', function(event, paragraphId) {
+    $scope.$on('moveParagraphUp', function(event, paragraph) {
       var newIndex = -1;
       for (var i = 0; i < $scope.note.paragraphs.length; i++) {
-        if ($scope.note.paragraphs[i].id === paragraphId) {
+        if ($scope.note.paragraphs[i].id === paragraph.id) {
           newIndex = i - 1;
           break;
         }
@@ -734,16 +737,22 @@
         return;
       }
       // save dirtyText of moving paragraphs.
-      var prevParagraphId = $scope.note.paragraphs[newIndex].id;
-      angular.element('#' + paragraphId + '_paragraphColumn_main').scope().saveParagraph();
-      angular.element('#' + prevParagraphId + '_paragraphColumn_main').scope().saveParagraph();
-      websocketMsgSrv.moveParagraph(paragraphId, newIndex);
+      var prevParagraph = $scope.note.paragraphs[newIndex];
+      angular
+        .element('#' + paragraph.id + '_paragraphColumn_main')
+        .scope()
+        .saveParagraph(paragraph);
+      angular
+        .element('#' + prevParagraph.id + '_paragraphColumn_main')
+        .scope()
+        .saveParagraph(prevParagraph);
+      websocketMsgSrv.moveParagraph(paragraph.id, newIndex);
     });
 
-    $scope.$on('moveParagraphDown', function(event, paragraphId) {
+    $scope.$on('moveParagraphDown', function(event, paragraph) {
       var newIndex = -1;
       for (var i = 0; i < $scope.note.paragraphs.length; i++) {
-        if ($scope.note.paragraphs[i].id === paragraphId) {
+        if ($scope.note.paragraphs[i].id === paragraph.id) {
           newIndex = i + 1;
           break;
         }
@@ -753,10 +762,16 @@
         return;
       }
       // save dirtyText of moving paragraphs.
-      var nextParagraphId = $scope.note.paragraphs[newIndex].id;
-      angular.element('#' + paragraphId + '_paragraphColumn_main').scope().saveParagraph();
-      angular.element('#' + nextParagraphId + '_paragraphColumn_main').scope().saveParagraph();
-      websocketMsgSrv.moveParagraph(paragraphId, newIndex);
+      var nextParagraph = $scope.note.paragraphs[newIndex];
+      angular
+        .element('#' + paragraph.id + '_paragraphColumn_main')
+        .scope()
+        .saveParagraph(paragraph);
+      angular
+        .element('#' + nextParagraph.id + '_paragraphColumn_main')
+        .scope()
+        .saveParagraph(nextParagraph);
+      websocketMsgSrv.moveParagraph(paragraph.id, newIndex);
     });
 
     $scope.$on('moveFocusToPreviousParagraph', function(event, currentParagraphId) {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/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 87ef008..699ef4c 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
@@ -27,12 +27,12 @@ limitations under the License.
         ng-click="runParagraph(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" tooltip="Cancel"
-        ng-click="cancelParagraph()"
+        ng-click="cancelParagraph(paragraph)"
         ng-show="paragraph.status=='RUNNING' || paragraph.status=='PENDING'"></span>
   <span class="{{paragraph.config.editorHide ? 'icon-size-fullscreen' : 'icon-size-actual'}}" style="cursor:pointer;" tooltip-placement="top" tooltip="{{(paragraph.config.editorHide ? 'Show' : 'Hide') + ' editor'}}"
-        ng-click="toggleEditor()"></span>
+        ng-click="toggleEditor(paragraph)"></span>
   <span class="{{paragraph.config.tableHide ? 'icon-notebook' : 'icon-book-open'}}" style="cursor:pointer;" tooltip-placement="top" tooltip="{{(paragraph.config.tableHide ? 'Show' : 'Hide') + ' output'}}"
-        ng-click="toggleOutput()"></span>
+        ng-click="toggleOutput(paragraph)"></span>
   <span class="dropdown navbar-right">
     <span class="icon-settings" style="cursor:pointer"
           data-toggle="dropdown"
@@ -48,49 +48,49 @@ limitations under the License.
           <form style="display:inline; margin-left:5px;">
             <select ng-model="paragraph.config.colWidth"
                     class="selectpicker"
-                    ng-change="changeColWidth()"
+                    ng-change="changeColWidth(paragraph, paragraph.config.colWidth)"
                     ng-options="col for col in colWidthOption"></select>
           </form>
         </a>
       </li>
       <li>
-        <a ng-click="moveUp()" ng-hide="$first"><span class="icon-arrow-up"></span> Move Up</a>
+        <a ng-click="moveUp(paragraph)" ng-hide="$first"><span class="icon-arrow-up"></span> Move Up</a>
       </li>
       <li>
-        <a ng-click="moveDown()" ng-hide="$last"><span class="icon-arrow-down"></span> Move Down</a>
+        <a ng-click="moveDown(paragraph)" ng-hide="$last"><span class="icon-arrow-down"></span> Move Down</a>
       </li>
       <li>
-        <a ng-click="insertNew()"><span class="icon-plus"></span> Insert New</a>
+        <a ng-click="insertNew('below')"><span class="icon-plus"></span> Insert New</a>
       </li>
       <li>
         <a ng-click="copyParagraph(getEditorValue())"><span class="fa fa-copy"></span> Clone paragraph</a>
       </li>
       <li>
         <!-- paragraph handler -->
-        <a ng-click="hideTitle()"
+        <a ng-click="hideTitle(paragraph)"
            ng-show="paragraph.config.title"><span class="fa fa-font"></span> Hide title</a>
-        <a ng-click="showTitle()"
+        <a ng-click="showTitle(paragraph)"
            ng-show="!paragraph.config.title"><span class="fa fa-font"></span> Show title</a>
       </li>
       <li>
-        <a ng-click="hideLineNumbers()"
+        <a ng-click="hideLineNumbers(paragraph)"
            ng-show="paragraph.config.lineNumbers"><span class="fa fa-list-ol"></span> Hide line numbers</a>
-        <a ng-click="showLineNumbers()"
+        <a ng-click="showLineNumbers(paragraph)"
            ng-show="!paragraph.config.lineNumbers"><span class="fa fa-list-ol"></span> Show line numbers</a>
       </li>
       <li>
-        <a ng-click="toggleEnableDisable()"><span class="icon-control-play"></span>
+        <a ng-click="toggleEnableDisable(paragraph)"><span class="icon-control-play"></span>
           {{paragraph.config.enabled ? "Disable" : "Enable"}} run</a>
       </li>
       <li>
         <a ng-click="goToSingleParagraph()"><span class="icon-share-alt"></span> Link this paragraph</a>
       </li>
       <li>
-        <a ng-click="clearParagraphOutput()"><span class="fa fa-eraser"></span> Clear output</a>
+        <a ng-click="clearParagraphOutput(paragraph)"><span class="fa fa-eraser"></span> Clear output</a>
       </li>
       <li>
         <!-- remove paragraph -->
-        <a ng-click="removeParagraph()" ng-hide="$last"><span class="fa fa-times"></span> Remove</a>
+        <a ng-click="removeParagraph(paragraph)" ng-hide="$last"><span class="fa fa-times"></span> Remove</a>
       </li>
     </ul>
   </span>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/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 31ec43b..09598cf 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
@@ -118,12 +118,10 @@
 
       noteVarShareService.put($scope.paragraph.id + '_paragraphScope', paragraphScope);
 
-      initializeDefault();
+      initializeDefault($scope.paragraph.config);
     };
 
-    var initializeDefault = function() {
-      var config = $scope.paragraph.config;
-
+    var initializeDefault = function(config) {
       if (!config.colWidth) {
         config.colWidth = 12;
       }
@@ -192,17 +190,13 @@
       return !object;
     };
 
-    $scope.isRunning = function() {
-      if ($scope.paragraph.status === 'RUNNING' || $scope.paragraph.status === 'PENDING') {
-        return true;
-      } else {
-        return false;
-      }
+    $scope.isRunning = function(paragraph) {
+      return paragraph.status === 'RUNNING' || paragraph.status === 'PENDING';
     };
 
-    $scope.cancelParagraph = function() {
-      console.log('Cancel %o', $scope.paragraph.id);
-      websocketMsgSrv.cancelParagraphRun($scope.paragraph.id);
+    $scope.cancelParagraph = function(paragraph) {
+      console.log('Cancel %o', paragraph.id);
+      websocketMsgSrv.cancelParagraphRun(paragraph.id);
     };
 
     $scope.runParagraph = function(data) {
@@ -212,52 +206,47 @@
       $scope.dirtyText = undefined;
 
       if ($scope.paragraph.config.editorSetting.editOnDblClick) {
-        closeEditorAndOpenTable();
+        closeEditorAndOpenTable($scope.paragraph);
       } else if (editorSetting.isOutputHidden &&
           !$scope.paragraph.config.editorSetting.editOnDblClick) {
         // %md/%angular repl make output to be hidden by default after running
         // so should open output if repl changed from %md/%angular to another
-        openEditorAndOpenTable();
+        openEditorAndOpenTable($scope.paragraph);
       }
       editorSetting.isOutputHidden = $scope.paragraph.config.editorSetting.editOnDblClick;
     };
 
-    $scope.saveParagraph = function() {
-      if ($scope.dirtyText === undefined || $scope.dirtyText === $scope.originalText) {
+    $scope.saveParagraph = function(paragraph) {
+      const dirtyText = paragraph.text;
+      if (dirtyText === undefined || dirtyText === $scope.originalText) {
         return;
       }
-      commitParagraph($scope.paragraph.title, $scope.dirtyText, $scope.paragraph.config,
-        $scope.paragraph.settings.params);
-      $scope.originalText = angular.copy($scope.dirtyText);
+      commitParagraph(paragraph);
+      $scope.originalText = dirtyText;
       $scope.dirtyText = undefined;
     };
 
-    $scope.toggleEnableDisable = function() {
-      $scope.paragraph.config.enabled = $scope.paragraph.config.enabled ? false : true;
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+    $scope.toggleEnableDisable = function(paragraph) {
+      paragraph.config.enabled = !paragraph.config.enabled;
+      commitParagraph(paragraph);
     };
 
-    $scope.run = function() {
-      var editorValue = $scope.editor.getValue();
-      if (editorValue) {
-        if (!($scope.paragraph.status === 'RUNNING' || $scope.paragraph.status === 'PENDING')) {
-          $scope.runParagraph(editorValue);
-        }
+    $scope.run = function(paragraph, editorValue) {
+      if (editorValue && !$scope.isRunning(paragraph)) {
+        $scope.runParagraph(editorValue);
       }
     };
 
-    $scope.moveUp = function() {
-      $scope.$emit('moveParagraphUp', $scope.paragraph.id);
+    $scope.moveUp = function(paragraph) {
+      $scope.$emit('moveParagraphUp', paragraph);
     };
 
-    $scope.moveDown = function() {
-      $scope.$emit('moveParagraphDown', $scope.paragraph.id);
+    $scope.moveDown = function(paragraph) {
+      $scope.$emit('moveParagraphDown', paragraph);
     };
 
     $scope.insertNew = function(position) {
-      $scope.$emit('insertParagraph', $scope.paragraph.id, position || 'below');
+      $scope.$emit('insertParagraph', $scope.paragraph.id, position);
     };
 
     $scope.copyPara = function(position) {
@@ -292,9 +281,9 @@
                                         config, $scope.paragraph.settings.params);
     };
 
-    $scope.removeParagraph = function() {
+    $scope.removeParagraph = function(paragraph) {
       var paragraphs = angular.element('div[id$="_paragraphColumn_main"]');
-      if (paragraphs[paragraphs.length - 1].id.startsWith($scope.paragraph.id)) {
+      if (paragraphs[paragraphs.length - 1].id.indexOf(paragraph.id) === 0) {
         BootstrapDialog.alert({
           closable: true,
           message: 'The last paragraph can\'t be deleted.',
@@ -312,7 +301,7 @@
           callback: function(result) {
             if (result) {
               console.log('Remove paragraph');
-              websocketMsgSrv.removeParagraph($scope.paragraph.id);
+              websocketMsgSrv.removeParagraph(paragraph.id);
               $scope.$emit('moveFocusToNextParagraph', $scope.paragraph.id);
             }
           }
@@ -320,117 +309,84 @@
       }
     };
 
-    $scope.clearParagraphOutput = function() {
-      websocketMsgSrv.clearParagraphOutput($scope.paragraph.id);
+    $scope.clearParagraphOutput = function(paragraph) {
+      websocketMsgSrv.clearParagraphOutput(paragraph.id);
     };
 
-    $scope.toggleEditor = function() {
-      if ($scope.paragraph.config.editorHide) {
-        $scope.openEditor();
+    $scope.toggleEditor = function(paragraph) {
+      if (paragraph.config.editorHide) {
+        $scope.openEditor(paragraph);
       } else {
-        $scope.closeEditor();
+        $scope.closeEditor(paragraph);
       }
     };
 
-    $scope.closeEditor = function() {
+    $scope.closeEditor = function(paragraph) {
       console.log('close the note');
-
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.editorHide = true;
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+      paragraph.config.editorHide = true;
+      commitParagraph(paragraph);
     };
 
-    $scope.openEditor = function() {
+    $scope.openEditor = function(paragraph) {
       console.log('open the note');
-
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.editorHide = false;
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+      paragraph.config.editorHide = false;
+      commitParagraph(paragraph);
     };
 
-    $scope.closeTable = function() {
+    $scope.closeTable = function(paragraph) {
       console.log('close the output');
-
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.tableHide = true;
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+      paragraph.config.tableHide = true;
+      commitParagraph(paragraph);
     };
 
-    $scope.openTable = function() {
+    $scope.openTable = function(paragraph) {
       console.log('open the output');
-
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.tableHide = false;
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+      paragraph.config.tableHide = false;
+      commitParagraph(paragraph);
     };
 
-    var openEditorAndCloseTable = function() {
-      manageEditorAndTableState(false, true);
+    var openEditorAndCloseTable = function(paragraph) {
+      manageEditorAndTableState(paragraph, false, true);
     };
 
-    var closeEditorAndOpenTable = function() {
-      manageEditorAndTableState(true, false);
+    var closeEditorAndOpenTable = function(paragraph) {
+      manageEditorAndTableState(paragraph, true, false);
     };
 
-    var openEditorAndOpenTable = function() {
-      manageEditorAndTableState(false, false);
+    var openEditorAndOpenTable = function(paragraph) {
+      manageEditorAndTableState(paragraph, false, false);
     };
 
-    var manageEditorAndTableState = function(hideEditor, hideTable) {
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.editorHide = hideEditor;
-      newConfig.tableHide = hideTable;
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+    var manageEditorAndTableState = function(paragraph, hideEditor, hideTable) {
+      paragraph.config.editorHide = hideEditor;
+      paragraph.config.tableHide = hideTable;
+      commitParagraph(paragraph);
     };
 
-    $scope.showTitle = function() {
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.title = true;
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+    $scope.showTitle = function(paragraph) {
+      paragraph.config.title = true;
+      commitParagraph(paragraph);
     };
 
-    $scope.hideTitle = function() {
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.title = false;
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+    $scope.hideTitle = function(paragraph) {
+      paragraph.config.title = false;
+      commitParagraph(paragraph);
     };
 
-    $scope.setTitle = function() {
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+    $scope.setTitle = function(paragraph) {
+      commitParagraph(paragraph);
     };
 
-    $scope.showLineNumbers = function() {
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.lineNumbers = true;
+    $scope.showLineNumbers = function(paragraph) {
+      paragraph.config.lineNumbers = true;
       $scope.editor.renderer.setShowGutter(true);
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+      commitParagraph(paragraph);
     };
 
-    $scope.hideLineNumbers = function() {
-      var newParams = angular.copy($scope.paragraph.settings.params);
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.lineNumbers = false;
+    $scope.hideLineNumbers = function(paragraph) {
+      paragraph.config.lineNumbers = false;
       $scope.editor.renderer.setShowGutter(false);
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+      commitParagraph(paragraph);
     };
 
     $scope.columnWidthClass = function(n) {
@@ -441,37 +397,17 @@
       }
     };
 
-    $scope.changeColWidth = function(width) {
+    $scope.changeColWidth = function(paragraph, width) {
       angular.element('.navbar-right.open').removeClass('open');
-      if (!width || width !== $scope.paragraph.config.colWidth) {
-        if (width) {
-          $scope.paragraph.config.colWidth = width;
-        }
-        var newParams = angular.copy($scope.paragraph.settings.params);
-        var newConfig = angular.copy($scope.paragraph.config);
-
-        commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
-      }
-    };
-
-    $scope.toggleGraphOption = function() {
-      var newConfig = angular.copy($scope.paragraph.config);
-      if (newConfig.graph.optionOpen) {
-        newConfig.graph.optionOpen = false;
-      } else {
-        newConfig.graph.optionOpen = true;
+      if (width !== paragraph.config.colWidth) {
+        paragraph.config.colWidth = width;
+        commitParagraph(paragraph);
       }
-      var newParams = angular.copy($scope.paragraph.settings.params);
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
     };
 
-    $scope.toggleOutput = function() {
-      var newConfig = angular.copy($scope.paragraph.config);
-      newConfig.tableHide = !newConfig.tableHide;
-      var newParams = angular.copy($scope.paragraph.settings.params);
-
-      commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
+    $scope.toggleOutput = function(paragraph) {
+      paragraph.config.tableHide = !paragraph.config.tableHide;
+      commitParagraph(paragraph);
     };
 
     $scope.loadForm = function(formulaire, params) {
@@ -492,10 +428,12 @@
       }
     };
 
-    $scope.aceChanged = function() {
-      $scope.dirtyText = $scope.editor.getSession().getValue();
+    $scope.aceChanged = function(_, editor) {
+      var session = editor.getSession();
+      var dirtyText = session.getValue();
+      $scope.dirtyText = dirtyText;
       $scope.startSaveTimer();
-      setParagraphMode($scope.editor.getSession(), $scope.dirtyText, $scope.editor.getCursorPosition());
+      setParagraphMode(session, dirtyText, editor.getCursorPosition());
     };
 
     $scope.aceLoaded = function(_editor) {
@@ -512,15 +450,15 @@
         $scope.editor.setHighlightGutterLine(false);
         $scope.editor.getSession().setUseWrapMode(true);
         $scope.editor.setTheme('ace/theme/chrome');
-        $scope.editor.setReadOnly($scope.isRunning());
+        $scope.editor.setReadOnly($scope.isRunning($scope.paragraph));
         if ($scope.paragraphFocused) {
           $scope.editor.focus();
-          $scope.goToEnd();
+          $scope.goToEnd($scope.editor);
         }
 
-        autoAdjustEditorHeight(_editor.container.id);
+        autoAdjustEditorHeight(_editor);
         angular.element(window).resize(function() {
-          autoAdjustEditorHeight(_editor.container.id);
+          autoAdjustEditorHeight(_editor);
         });
 
         if (navigator.appVersion.indexOf('Mac') !== -1) {
@@ -590,13 +528,13 @@
         });
 
         $scope.editor.on('paste', function(e) {
-          if (e.text.startsWith('%')) {
+          if (e.text.indexOf('%') === 0) {
             pastePercentSign = true;
           }
         });
 
         $scope.editor.getSession().on('change', function(e, editSession) {
-          autoAdjustEditorHeight(_editor.container.id);
+          autoAdjustEditorHeight(_editor);
         });
 
         setParagraphMode($scope.editor.getSession(), $scope.editor.getSession().getValue());
@@ -676,12 +614,12 @@
       }
     };
 
-    var getEditorSetting = function(interpreterName) {
+    var getEditorSetting = function(paragraph, interpreterName) {
       var deferred = $q.defer();
-      websocketMsgSrv.getEditorSetting($scope.paragraph.id, interpreterName);
+      websocketMsgSrv.getEditorSetting(paragraph.id, interpreterName);
       $timeout(
         $scope.$on('editorSetting', function(event, data) {
-          if ($scope.paragraph.id === data.paragraphId) {
+          if (paragraph.id === data.paragraphId) {
             deferred.resolve(data);
           }
         }
@@ -709,7 +647,7 @@
           var magic = getInterpreterName(paragraphText);
           if (editorSetting.magic !== magic) {
             editorSetting.magic = magic;
-            getEditorSetting(magic)
+            getEditorSetting($scope.paragraph, magic)
               .then(function(setting) {
                 setEditorLanguage(session, setting.editor.language);
                 _.merge($scope.paragraph.config.editorSetting, setting.editor);
@@ -733,19 +671,20 @@
       return '';
     };
 
-    var autoAdjustEditorHeight = function(id) {
-      var editor = $scope.editor;
-      var height = editor.getSession().getScreenLength() * editor.renderer.lineHeight +
+    var autoAdjustEditorHeight = function(editor) {
+      var height =
+        editor.getSession().getScreenLength() *
+        editor.renderer.lineHeight +
         editor.renderer.scrollBar.getWidth();
 
-      angular.element('#' + id).height(height.toString() + 'px');
+      angular.element('#' + editor.container.id).height(height.toString() + 'px');
       editor.resize();
     };
 
     $rootScope.$on('scrollToCursor', function(event) {
       // scroll on 'scrollToCursor' event only when cursor is in the last paragraph
       var paragraphs = angular.element('div[id$="_paragraphColumn_main"]');
-      if (paragraphs[paragraphs.length - 1].id.startsWith($scope.paragraph.id)) {
+      if (paragraphs[paragraphs.length - 1].id.indexOf($scope.paragraph.id) === 0) {
         $scope.scrollToCursor($scope.paragraph.id, 0);
       }
     });
@@ -802,14 +741,13 @@
     };
 
     $scope.getProgress = function() {
-      return ($scope.currentProgress) ? $scope.currentProgress : 0;
+      return $scope.currentProgress || 0;
     };
 
-    $scope.getExecutionTime = function() {
-      var pdata = $scope.paragraph;
+    $scope.getExecutionTime = function(pdata) {
       var timeMs = Date.parse(pdata.dateFinished) - Date.parse(pdata.dateStarted);
       if (isNaN(timeMs) || timeMs < 0) {
-        if ($scope.isResultOutdated()) {
+        if ($scope.isResultOutdated(pdata)) {
           return 'outdated';
         }
         return '';
@@ -817,26 +755,25 @@
       var user = (pdata.user === undefined || pdata.user === null) ? 'anonymous' : pdata.user;
       var desc = 'Took ' + moment.duration((timeMs / 1000), 'seconds').format('h [hrs] m [min] s [sec]') +
         '. Last updated by ' + user + ' at ' + moment(pdata.dateFinished).format('MMMM DD YYYY, h:mm:ss A') + '.';
-      if ($scope.isResultOutdated()) {
+      if ($scope.isResultOutdated(pdata)) {
         desc += ' (outdated)';
       }
       return desc;
     };
 
-    $scope.getElapsedTime = function() {
-      return 'Started ' + moment($scope.paragraph.dateStarted).fromNow() + '.';
+    $scope.getElapsedTime = function(paragraph) {
+      return 'Started ' + moment(paragraph.dateStarted).fromNow() + '.';
     };
 
-    $scope.isResultOutdated = function() {
-      var pdata = $scope.paragraph;
+    $scope.isResultOutdated = function(pdata) {
       if (pdata.dateUpdated !== undefined && Date.parse(pdata.dateUpdated) > Date.parse(pdata.dateStarted)) {
         return true;
       }
       return false;
     };
 
-    $scope.goToEnd = function() {
-      $scope.editor.navigateFileEnd();
+    $scope.goToEnd = function(editor) {
+      editor.navigateFileEnd();
     };
 
     $scope.getResultType = function(paragraph) {
@@ -863,17 +800,19 @@
       return cell;
     };
 
-    var commitParagraph = function(title, text, config, params) {
-      websocketMsgSrv.commitParagraph($scope.paragraph.id, title, text, config, params);
+    var commitParagraph = function(paragraph) {
+      const {
+        id,
+        title,
+        text,
+        config,
+        settings: {params},
+      } = paragraph;
+
+      websocketMsgSrv.commitParagraph(id, title, text, config, params);
     };
 
     /** Utility function */
-    if (typeof String.prototype.startsWith !== 'function') {
-      String.prototype.startsWith = function(str) {
-        return this.slice(0, str.length) === str;
-      };
-    }
-
     $scope.goToSingleParagraph = function() {
       var noteId = $route.current.pathParams.noteId;
       var redirectToUrl = location.protocol + '//' + location.host + location.pathname + '#/notebook/' + noteId +
@@ -881,30 +820,30 @@
       $window.open(redirectToUrl);
     };
 
-    $scope.showScrollDownIcon = function() {
-      var doc = angular.element('#p' + $scope.paragraph.id + '_text');
+    $scope.showScrollDownIcon = function(id) {
+      var doc = angular.element('#p' + id + '_text');
       if (doc[0]) {
         return doc[0].scrollHeight > doc.innerHeight();
       }
       return false;
     };
 
-    $scope.scrollParagraphDown = function() {
-      var doc = angular.element('#p' + $scope.paragraph.id + '_text');
+    $scope.scrollParagraphDown = function(id) {
+      var doc = angular.element('#p' + id + '_text');
       doc.animate({scrollTop: doc[0].scrollHeight}, 500);
       $scope.keepScrollDown = true;
     };
 
-    $scope.showScrollUpIcon = function() {
-      if (angular.element('#p' + $scope.paragraph.id + '_text')[0]) {
-        return angular.element('#p' + $scope.paragraph.id + '_text')[0].scrollTop !== 0;
+    $scope.showScrollUpIcon = function(id) {
+      if (angular.element('#p' + id + '_text')[0]) {
+        return angular.element('#p' + id + '_text')[0].scrollTop !== 0;
       }
       return false;
 
     };
 
-    $scope.scrollParagraphUp = function() {
-      var doc = angular.element('#p' + $scope.paragraph.id + '_text');
+    $scope.scrollParagraphUp = function(id) {
+      var doc = angular.element('#p' + id + '_text');
       doc.animate({scrollTop: 0}, 500);
       $scope.keepScrollDown = false;
     };
@@ -960,7 +899,7 @@
         scope[varName] = data.angularObject.object;
 
         // create proxy for AngularFunction
-        if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
+        if (varName.indexOf(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX) === 0) {
           var funcName = varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
           scope[funcName] = function() {
             scope[varName] = arguments;
@@ -997,7 +936,7 @@
         scope[varName] = undefined;
 
         // remove proxy for AngularFunction
-        if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
+        if (varName.indexOf(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX) === 0) {
           var funcName = varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
           scope[funcName] = undefined;
         }
@@ -1072,11 +1011,11 @@
         $scope.paragraph.status = data.paragraph.status;
         $scope.paragraph.results = data.paragraph.results;
         $scope.paragraph.settings = data.paragraph.settings;
-        $scope.editor.setReadOnly($scope.isRunning());
+        $scope.editor.setReadOnly($scope.isRunning(data.paragraph));
 
         if (!$scope.asIframe) {
           $scope.paragraph.config = data.paragraph.config;
-          initializeDefault();
+          initializeDefault(data.paragraph.config);
         } else {
           data.paragraph.config.editorHide = true;
           data.paragraph.config.tableHide = false;
@@ -1087,7 +1026,7 @@
           // when last paragraph runs, zeppelin automatically appends new paragraph.
           // this broadcast will focus to the newly inserted paragraph
           var paragraphs = angular.element('div[id$="_paragraphColumn_main"]');
-          if (paragraphs.length >= 2 && paragraphs[paragraphs.length - 2].id.startsWith($scope.paragraph.id)) {
+          if (paragraphs.length >= 2 && paragraphs[paragraphs.length - 2].id.indexOf($scope.paragraph.id) === 0) {
             // rendering output can took some time. So delay scrolling event firing for sometime.
             setTimeout(function() {
               $rootScope.$broadcast('scrollToCursor');
@@ -1118,45 +1057,45 @@
           // move focus to next paragraph
           $scope.$emit('moveFocusToNextParagraph', paragraphId);
         } else if (keyEvent.shiftKey && keyCode === 13) { // Shift + Enter
-          $scope.run();
+          $scope.run($scope.paragraph, $scope.editor.getValue());
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 67) { // Ctrl + Alt + c
-          $scope.cancelParagraph();
+          $scope.cancelParagraph($scope.paragraph);
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 68) { // Ctrl + Alt + d
-          $scope.removeParagraph();
+          $scope.removeParagraph($scope.paragraph);
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 75) { // Ctrl + Alt + k
-          $scope.moveUp();
+          $scope.moveUp($scope.paragraph);
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 74) { // Ctrl + Alt + j
-          $scope.moveDown();
+          $scope.moveDown($scope.paragraph);
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 65) { // Ctrl + Alt + a
           $scope.insertNew('above');
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 66) { // Ctrl + Alt + b
           $scope.insertNew('below');
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 79) { // Ctrl + Alt + o
-          $scope.toggleOutput();
+          $scope.toggleOutput($scope.paragraph);
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 82) { // Ctrl + Alt + r
-          $scope.toggleEnableDisable();
+          $scope.toggleEnableDisable($scope.paragraph);
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 69) { // Ctrl + Alt + e
-          $scope.toggleEditor();
+          $scope.toggleEditor($scope.paragraph);
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 77) { // Ctrl + Alt + m
           if ($scope.paragraph.config.lineNumbers) {
-            $scope.hideLineNumbers();
+            $scope.hideLineNumbers($scope.paragraph);
           } else {
-            $scope.showLineNumbers();
+            $scope.showLineNumbers($scope.paragraph);
           }
         } else if (keyEvent.ctrlKey && keyEvent.shiftKey && keyCode === 189) { // Ctrl + Shift + -
-          $scope.changeColWidth(Math.max(1, $scope.paragraph.config.colWidth - 1));
+          $scope.changeColWidth($scope.paragraph, Math.max(1, $scope.paragraph.config.colWidth - 1));
         } else if (keyEvent.ctrlKey && keyEvent.shiftKey && keyCode === 187) { // Ctrl + Shift + =
-          $scope.changeColWidth(Math.min(12, $scope.paragraph.config.colWidth + 1));
+          $scope.changeColWidth($scope.paragraph, Math.min(12, $scope.paragraph.config.colWidth + 1));
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 84) { // Ctrl + Alt + t
           if ($scope.paragraph.config.title) {
-            $scope.hideTitle();
+            $scope.hideTitle($scope.paragraph);
           } else {
-            $scope.showTitle();
+            $scope.showTitle($scope.paragraph);
           }
         }else if (keyEvent.ctrlKey && keyEvent.shiftKey && keyCode === 67) { // Ctrl + Alt + c
           $scope.copyPara('below');
         } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 76) { // Ctrl + Alt + l
-          $scope.clearParagraphOutput();
+          $scope.clearParagraphOutput($scope.paragraph);
         } else {
           noShortcutDefined = true;
         }
@@ -1197,7 +1136,7 @@
       if ($scope.paragraph.id === paragraphId && $scope.paragraph.config.editorHide &&
           $scope.paragraph.config.editorSetting.editOnDblClick) {
         var deferred = $q.defer();
-        openEditorAndCloseTable();
+        openEditorAndCloseTable($scope.paragraph);
         $timeout(
           $scope.$on('updateParagraph', function(event, data) {
             deferred.resolve(data);
@@ -1206,29 +1145,25 @@
 
         deferred.promise.then(function(data) {
           $scope.editor.focus();
-          $scope.goToEnd();
+          $scope.goToEnd($scope.editor);
         });
       }
     });
 
-    $scope.$on('runParagraph', function(event) {
-      $scope.runParagraph($scope.editor.getValue());
-    });
-
     $scope.$on('openEditor', function(event) {
-      $scope.openEditor();
+      $scope.openEditor($scope.paragraph);
     });
 
     $scope.$on('closeEditor', function(event) {
-      $scope.closeEditor();
+      $scope.closeEditor($scope.paragraph);
     });
 
     $scope.$on('openTable', function(event) {
-      $scope.openTable();
+      $scope.openTable($scope.paragraph);
     });
 
     $scope.$on('closeTable', function(event) {
-      $scope.closeTable();
+      $scope.closeTable($scope.paragraph);
     });
   }
 })();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/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 69a6356..bbb6b03 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.html
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.html
@@ -26,8 +26,8 @@ limitations under the License.
            ng-model="paragraph.title"
            ng-if="input.showEditor"
            ng-escape="input.showEditor = false; paragraph.title = oldTitle;"
-           ng-blur="setTitle(); input.showEditor = false"
-           ng-enter="setTitle(); input.showEditor = false"
+           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; oldTitle = paragraph.title;"
          ng-show="!input.showEditor"
@@ -72,11 +72,11 @@ limitations under the License.
   <div ng-if="!asIframe" class="paragraphFooter">
     <div ng-show="!paragraph.config.tableHide && !viewOnly"
          id="{{paragraph.id}}_executionTime"
-         class="executionTime" ng-bind-html="getExecutionTime()">
+         class="executionTime" ng-bind-html="getExecutionTime(paragraph)">
     </div>
     <div ng-if = "paragraph.status === 'RUNNING'" class = "paragraphFooterElapsed">
       <div id="{{paragraph.id}}_elapsedTime"
-           class="elapsedTime" ng-bind-html="getElapsedTime()">
+           class="elapsedTime" ng-bind-html="getElapsedTime(paragraph)">
       </div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/zeppelin-web/src/app/notebook/paragraph/result/result-results.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/paragraph/result/result-results.html b/zeppelin-web/src/app/notebook/paragraph/result/result-results.html
new file mode 100644
index 0000000..13f050f
--- /dev/null
+++ b/zeppelin-web/src/app/notebook/paragraph/result/result-results.html
@@ -0,0 +1,62 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div
+  id="p{{id}}_resize"
+  ng-if="!config.helium.activeApp"
+  style="padding-bottom: 5px;"
+  resize='{"allowresize": "{{!asIframe && !viewOnly}}", "graphType": "{{type}}"}'
+     resizable on-resize="resize(width, height);">
+  <div ng-include src="'app/notebook/paragraph/result/result-graph.html'"></div>
+
+  <div id="{{id}}_comment"
+       class="text"
+       ng-if="type == 'TABLE' && tableDataComment"
+       ng-bind-html="tableDataComment">
+  </div>
+
+  <div id="p{{id}}_text"
+       ng-if="type == 'TEXT'">
+    <div class="fa fa-level-down scroll-paragraph-down"
+         ng-show="showScrollDownIcon(id)"
+         ng-click="scrollParagraphDown(id)"
+         tooltip="Follow Output"></div>
+    <div id="p{{id}}_text"
+         style="max-height: {{config.graph.height}}px; overflow: auto"
+         class="text"></div>
+    <div class="fa fa-chevron-up scroll-paragraph-up"
+         ng-show="showScrollUpIcon(id)"
+         ng-click="scrollParagraphUp(id)"
+         tooltip="Scroll Top"></div>
+  </div>
+
+  <div id="p{{id}}_html"
+       class="resultContained"
+       ng-if="type == 'HTML'">
+  </div>
+
+  <div id="p{{id}}_angular"
+       class="resultContained"
+       ng-if="type == 'ANGULAR'">
+  </div>
+
+  <img id="{{id}}_img"
+       ng-if="type == 'IMG'"
+       ng-src="{{getBase64ImageSrc(result.data)}}" />
+</div>
+
+<div ng-repeat="app in apps">
+  <div id="p{{app.id}}"
+       ng-show="config.helium.activeApp == app.id">
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js
index b05ad15..50a7a23 100644
--- a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js
+++ b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js
@@ -842,7 +842,7 @@
         scope[varName] = data.angularObject.object;
 
         // create proxy for AngularFunction
-        if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
+        if (varName.indexOf(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX) === 0) {
           var funcName = varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
           scope[funcName] = function() {
             scope[varName] = arguments;
@@ -881,7 +881,7 @@
         scope[varName] = undefined;
 
         // remove proxy for AngularFunction
-        if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
+        if (varName.indexOf(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX) === 0) {
           var funcName = varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
           scope[funcName] = undefined;
         }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/ba87ad33/zeppelin-web/test/spec/controllers/paragraph.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/paragraph.js b/zeppelin-web/test/spec/controllers/paragraph.js
index d3d71bf..2134736 100644
--- a/zeppelin-web/test/spec/controllers/paragraph.js
+++ b/zeppelin-web/test/spec/controllers/paragraph.js
@@ -34,7 +34,7 @@ describe('Controller: ParagraphCtrl', function() {
   var functions = ['isRunning', 'getIframeDimensions', 'cancelParagraph', 'runParagraph', 'saveParagraph',
     'moveUp', 'moveDown', 'insertNew', 'removeParagraph', 'toggleEditor', 'closeEditor', 'openEditor',
     'closeTable', 'openTable', 'showTitle', 'hideTitle', 'setTitle', 'showLineNumbers', 'hideLineNumbers',
-    'changeColWidth', 'columnWidthClass', 'toggleGraphOption', 'toggleOutput', 'loadForm',
+    'changeColWidth', 'columnWidthClass', 'toggleOutput', 'loadForm',
     'aceChanged', 'aceLoaded', 'getEditorValue', 'getProgress', 'getExecutionTime', 'isResultOutdated'];
 
   functions.forEach(function(fn) {


Mime
View raw message