Repository: zeppelin
Updated Branches:
  refs/heads/master dbe5e6c12 -> 9289bb8db


[Zeppelin-1167] Group $scope.$on functions

### What is this PR for?
This is a small refactoring PR for zeppelin-web.
This is moving all the code's `$scope.$on` functions together at the end of 
each controller file.

### What type of PR is it?
Refactoring

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

### How should this be tested?
No test is needed, the code was just moved around

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

Author: Damien CORNEAU <cornead...@gmail.com>

Closes #1178 from corneadoug/ZEPPELIN-1167 and squashes the following commits:

a282dc5 [Damien CORNEAU] Fix indentation in result-list controller
7cd9146 [Damien CORNEAU] group .on functions at the end of the controllers


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

Branch: refs/heads/master
Commit: 9289bb8dbc5d940dc0ee73d9843161c6f7d45353
Parents: dbe5e6c
Author: Damien CORNEAU <cornead...@gmail.com>
Authored: Wed Jul 13 16:52:01 2016 +0900
Committer: Damien CORNEAU <cornead...@gmail.com>
Committed: Tue Jul 19 15:02:47 2016 +0900

----------------------------------------------------------------------
 zeppelin-web/src/app/home/home.controller.js    |  38 +-
 .../src/app/jobmanager/jobmanager.controller.js |  58 +-
 .../src/app/notebook/notebook.controller.js     | 258 +++----
 .../notebook/paragraph/paragraph.controller.js  | 726 ++++++++++---------
 .../src/app/search/result-list.controller.js    | 232 +++---
 .../src/components/login/login.controller.js    |  11 +-
 .../src/components/navbar/navbar.controller.js  |  28 +-
 .../notenameImport.controller.js                |   4 +
 8 files changed, 691 insertions(+), 664 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/zeppelin-web/src/app/home/home.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/home/home.controller.js 
b/zeppelin-web/src/app/home/home.controller.js
index b733f53..1a23f9c 100644
--- a/zeppelin-web/src/app/home/home.controller.js
+++ b/zeppelin-web/src/app/home/home.controller.js
@@ -35,6 +35,27 @@ angular.module('zeppelinWebApp').controller('HomeCtrl', 
function($scope, noteboo
 
   initHome();
 
+  $scope.reloadNotebookList = function() {
+    websocketMsgSrv.reloadAllNotesFromRepo();
+    $scope.isReloadingNotes = true;
+  };
+
+  $scope.toggleFolderNode = function(node) {
+    node.hidden = !node.hidden;
+  };
+
+  angular.element('#loginModal').on('hidden.bs.modal', function(e) {
+    $rootScope.$broadcast('initLoginValues');
+  });
+
+  /*
+  ** $scope.$on functions below
+  */
+
+  $scope.$on('setNoteMenu', function(event, notes) {
+    $scope.isReloadingNotes = false;
+  });
+
   $scope.$on('setNoteContent', function(event, note) {
     if (note) {
       vm.note = note;
@@ -53,21 +74,4 @@ angular.module('zeppelinWebApp').controller('HomeCtrl', 
function($scope, noteboo
     }
   });
 
-  $scope.$on('setNoteMenu', function(event, notes) {
-    $scope.isReloadingNotes = false;
-  });
-
-  $scope.reloadNotebookList = function() {
-    websocketMsgSrv.reloadAllNotesFromRepo();
-    $scope.isReloadingNotes = true;
-  };
-
-  $scope.toggleFolderNode = function(node) {
-    node.hidden = !node.hidden;
-  };
-
-  angular.element('#loginModal').on('hidden.bs.modal', function(e) {
-    $rootScope.$broadcast('initLoginValues');
-  });
-
 });

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/zeppelin-web/src/app/jobmanager/jobmanager.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/jobmanager/jobmanager.controller.js 
b/zeppelin-web/src/app/jobmanager/jobmanager.controller.js
index 410f7c2..8102293 100644
--- a/zeppelin-web/src/app/jobmanager/jobmanager.controller.js
+++ b/zeppelin-web/src/app/jobmanager/jobmanager.controller.js
@@ -18,6 +18,37 @@ angular.module('zeppelinWebApp')
   .controller('JobmanagerCtrl',
     function($scope, websocketMsgSrv, $interval) {
 
+      $scope.filterValueToName = function(filterValue) {
+        var index = _.findIndex($scope.ACTIVE_INTERPRETERS, {value: 
filterValue});
+
+        if ($scope.ACTIVE_INTERPRETERS[index].name !== undefined) {
+          return $scope.ACTIVE_INTERPRETERS[index].name;
+        } else {
+          return 'undefined';
+        }
+      };
+
+      $scope.init = function() {
+        $scope.jobInfomations = [];
+        $scope.JobInfomationsByFilter = $scope.jobInfomations;
+
+        websocketMsgSrv.getNotebookJobsList();
+        var refreshObj = $interval(function() {
+          if ($scope.lastJobServerUnixTime !== undefined) {
+            
websocketMsgSrv.getUpdateNotebookJobsList($scope.lastJobServerUnixTime);
+          }
+        }, 1000);
+
+        $scope.$on('$destroy', function() {
+          $interval.cancel(refreshObj);
+          websocketMsgSrv.unsubscribeJobManager();
+        });
+      };
+
+      /*
+      ** $scope.$on functions below
+      */
+
       $scope.$on('setNotebookJobs', function(event, responseData) {
         $scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
         $scope.jobInfomations = responseData.jobs;
@@ -62,31 +93,4 @@ angular.module('zeppelinWebApp')
           }
         });
       });
-
-      $scope.filterValueToName = function(filterValue) {
-        var index = _.findIndex($scope.ACTIVE_INTERPRETERS, {value: 
filterValue});
-
-        if ($scope.ACTIVE_INTERPRETERS[index].name !== undefined) {
-          return $scope.ACTIVE_INTERPRETERS[index].name;
-        } else {
-          return 'undefined';
-        }
-      };
-
-      $scope.init = function() {
-        $scope.jobInfomations = [];
-        $scope.JobInfomationsByFilter = $scope.jobInfomations;
-
-        websocketMsgSrv.getNotebookJobsList();
-        var refreshObj = $interval(function() {
-          if ($scope.lastJobServerUnixTime !== undefined) {
-            
websocketMsgSrv.getUpdateNotebookJobsList($scope.lastJobServerUnixTime);
-          }
-        }, 1000);
-
-        $scope.$on('$destroy', function() {
-          $interval.cancel(refreshObj);
-          websocketMsgSrv.unsubscribeJobManager();
-        });
-      };
     });

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/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 f33bfac..7d58e46 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -55,13 +55,6 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', 
function($scope, $ro
   var searchText = [];
   $scope.role = '';
 
-  $scope.$on('setConnectedStatus', function(event, param) {
-    if (connectedOnce && param) {
-      initNotebook();
-    }
-    connectedOnce = true;
-  });
-
   $scope.getCronOptionNameFromValue = function(value) {
     if (!value) {
       return '';
@@ -288,15 +281,6 @@ 
angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
     $scope.saveNote();
   });
 
-  $scope.$on('$destroy', function() {
-    angular.element(window).off('beforeunload');
-    $scope.killSaveTimer();
-    $scope.saveNote();
-
-    document.removeEventListener('click', $scope.focusParagraphOnClick);
-    document.removeEventListener('keydown', $scope.keyboardShortcut);
-  });
-
   $scope.setLookAndFeel = function(looknfeel) {
     $scope.note.config.looknfeel = looknfeel;
     $scope.setConfig();
@@ -335,29 +319,6 @@ 
angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
     }
   };
 
-  /** update the current note */
-  $scope.$on('setNoteContent', function(event, note) {
-    if (note === undefined) {
-      $location.path('/');
-    }
-
-    $scope.paragraphUrl = $routeParams.paragraphId;
-    $scope.asIframe = $routeParams.asIframe;
-    if ($scope.paragraphUrl) {
-      note = cleanParagraphExcept($scope.paragraphUrl, note);
-      $rootScope.$broadcast('setIframe', $scope.asIframe);
-    }
-
-    if ($scope.note === null) {
-      $scope.note = note;
-    } else {
-      updateNote(note);
-    }
-    initializeLookAndFeel();
-    //open interpreter binding setting when there're none selected
-    getInterpreterBindings(getInterpreterBindingsCallBack);
-  });
-
   var initializeLookAndFeel = function() {
     if (!$scope.note.config.looknfeel) {
       $scope.note.config.looknfeel = 'default';
@@ -388,94 +349,6 @@ 
angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
     return noteCopy;
   };
 
-  // create new paragraph on current position
-  $scope.$on('insertParagraph', function(event, paragraphId, position) {
-    var newIndex = -1;
-    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
-      if ($scope.note.paragraphs[i].id === paragraphId) {
-        //determine position of where to add new paragraph; default is below
-        if (position === 'above') {
-          newIndex = i;
-        } else {
-          newIndex = i + 1;
-        }
-        break;
-      }
-    }
-
-    if (newIndex < 0 || newIndex > $scope.note.paragraphs.length) {
-      return;
-    }
-    websocketMsgSrv.insertParagraph(newIndex);
-  });
-
-  $scope.$on('moveParagraphUp', function(event, paragraphId) {
-    var newIndex = -1;
-    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
-      if ($scope.note.paragraphs[i].id === paragraphId) {
-        newIndex = i - 1;
-        break;
-      }
-    }
-    if (newIndex < 0 || newIndex >= $scope.note.paragraphs.length) {
-      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);
-  });
-
-  $scope.$on('moveParagraphDown', function(event, paragraphId) {
-    var newIndex = -1;
-    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
-      if ($scope.note.paragraphs[i].id === paragraphId) {
-        newIndex = i + 1;
-        break;
-      }
-    }
-
-    if (newIndex < 0 || newIndex >= $scope.note.paragraphs.length) {
-      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);
-  });
-
-  $scope.$on('moveFocusToPreviousParagraph', function(event, 
currentParagraphId) {
-    var focus = false;
-    for (var i = $scope.note.paragraphs.length - 1; i >= 0; i--) {
-      if (focus === false) {
-        if ($scope.note.paragraphs[i].id === currentParagraphId) {
-          focus = true;
-          continue;
-        }
-      } else {
-        $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id, -1);
-        break;
-      }
-    }
-  });
-
-  $scope.$on('moveFocusToNextParagraph', function(event, currentParagraphId) {
-    var focus = false;
-    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
-      if (focus === false) {
-        if ($scope.note.paragraphs[i].id === currentParagraphId) {
-          focus = true;
-          continue;
-        }
-      } else {
-        $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id, 0);
-        break;
-      }
-    }
-  });
-
   var updateNote = function(note) {
     /** update Note name */
     if (note.name !== $scope.note.name) {
@@ -887,11 +760,13 @@ 
angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
       $scope.search('owners');
     });
   }, 350));
+
   $scope.$watch('permissions.readers', _.debounce(function(readers) {
     $scope.$apply(function() {
       $scope.search('readers');
     });
   }, 350));
+
   $scope.$watch('permissions.writers', _.debounce(function(readers) {
     $scope.$apply(function() {
       $scope.search('writers');
@@ -972,4 +847,133 @@ 
angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
     angular.element('.ace_autocomplete').hide();
   });
 
+  /*
+  ** $scope.$on functions below
+  */
+
+  $scope.$on('setConnectedStatus', function(event, param) {
+    if (connectedOnce && param) {
+      initNotebook();
+    }
+    connectedOnce = true;
+  });
+
+  $scope.$on('moveParagraphUp', function(event, paragraphId) {
+    var newIndex = -1;
+    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
+      if ($scope.note.paragraphs[i].id === paragraphId) {
+        newIndex = i - 1;
+        break;
+      }
+    }
+    if (newIndex < 0 || newIndex >= $scope.note.paragraphs.length) {
+      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);
+  });
+
+  $scope.$on('moveParagraphDown', function(event, paragraphId) {
+    var newIndex = -1;
+    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
+      if ($scope.note.paragraphs[i].id === paragraphId) {
+        newIndex = i + 1;
+        break;
+      }
+    }
+
+    if (newIndex < 0 || newIndex >= $scope.note.paragraphs.length) {
+      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);
+  });
+
+  $scope.$on('moveFocusToPreviousParagraph', function(event, 
currentParagraphId) {
+    var focus = false;
+    for (var i = $scope.note.paragraphs.length - 1; i >= 0; i--) {
+      if (focus === false) {
+        if ($scope.note.paragraphs[i].id === currentParagraphId) {
+          focus = true;
+          continue;
+        }
+      } else {
+        $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id, -1);
+        break;
+      }
+    }
+  });
+
+  $scope.$on('moveFocusToNextParagraph', function(event, currentParagraphId) {
+    var focus = false;
+    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
+      if (focus === false) {
+        if ($scope.note.paragraphs[i].id === currentParagraphId) {
+          focus = true;
+          continue;
+        }
+      } else {
+        $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id, 0);
+        break;
+      }
+    }
+  });
+
+  $scope.$on('insertParagraph', function(event, paragraphId, position) {
+    var newIndex = -1;
+    for (var i = 0; i < $scope.note.paragraphs.length; i++) {
+      if ($scope.note.paragraphs[i].id === paragraphId) {
+        //determine position of where to add new paragraph; default is below
+        if (position === 'above') {
+          newIndex = i;
+        } else {
+          newIndex = i + 1;
+        }
+        break;
+      }
+    }
+
+    if (newIndex < 0 || newIndex > $scope.note.paragraphs.length) {
+      return;
+    }
+    websocketMsgSrv.insertParagraph(newIndex);
+  });
+
+  $scope.$on('setNoteContent', function(event, note) {
+    if (note === undefined) {
+      $location.path('/');
+    }
+
+    $scope.paragraphUrl = $routeParams.paragraphId;
+    $scope.asIframe = $routeParams.asIframe;
+    if ($scope.paragraphUrl) {
+      note = cleanParagraphExcept($scope.paragraphUrl, note);
+      $rootScope.$broadcast('setIframe', $scope.asIframe);
+    }
+
+    if ($scope.note === null) {
+      $scope.note = note;
+    } else {
+      updateNote(note);
+    }
+    initializeLookAndFeel();
+    //open interpreter binding setting when there're none selected
+    getInterpreterBindings(getInterpreterBindingsCallBack);
+  });
+
+  $scope.$on('$destroy', function() {
+    angular.element(window).off('beforeunload');
+    $scope.killSaveTimer();
+    $scope.saveNote();
+
+    document.removeEventListener('click', $scope.focusParagraphOnClick);
+    document.removeEventListener('keydown', $scope.keyboardShortcut);
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/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 8bb7731..fcf609e 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
@@ -208,115 +208,6 @@ 
angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
     }
   };
 
-  $scope.$on('angularObjectUpdate', function(event, data) {
-    var noteId = $route.current.pathParams.noteId;
-    if (!data.noteId || data.noteId === noteId) {
-      var scope;
-      var registry;
-
-      if (!data.paragraphId || data.paragraphId === $scope.paragraph.id) {
-        scope = paragraphScope;
-        registry = angularObjectRegistry;
-      } else {
-        var app = _.find($scope.apps, {id: data.paragraphId});
-        if (app) {
-          scope = getAppScope(app);
-          registry = getAppRegistry(app);
-        } else {
-          // no matching app in this paragraph
-          return;
-        }
-      }
-      var varName = data.angularObject.name;
-
-      if (angular.equals(data.angularObject.object, scope[varName])) {
-        // return when update has no change
-        return;
-      }
-
-      if (!registry[varName]) {
-        registry[varName] = {
-          interpreterGroupId: data.interpreterGroupId,
-          noteId: data.noteId,
-          paragraphId: data.paragraphId
-        };
-      } else {
-        registry[varName].noteId = registry[varName].noteId || data.noteId;
-        registry[varName].paragraphId = registry[varName].paragraphId || 
data.paragraphId;
-      }
-
-      registry[varName].skipEmit = true;
-
-      if (!registry[varName].clearWatcher) {
-        registry[varName].clearWatcher = scope.$watch(varName, 
function(newValue, oldValue) {
-          console.log('angular object (paragraph) updated %o %o', varName, 
registry[varName]);
-          if (registry[varName].skipEmit) {
-            registry[varName].skipEmit = false;
-            return;
-          }
-          websocketMsgSrv.updateAngularObject(
-            registry[varName].noteId,
-            registry[varName].paragraphId,
-            varName,
-            newValue,
-            registry[varName].interpreterGroupId);
-        });
-      }
-      console.log('angular object (paragraph) created %o', varName);
-      scope[varName] = data.angularObject.object;
-
-      // create proxy for AngularFunction
-      if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
-        var funcName = 
varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
-        scope[funcName] = function() {
-          scope[varName] = arguments;
-          console.log('angular function (paragraph) invoked %o', arguments);
-        };
-
-        console.log('angular function (paragraph) created %o', 
scope[funcName]);
-      }
-    }
-  });
-
-  $scope.$on('angularObjectRemove', function(event, data) {
-    var noteId = $route.current.pathParams.noteId;
-    if (!data.noteId || data.noteId === noteId) {
-      var scope;
-      var registry;
-
-      if (!data.paragraphId || data.paragraphId === $scope.paragraph.id) {
-        scope = paragraphScope;
-        registry = angularObjectRegistry;
-      } else {
-        var app = _.find($scope.apps, {id: data.paragraphId});
-        if (app) {
-          scope = getAppScope(app);
-          registry = getAppRegistry(app);
-        } else {
-          // no matching app in this paragraph
-          return;
-        }
-      }
-
-      var varName = data.name;
-
-      // clear watcher
-      if (registry[varName]) {
-        registry[varName].clearWatcher();
-        registry[varName] = undefined;
-      }
-
-      // remove scope variable
-      scope[varName] = undefined;
-
-      // remove proxy for AngularFunction
-      if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
-        var funcName = 
varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
-        scope[funcName] = undefined;
-      }
-    }
-  });
-
   var initializeDefault = function() {
     var config = $scope.paragraph.config;
 
@@ -383,137 +274,6 @@ 
angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
     return !object;
   };
 
-  // TODO: this may have impact on performance when there are many paragraphs 
in a note.
-  $scope.$on('updateParagraph', function(event, data) {
-    if (data.paragraph.id === $scope.paragraph.id &&
-        (data.paragraph.dateCreated !== $scope.paragraph.dateCreated ||
-         data.paragraph.dateFinished !== $scope.paragraph.dateFinished ||
-         data.paragraph.dateStarted !== $scope.paragraph.dateStarted ||
-         data.paragraph.dateUpdated !== $scope.paragraph.dateUpdated ||
-         data.paragraph.status !== $scope.paragraph.status ||
-         data.paragraph.jobName !== $scope.paragraph.jobName ||
-         data.paragraph.title !== $scope.paragraph.title ||
-         isEmpty(data.paragraph.result) !== isEmpty($scope.paragraph.result) ||
-         data.paragraph.errorMessage !== $scope.paragraph.errorMessage ||
-         !angular.equals(data.paragraph.settings, $scope.paragraph.settings) ||
-         !angular.equals(data.paragraph.config, $scope.paragraph.config))
-       ) {
-
-      var oldType = $scope.getResultType();
-      var newType = $scope.getResultType(data.paragraph);
-      var oldGraphMode = $scope.getGraphMode();
-      var newGraphMode = $scope.getGraphMode(data.paragraph);
-      var oldActiveApp = _.get($scope.paragraph.config, 'helium.activeApp');
-      var newActiveApp = _.get(data.paragraph.config, 'helium.activeApp');
-
-      var statusChanged = (data.paragraph.status !== $scope.paragraph.status);
-
-      var resultRefreshed = (data.paragraph.dateFinished !== 
$scope.paragraph.dateFinished) ||
-        isEmpty(data.paragraph.result) !== isEmpty($scope.paragraph.result) ||
-        data.paragraph.status === 'ERROR' || (data.paragraph.status === 
'FINISHED' && statusChanged) ||
-        (!newActiveApp && oldActiveApp !== newActiveApp);
-
-      //console.log("updateParagraph oldData %o, newData %o. type %o -> %o, 
mode %o -> %o", $scope.paragraph, data, oldType, newType, oldGraphMode, 
newGraphMode);
-
-      if ($scope.paragraph.text !== data.paragraph.text) {
-        if ($scope.dirtyText) {         // check if editor has local update
-          if ($scope.dirtyText === data.paragraph.text) {  // when local 
update is the same from remote, clear local update
-            $scope.paragraph.text = data.paragraph.text;
-            $scope.dirtyText = undefined;
-            $scope.originalText = angular.copy(data.paragraph.text);
-          } else { // if there're local update, keep it.
-            $scope.paragraph.text = $scope.dirtyText;
-          }
-        } else {
-          $scope.paragraph.text = data.paragraph.text;
-          $scope.originalText = angular.copy(data.paragraph.text);
-        }
-      }
-
-      /** push the rest */
-      $scope.paragraph.aborted = data.paragraph.aborted;
-      $scope.paragraph.user = data.paragraph.user;
-      $scope.paragraph.dateUpdated = data.paragraph.dateUpdated;
-      $scope.paragraph.dateCreated = data.paragraph.dateCreated;
-      $scope.paragraph.dateFinished = data.paragraph.dateFinished;
-      $scope.paragraph.dateStarted = data.paragraph.dateStarted;
-      $scope.paragraph.errorMessage = data.paragraph.errorMessage;
-      $scope.paragraph.jobName = data.paragraph.jobName;
-      $scope.paragraph.title = data.paragraph.title;
-      $scope.paragraph.lineNumbers = data.paragraph.lineNumbers;
-      $scope.paragraph.status = data.paragraph.status;
-      $scope.paragraph.result = data.paragraph.result;
-      $scope.paragraph.settings = data.paragraph.settings;
-
-      if (!$scope.asIframe) {
-        $scope.paragraph.config = data.paragraph.config;
-        initializeDefault();
-      } else {
-        data.paragraph.config.editorHide = true;
-        data.paragraph.config.tableHide = false;
-        $scope.paragraph.config = data.paragraph.config;
-      }
-
-      if (newType === 'TABLE') {
-        $scope.loadTableData($scope.paragraph.result);
-        if (oldType !== 'TABLE' || resultRefreshed) {
-          clearUnknownColsFromGraphOption();
-          selectDefaultColsForGraphOption();
-        }
-        /** User changed the chart type? */
-        if (oldGraphMode !== newGraphMode) {
-          $scope.setGraphMode(newGraphMode, false, false);
-        } else {
-          $scope.setGraphMode(newGraphMode, false, true);
-        }
-      } else if (newType === 'HTML' && resultRefreshed) {
-        $scope.renderHtml();
-      } else if (newType === 'ANGULAR' && resultRefreshed) {
-        $scope.renderAngular();
-      } else if (newType === 'TEXT' && resultRefreshed) {
-        $scope.renderText();
-      }
-
-      getApplicationStates();
-      getSuggestions();
-
-      if (newActiveApp && newActiveApp !== oldActiveApp) {
-        var app = _.find($scope.apps, {id: newActiveApp});
-        renderApp(app);
-      }
-
-      if (statusChanged || resultRefreshed) {
-        // 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)) {
-          // rendering output can took some time. So delay scrolling event 
firing for sometime.
-          setTimeout(function() {
-            $rootScope.$broadcast('scrollToCursor');
-          }, 500);
-        }
-      }
-    }
-
-  });
-
-  $scope.$on('appendParagraphOutput', function(event, data) {
-    if ($scope.paragraph.id === data.paragraphId) {
-      if ($scope.flushStreamingOutput) {
-        $scope.clearTextOutput();
-        $scope.flushStreamingOutput = false;
-      }
-      $scope.appendTextOutput(data.data);
-    }
-  });
-
-  $scope.$on('updateParagraphOutput', function(event, data) {
-    if ($scope.paragraph.id === data.paragraphId) {
-      $scope.clearTextOutput();
-      $scope.appendTextOutput(data.data);
-    }
-  });
-
   $scope.isRunning = function() {
     if ($scope.paragraph.status === 'RUNNING' || $scope.paragraph.status === 
'PENDING') {
       return true;
@@ -1060,129 +820,18 @@ 
angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
     $scope.editor.navigateLineEnd();
   };
 
-  $scope.$on('updateProgress', function(event, data) {
-    if (data.id === $scope.paragraph.id) {
-      $scope.currentProgress = data.progress;
+  $scope.getResultType = function(paragraph) {
+    var pdata = (paragraph) ? paragraph : $scope.paragraph;
+    if (pdata.result && pdata.result.type) {
+      return pdata.result.type;
+    } else {
+      return 'TEXT';
     }
-  });
+  };
 
-  $scope.$on('keyEvent', function(event, keyEvent) {
-    if ($scope.paragraphFocused) {
-
-      var paragraphId = $scope.paragraph.id;
-      var keyCode = keyEvent.keyCode;
-      var noShortcutDefined = false;
-      var editorHide = $scope.paragraph.config.editorHide;
-
-      if (editorHide && (keyCode === 38 || (keyCode === 80 && keyEvent.ctrlKey 
&& !keyEvent.altKey))) { // up
-        // move focus to previous paragraph
-        $scope.$emit('moveFocusToPreviousParagraph', paragraphId);
-      } else if (editorHide && (keyCode === 40 || (keyCode === 78 && 
keyEvent.ctrlKey && !keyEvent.altKey))) { // down
-        // move focus to next paragraph
-        $scope.$emit('moveFocusToNextParagraph', paragraphId);
-      } else if (keyEvent.shiftKey && keyCode === 13) { // Shift + Enter
-        $scope.run();
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 67) { // 
Ctrl + Alt + c
-        $scope.cancelParagraph();
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 68) { // 
Ctrl + Alt + d
-        $scope.removeParagraph();
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 75) { // 
Ctrl + Alt + k
-        $scope.moveUp();
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 74) { // 
Ctrl + Alt + j
-        $scope.moveDown();
-      } 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();
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 82) { // 
Ctrl + Alt + r
-        $scope.toggleEnableDisable();
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 69) { // 
Ctrl + Alt + e
-        $scope.toggleEditor();
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 77) { // 
Ctrl + Alt + m
-        if ($scope.paragraph.config.lineNumbers) {
-          $scope.hideLineNumbers();
-        } else {
-          $scope.showLineNumbers();
-        }
-      } else if (keyEvent.ctrlKey && keyEvent.shiftKey && keyCode === 189) { 
// Ctrl + Shift + -
-        $scope.changeColWidth(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));
-      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 84) { // 
Ctrl + Alt + t
-        if ($scope.paragraph.config.title) {
-          $scope.hideTitle();
-        } else {
-          $scope.showTitle();
-        }
-      } else {
-        noShortcutDefined = true;
-      }
-
-      if (!noShortcutDefined) {
-        keyEvent.preventDefault();
-      }
-    }
-  });
-
-  $scope.$on('focusParagraph', function(event, paragraphId, cursorPos, 
mouseEvent) {
-    if ($scope.paragraph.id === paragraphId) {
-      // focus editor
-      if (!$scope.paragraph.config.editorHide) {
-        if (!mouseEvent) {
-          $scope.editor.focus();
-          // move cursor to the first row (or the last row)
-          var row;
-          if (cursorPos >= 0) {
-            row = cursorPos;
-            $scope.editor.gotoLine(row, 0);
-          } else {
-            row = $scope.editor.session.getLength();
-            $scope.editor.gotoLine(row, 0);
-          }
-          $scope.scrollToCursor($scope.paragraph.id, 0);
-        }
-      }
-      $scope.handleFocus(true);
-    } else {
-      $scope.editor.blur();
-      $scope.handleFocus(false);
-    }
-  });
-
-  $scope.$on('runParagraph', function(event) {
-    $scope.runParagraph($scope.editor.getValue());
-  });
-
-  $scope.$on('openEditor', function(event) {
-    $scope.openEditor();
-  });
-
-  $scope.$on('closeEditor', function(event) {
-    $scope.closeEditor();
-  });
-
-  $scope.$on('openTable', function(event) {
-    $scope.openTable();
-  });
-
-  $scope.$on('closeTable', function(event) {
-    $scope.closeTable();
-  });
-
-  $scope.getResultType = function(paragraph) {
-    var pdata = (paragraph) ? paragraph : $scope.paragraph;
-    if (pdata.result && pdata.result.type) {
-      return pdata.result.type;
-    } else {
-      return 'TEXT';
-    }
-  };
-
-  $scope.getBase64ImageSrc = function(base64Data) {
-    return 'data:image/png;base64,' + base64Data;
-  };
+  $scope.getBase64ImageSrc = function(base64Data) {
+    return 'data:image/png;base64,' + base64Data;
+  };
 
   $scope.getGraphMode = function(paragraph) {
     var pdata = (paragraph) ? paragraph : $scope.paragraph;
@@ -2340,6 +1989,10 @@ 
angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
     $timeout(retryRenderer);
   };
 
+  /*
+  ** $scope.$on functions below
+  */
+
   $scope.$on('appendAppOutput', function(event, data) {
     if ($scope.paragraph.id === data.paragraphId) {
       var app = _.find($scope.apps, {id: data.appId});
@@ -2402,4 +2055,355 @@ 
angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
       }
     }
   });
+
+  $scope.$on('angularObjectUpdate', function(event, data) {
+    var noteId = $route.current.pathParams.noteId;
+    if (!data.noteId || data.noteId === noteId) {
+      var scope;
+      var registry;
+
+      if (!data.paragraphId || data.paragraphId === $scope.paragraph.id) {
+        scope = paragraphScope;
+        registry = angularObjectRegistry;
+      } else {
+        var app = _.find($scope.apps, {id: data.paragraphId});
+        if (app) {
+          scope = getAppScope(app);
+          registry = getAppRegistry(app);
+        } else {
+          // no matching app in this paragraph
+          return;
+        }
+      }
+      var varName = data.angularObject.name;
+
+      if (angular.equals(data.angularObject.object, scope[varName])) {
+        // return when update has no change
+        return;
+      }
+
+      if (!registry[varName]) {
+        registry[varName] = {
+          interpreterGroupId: data.interpreterGroupId,
+          noteId: data.noteId,
+          paragraphId: data.paragraphId
+        };
+      } else {
+        registry[varName].noteId = registry[varName].noteId || data.noteId;
+        registry[varName].paragraphId = registry[varName].paragraphId || 
data.paragraphId;
+      }
+
+      registry[varName].skipEmit = true;
+
+      if (!registry[varName].clearWatcher) {
+        registry[varName].clearWatcher = scope.$watch(varName, 
function(newValue, oldValue) {
+          console.log('angular object (paragraph) updated %o %o', varName, 
registry[varName]);
+          if (registry[varName].skipEmit) {
+            registry[varName].skipEmit = false;
+            return;
+          }
+          websocketMsgSrv.updateAngularObject(
+            registry[varName].noteId,
+            registry[varName].paragraphId,
+            varName,
+            newValue,
+            registry[varName].interpreterGroupId);
+        });
+      }
+      console.log('angular object (paragraph) created %o', varName);
+      scope[varName] = data.angularObject.object;
+
+      // create proxy for AngularFunction
+      if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
+        var funcName = 
varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
+        scope[funcName] = function() {
+          scope[varName] = arguments;
+          console.log('angular function (paragraph) invoked %o', arguments);
+        };
+
+        console.log('angular function (paragraph) created %o', 
scope[funcName]);
+      }
+    }
+  });
+
+  $scope.$on('angularObjectRemove', function(event, data) {
+    var noteId = $route.current.pathParams.noteId;
+    if (!data.noteId || data.noteId === noteId) {
+      var scope;
+      var registry;
+
+      if (!data.paragraphId || data.paragraphId === $scope.paragraph.id) {
+        scope = paragraphScope;
+        registry = angularObjectRegistry;
+      } else {
+        var app = _.find($scope.apps, {id: data.paragraphId});
+        if (app) {
+          scope = getAppScope(app);
+          registry = getAppRegistry(app);
+        } else {
+          // no matching app in this paragraph
+          return;
+        }
+      }
+
+      var varName = data.name;
+
+      // clear watcher
+      if (registry[varName]) {
+        registry[varName].clearWatcher();
+        registry[varName] = undefined;
+      }
+
+      // remove scope variable
+      scope[varName] = undefined;
+
+      // remove proxy for AngularFunction
+      if (varName.startsWith(ANGULAR_FUNCTION_OBJECT_NAME_PREFIX)) {
+        var funcName = 
varName.substring((ANGULAR_FUNCTION_OBJECT_NAME_PREFIX).length);
+        scope[funcName] = undefined;
+      }
+    }
+  });
+
+  $scope.$on('updateParagraph', function(event, data) {
+    if (data.paragraph.id === $scope.paragraph.id &&
+        (data.paragraph.dateCreated !== $scope.paragraph.dateCreated ||
+         data.paragraph.dateFinished !== $scope.paragraph.dateFinished ||
+         data.paragraph.dateStarted !== $scope.paragraph.dateStarted ||
+         data.paragraph.dateUpdated !== $scope.paragraph.dateUpdated ||
+         data.paragraph.status !== $scope.paragraph.status ||
+         data.paragraph.jobName !== $scope.paragraph.jobName ||
+         data.paragraph.title !== $scope.paragraph.title ||
+         isEmpty(data.paragraph.result) !== isEmpty($scope.paragraph.result) ||
+         data.paragraph.errorMessage !== $scope.paragraph.errorMessage ||
+         !angular.equals(data.paragraph.settings, $scope.paragraph.settings) ||
+         !angular.equals(data.paragraph.config, $scope.paragraph.config))
+       ) {
+
+      var oldType = $scope.getResultType();
+      var newType = $scope.getResultType(data.paragraph);
+      var oldGraphMode = $scope.getGraphMode();
+      var newGraphMode = $scope.getGraphMode(data.paragraph);
+      var oldActiveApp = _.get($scope.paragraph.config, 'helium.activeApp');
+      var newActiveApp = _.get(data.paragraph.config, 'helium.activeApp');
+
+      var statusChanged = (data.paragraph.status !== $scope.paragraph.status);
+
+      var resultRefreshed = (data.paragraph.dateFinished !== 
$scope.paragraph.dateFinished) ||
+        isEmpty(data.paragraph.result) !== isEmpty($scope.paragraph.result) ||
+        data.paragraph.status === 'ERROR' || (data.paragraph.status === 
'FINISHED' && statusChanged) ||
+        (!newActiveApp && oldActiveApp !== newActiveApp);
+
+      //console.log("updateParagraph oldData %o, newData %o. type %o -> %o, 
mode %o -> %o", $scope.paragraph, data, oldType, newType, oldGraphMode, 
newGraphMode);
+
+      if ($scope.paragraph.text !== data.paragraph.text) {
+        if ($scope.dirtyText) {         // check if editor has local update
+          if ($scope.dirtyText === data.paragraph.text) {  // when local 
update is the same from remote, clear local update
+            $scope.paragraph.text = data.paragraph.text;
+            $scope.dirtyText = undefined;
+            $scope.originalText = angular.copy(data.paragraph.text);
+          } else { // if there're local update, keep it.
+            $scope.paragraph.text = $scope.dirtyText;
+          }
+        } else {
+          $scope.paragraph.text = data.paragraph.text;
+          $scope.originalText = angular.copy(data.paragraph.text);
+        }
+      }
+
+      /** push the rest */
+      $scope.paragraph.aborted = data.paragraph.aborted;
+      $scope.paragraph.user = data.paragraph.user;
+      $scope.paragraph.dateUpdated = data.paragraph.dateUpdated;
+      $scope.paragraph.dateCreated = data.paragraph.dateCreated;
+      $scope.paragraph.dateFinished = data.paragraph.dateFinished;
+      $scope.paragraph.dateStarted = data.paragraph.dateStarted;
+      $scope.paragraph.errorMessage = data.paragraph.errorMessage;
+      $scope.paragraph.jobName = data.paragraph.jobName;
+      $scope.paragraph.title = data.paragraph.title;
+      $scope.paragraph.lineNumbers = data.paragraph.lineNumbers;
+      $scope.paragraph.status = data.paragraph.status;
+      $scope.paragraph.result = data.paragraph.result;
+      $scope.paragraph.settings = data.paragraph.settings;
+
+      if (!$scope.asIframe) {
+        $scope.paragraph.config = data.paragraph.config;
+        initializeDefault();
+      } else {
+        data.paragraph.config.editorHide = true;
+        data.paragraph.config.tableHide = false;
+        $scope.paragraph.config = data.paragraph.config;
+      }
+
+      if (newType === 'TABLE') {
+        $scope.loadTableData($scope.paragraph.result);
+        if (oldType !== 'TABLE' || resultRefreshed) {
+          clearUnknownColsFromGraphOption();
+          selectDefaultColsForGraphOption();
+        }
+        /** User changed the chart type? */
+        if (oldGraphMode !== newGraphMode) {
+          $scope.setGraphMode(newGraphMode, false, false);
+        } else {
+          $scope.setGraphMode(newGraphMode, false, true);
+        }
+      } else if (newType === 'HTML' && resultRefreshed) {
+        $scope.renderHtml();
+      } else if (newType === 'ANGULAR' && resultRefreshed) {
+        $scope.renderAngular();
+      } else if (newType === 'TEXT' && resultRefreshed) {
+        $scope.renderText();
+      }
+
+      getApplicationStates();
+      getSuggestions();
+
+      if (newActiveApp && newActiveApp !== oldActiveApp) {
+        var app = _.find($scope.apps, {id: newActiveApp});
+        renderApp(app);
+      }
+
+      if (statusChanged || resultRefreshed) {
+        // 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)) {
+          // rendering output can took some time. So delay scrolling event 
firing for sometime.
+          setTimeout(function() {
+            $rootScope.$broadcast('scrollToCursor');
+          }, 500);
+        }
+      }
+    }
+
+  });
+
+  $scope.$on('appendParagraphOutput', function(event, data) {
+    if ($scope.paragraph.id === data.paragraphId) {
+      if ($scope.flushStreamingOutput) {
+        $scope.clearTextOutput();
+        $scope.flushStreamingOutput = false;
+      }
+      $scope.appendTextOutput(data.data);
+    }
+  });
+
+  $scope.$on('updateParagraphOutput', function(event, data) {
+    if ($scope.paragraph.id === data.paragraphId) {
+      $scope.clearTextOutput();
+      $scope.appendTextOutput(data.data);
+    }
+  });
+
+  $scope.$on('updateProgress', function(event, data) {
+    if (data.id === $scope.paragraph.id) {
+      $scope.currentProgress = data.progress;
+    }
+  });
+
+  $scope.$on('keyEvent', function(event, keyEvent) {
+    if ($scope.paragraphFocused) {
+
+      var paragraphId = $scope.paragraph.id;
+      var keyCode = keyEvent.keyCode;
+      var noShortcutDefined = false;
+      var editorHide = $scope.paragraph.config.editorHide;
+
+      if (editorHide && (keyCode === 38 || (keyCode === 80 && keyEvent.ctrlKey 
&& !keyEvent.altKey))) { // up
+        // move focus to previous paragraph
+        $scope.$emit('moveFocusToPreviousParagraph', paragraphId);
+      } else if (editorHide && (keyCode === 40 || (keyCode === 78 && 
keyEvent.ctrlKey && !keyEvent.altKey))) { // down
+        // move focus to next paragraph
+        $scope.$emit('moveFocusToNextParagraph', paragraphId);
+      } else if (keyEvent.shiftKey && keyCode === 13) { // Shift + Enter
+        $scope.run();
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 67) { // 
Ctrl + Alt + c
+        $scope.cancelParagraph();
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 68) { // 
Ctrl + Alt + d
+        $scope.removeParagraph();
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 75) { // 
Ctrl + Alt + k
+        $scope.moveUp();
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 74) { // 
Ctrl + Alt + j
+        $scope.moveDown();
+      } 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();
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 82) { // 
Ctrl + Alt + r
+        $scope.toggleEnableDisable();
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 69) { // 
Ctrl + Alt + e
+        $scope.toggleEditor();
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 77) { // 
Ctrl + Alt + m
+        if ($scope.paragraph.config.lineNumbers) {
+          $scope.hideLineNumbers();
+        } else {
+          $scope.showLineNumbers();
+        }
+      } else if (keyEvent.ctrlKey && keyEvent.shiftKey && keyCode === 189) { 
// Ctrl + Shift + -
+        $scope.changeColWidth(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));
+      } else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 84) { // 
Ctrl + Alt + t
+        if ($scope.paragraph.config.title) {
+          $scope.hideTitle();
+        } else {
+          $scope.showTitle();
+        }
+      } else {
+        noShortcutDefined = true;
+      }
+
+      if (!noShortcutDefined) {
+        keyEvent.preventDefault();
+      }
+    }
+  });
+
+  $scope.$on('focusParagraph', function(event, paragraphId, cursorPos, 
mouseEvent) {
+    if ($scope.paragraph.id === paragraphId) {
+      // focus editor
+      if (!$scope.paragraph.config.editorHide) {
+        if (!mouseEvent) {
+          $scope.editor.focus();
+          // move cursor to the first row (or the last row)
+          var row;
+          if (cursorPos >= 0) {
+            row = cursorPos;
+            $scope.editor.gotoLine(row, 0);
+          } else {
+            row = $scope.editor.session.getLength();
+            $scope.editor.gotoLine(row, 0);
+          }
+          $scope.scrollToCursor($scope.paragraph.id, 0);
+        }
+      }
+      $scope.handleFocus(true);
+    } else {
+      $scope.editor.blur();
+      $scope.handleFocus(false);
+    }
+  });
+
+  $scope.$on('runParagraph', function(event) {
+    $scope.runParagraph($scope.editor.getValue());
+  });
+
+  $scope.$on('openEditor', function(event) {
+    $scope.openEditor();
+  });
+
+  $scope.$on('closeEditor', function(event) {
+    $scope.closeEditor();
+  });
+
+  $scope.$on('openTable', function(event) {
+    $scope.openTable();
+  });
+
+  $scope.$on('closeTable', function(event) {
+    $scope.closeTable();
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/zeppelin-web/src/app/search/result-list.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/search/result-list.controller.js 
b/zeppelin-web/src/app/search/result-list.controller.js
index 1cda335..807f4dc 100644
--- a/zeppelin-web/src/app/search/result-list.controller.js
+++ b/zeppelin-web/src/app/search/result-list.controller.js
@@ -23,136 +23,134 @@ angular
     var results = searchService.search({'q': $routeParams.searchTerm}).query();
 
     results.$promise.then(function(result) {
-    $scope.notes = result.body.map(function(note) {
-      // redirect to notebook when search result is a notebook itself,
-      // not a paragraph
-      if (!/\/paragraph\//.test(note.id)) {
-        return note;
-      }
+      $scope.notes = result.body.map(function(note) {
+        // redirect to notebook when search result is a notebook itself,
+        // not a paragraph
+        if (!/\/paragraph\//.test(note.id)) {
+          return note;
+        }
 
-      note.id = note.id.replace('paragraph/', '?paragraph=') +
-        '&term=' +
-        $routeParams.searchTerm;
+        note.id = note.id.replace('paragraph/', '?paragraph=') +
+          '&term=' + $routeParams.searchTerm;
 
-      return note;
-    });
-    if ($scope.notes.length === 0) {
-      $scope.isResult = false;
-    } else {
-      $scope.isResult = true;
-    }
-
-    $scope.$on('$routeChangeStart', function(event, next, current) {
-      if (next.originalPath !== '/search/:searchTerm') {
-        searchService.searchTerm = '';
+        return note;
+      });
+      if ($scope.notes.length === 0) {
+        $scope.isResult = false;
+      } else {
+        $scope.isResult = true;
       }
+
+      $scope.$on('$routeChangeStart', function(event, next, current) {
+        if (next.originalPath !== '/search/:searchTerm') {
+          searchService.searchTerm = '';
+        }
+      });
     });
-  });
 
     $scope.page = 0;
     $scope.allResults = false;
 
     $scope.highlightSearchResults = function(note) {
-    return function(_editor) {
-      function getEditorMode(text) {
-        var editorModes = {
-          'ace/mode/scala': /^%(\w*\.)?spark/,
-          'ace/mode/python': /^%(\w*\.)?(pyspark|python)/,
-          'ace/mode/r': /^%(\w*\.)?(r|sparkr|knitr)/,
-          'ace/mode/sql': /^%(\w*\.)?\wql/,
-          'ace/mode/markdown': /^%md/,
-          'ace/mode/sh': /^%sh/
-        };
-
-        return Object.keys(editorModes).reduce(function(res, mode) {
-          return editorModes[mode].test(text) ? mode : res;
-        }, 'ace/mode/scala');
-      }
-
-      var Range = ace.require('ace/range').Range;
-
-      _editor.setOption('highlightActiveLine', false);
-      _editor.$blockScrolling = Infinity;
-      _editor.setReadOnly(true);
-      _editor.renderer.setShowGutter(false);
-      _editor.setTheme('ace/theme/chrome');
-      _editor.getSession().setMode(getEditorMode(note.text));
-
-      function getIndeces(term) {
-        return function(str) {
-          var indeces = [];
-          var i = -1;
-          while ((i = str.indexOf(term, i + 1)) >= 0) {
-            indeces.push(i);
-          }
-          return indeces;
-        };
-      }
-
-      var result = '';
-      if (note.header !== '') {
-        result = note.header + '\n\n' + note.snippet;
-      } else {
-        result = note.snippet;
-      }
-
-      var lines = result
-        .split('\n')
-        .map(function(line, row) {
-
-          var match = line.match(/<B>(.+?)<\/B>/);
-
-          // return early if nothing to highlight
-          if (!match) {
-            return line;
-          }
-
-          var term = match[1];
-          var __line = line
-            .replace(/<B>/g, '')
-            .replace(/<\/B>/g, '');
-
-          var indeces = getIndeces(term)(__line);
-
-          indeces.forEach(function(start) {
-            var end = start + term.length;
-            if (note.header !== '' && row === 0) {
-              _editor
-                .getSession()
-                .addMarker(
-                new Range(row, 0, row, line.length),
-                'search-results-highlight-header',
-                'background'
-              );
-              _editor
-                .getSession()
-                .addMarker(
-                new Range(row, start, row, end),
-                'search-results-highlight',
-                'line'
-              );
-            } else {
-              _editor
-                .getSession()
-                .addMarker(
-                new Range(row, start, row, end),
-                'search-results-highlight',
-                'line'
-              );
+      return function(_editor) {
+        function getEditorMode(text) {
+          var editorModes = {
+            'ace/mode/scala': /^%(\w*\.)?spark/,
+            'ace/mode/python': /^%(\w*\.)?(pyspark|python)/,
+            'ace/mode/r': /^%(\w*\.)?(r|sparkr|knitr)/,
+            'ace/mode/sql': /^%(\w*\.)?\wql/,
+            'ace/mode/markdown': /^%md/,
+            'ace/mode/sh': /^%sh/
+          };
+
+          return Object.keys(editorModes).reduce(function(res, mode) {
+            return editorModes[mode].test(text) ? mode : res;
+          }, 'ace/mode/scala');
+        }
+
+        var Range = ace.require('ace/range').Range;
+
+        _editor.setOption('highlightActiveLine', false);
+        _editor.$blockScrolling = Infinity;
+        _editor.setReadOnly(true);
+        _editor.renderer.setShowGutter(false);
+        _editor.setTheme('ace/theme/chrome');
+        _editor.getSession().setMode(getEditorMode(note.text));
+
+        function getIndeces(term) {
+          return function(str) {
+            var indeces = [];
+            var i = -1;
+            while ((i = str.indexOf(term, i + 1)) >= 0) {
+              indeces.push(i);
+            }
+            return indeces;
+          };
+        }
+
+        var result = '';
+        if (note.header !== '') {
+          result = note.header + '\n\n' + note.snippet;
+        } else {
+          result = note.snippet;
+        }
+
+        var lines = result
+          .split('\n')
+          .map(function(line, row) {
+
+            var match = line.match(/<B>(.+?)<\/B>/);
+
+            // return early if nothing to highlight
+            if (!match) {
+              return line;
             }
+
+            var term = match[1];
+            var __line = line
+              .replace(/<B>/g, '')
+              .replace(/<\/B>/g, '');
+
+            var indeces = getIndeces(term)(__line);
+
+            indeces.forEach(function(start) {
+              var end = start + term.length;
+              if (note.header !== '' && row === 0) {
+                _editor
+                  .getSession()
+                  .addMarker(
+                    new Range(row, 0, row, line.length),
+                    'search-results-highlight-header',
+                    'background'
+                  );
+                _editor
+                  .getSession()
+                  .addMarker(
+                    new Range(row, start, row, end),
+                    'search-results-highlight',
+                    'line'
+                  );
+              } else {
+                _editor
+                  .getSession()
+                  .addMarker(
+                    new Range(row, start, row, end),
+                    'search-results-highlight',
+                    'line'
+                  );
+              }
+            });
+            return __line;
           });
-          return __line;
-        });
 
-      // resize editor based on content length
-      _editor.setOption(
-        'maxLines',
-        lines.reduce(function(len, line) {return len + line.length;}, 0)
-      );
+        // resize editor based on content length
+        _editor.setOption(
+          'maxLines',
+          lines.reduce(function(len, line) {return len + line.length;}, 0)
+        );
 
-      _editor.getSession().setValue(lines.join('\n'));
+        _editor.getSession().setValue(lines.join('\n'));
 
+      };
     };
-  };
-
   });

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/zeppelin-web/src/components/login/login.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/login/login.controller.js 
b/zeppelin-web/src/components/login/login.controller.js
index 2f3f10c..e47ca50 100644
--- a/zeppelin-web/src/components/login/login.controller.js
+++ b/zeppelin-web/src/components/login/login.controller.js
@@ -40,14 +40,19 @@ angular.module('zeppelinWebApp').controller('LoginCtrl',
 
     };
 
-    $scope.$on('initLoginValues', function() {
-      initValues();
-    });
     var initValues = function() {
       $scope.loginParams = {
         userName: '',
         password: ''
       };
     };
+
+    /*
+    ** $scope.$on functions below
+    */
+
+    $scope.$on('initLoginValues', function() {
+      initValues();
+    });
   }
 );

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/zeppelin-web/src/components/navbar/navbar.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar.controller.js 
b/zeppelin-web/src/components/navbar/navbar.controller.js
index 50d50ab..c8da491 100644
--- a/zeppelin-web/src/components/navbar/navbar.controller.js
+++ b/zeppelin-web/src/components/navbar/navbar.controller.js
@@ -40,18 +40,6 @@ angular.module('zeppelinWebApp')
     $scope.query.q = '';
   });
 
-  $scope.$on('setNoteMenu', function(event, notes) {
-    notebookListDataFactory.setNotes(notes);
-  });
-
-  $scope.$on('setConnectedStatus', function(event, param) {
-    vm.connected = param;
-  });
-
-  $scope.$on('loginSuccess', function(event, param) {
-    loadNotes();
-  });
-
   $scope.logout = function() {
     var logoutURL = baseUrlSrv.getRestApiBase() + '/login/logout';
 
@@ -108,4 +96,20 @@ angular.module('zeppelinWebApp')
   getZeppelinVersion();
   vm.loadNotes();
 
+  /*
+  ** $scope.$on functions below
+  */
+
+  $scope.$on('setNoteMenu', function(event, notes) {
+    notebookListDataFactory.setNotes(notes);
+  });
+
+  $scope.$on('setConnectedStatus', function(event, param) {
+    vm.connected = param;
+  });
+
+  $scope.$on('loginSuccess', function(event, param) {
+    loadNotes();
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9289bb8d/zeppelin-web/src/components/noteName-import/notenameImport.controller.js
----------------------------------------------------------------------
diff --git 
a/zeppelin-web/src/components/noteName-import/notenameImport.controller.js 
b/zeppelin-web/src/components/noteName-import/notenameImport.controller.js
index 766064f..dea3dd3 100644
--- a/zeppelin-web/src/components/noteName-import/notenameImport.controller.js
+++ b/zeppelin-web/src/components/noteName-import/notenameImport.controller.js
@@ -102,6 +102,10 @@ 
angular.module('zeppelinWebApp').controller('NoteImportCtrl', function($scope, $
     $scope.$apply();
   };
 
+  /*
+  ** $scope.$on functions below
+  */
+
   $scope.$on('setNoteMenu', function(event, notes) {
     vm.resetFlags();
     angular.element('#noteImportModal').modal('hide');

Reply via email to