Просмотр исходного кода

HUE-6185 [frontend] Properly dispose the ace editor and the autocompleter

This cleans out about 30 listeners when destroyed.
Johan Ahlen 8 лет назад
Родитель
Сommit
095a74b703

+ 176 - 50
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -3271,6 +3271,16 @@
       var apiHelper = snippet.getApiHelper();
       var apiHelper = snippet.getApiHelper();
       var aceOptions = options.aceOptions || {};
       var aceOptions = options.aceOptions || {};
 
 
+      var disposeFunctions = [];
+
+      var dispose = function () {
+        disposeFunctions.forEach(function (dispose) {
+          dispose();
+        })
+      };
+
+      ko.utils.domNodeDisposal.addDisposeCallback(element, dispose);
+
       $el.text(snippet.statement_raw());
       $el.text(snippet.statement_raw());
 
 
       window.setTimeout(function () {
       window.setTimeout(function () {
@@ -3316,19 +3326,25 @@
         }
         }
       }
       }
 
 
-
-      snippet.errors.subscribe(function (newErrors) {
+      var errorsSub = snippet.errors.subscribe(function (newErrors) {
         processErrorsAndWarnings('error', newErrors);
         processErrorsAndWarnings('error', newErrors);
       });
       });
 
 
-      snippet.aceWarnings.subscribe(function (newWarnings) {
+
+      var aceWarningsSub = snippet.aceWarnings.subscribe(function (newWarnings) {
         processErrorsAndWarnings('warning', newWarnings);
         processErrorsAndWarnings('warning', newWarnings);
       });
       });
 
 
-      snippet.aceErrors.subscribe(function (newErrors) {
+      var aceErrorsSub = snippet.aceErrors.subscribe(function (newErrors) {
         processErrorsAndWarnings('error', newErrors);
         processErrorsAndWarnings('error', newErrors);
       });
       });
 
 
+      disposeFunctions.push(function () {
+        errorsSub.dispose();
+        aceWarningsSub.dispose();
+        aceErrorsSub.dispose();
+      });
+
       editor.setTheme($.totalStorage("hue.ace.theme") || "ace/theme/hue");
       editor.setTheme($.totalStorage("hue.ace.theme") || "ace/theme/hue");
 
 
       var editorOptions = {
       var editorOptions = {
@@ -3391,7 +3407,7 @@
         var aceSqlWorker = new Worker('/static/desktop/js/aceSqlWorker.js?bust=' + Math.random());
         var aceSqlWorker = new Worker('/static/desktop/js/aceSqlWorker.js?bust=' + Math.random());
         var workerIsReady = false;
         var workerIsReady = false;
 
 
-        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
+        disposeFunctions.push(function () {
           aceSqlWorker.terminate();
           aceSqlWorker.terminate();
         });
         });
 
 
@@ -3423,10 +3439,14 @@
           var lastKnownLocations = { id: $el.attr("id"), type: snippet.type(), defaultDatabase: snippet.database(), locations: e.data.locations };
           var lastKnownLocations = { id: $el.attr("id"), type: snippet.type(), defaultDatabase: snippet.database(), locations: e.data.locations };
           huePubSub.publish('editor.active.locations', lastKnownLocations);
           huePubSub.publish('editor.active.locations', lastKnownLocations);
 
 
-          huePubSub.subscribe('get.active.editor.locations', function () {
+          var locationsSub = huePubSub.subscribe('get.active.editor.locations', function () {
             huePubSub.publish('editor.active.locations', lastKnownLocations);
             huePubSub.publish('editor.active.locations', lastKnownLocations);
           });
           });
 
 
+          disposeFunctions.push(function () {
+            locationsSub.remove();
+          });
+
 
 
           // Clear out old parse locations to prevent them from being shown when there's a syntax error in the statement
           // Clear out old parse locations to prevent them from being shown when there's a syntax error in the statement
           while(activeTokens.length > 0) {
           while(activeTokens.length > 0) {
@@ -3490,12 +3510,6 @@
           });
           });
         };
         };
 
 
-        editor.on("change", function (e) {
-          if (snippet.getAceMode() === 'ace/mode/hive' || snippet.getAceMode() === 'ace/mode/impala') {
-            aceSqlWorker.postMessage({ text: editor.getValue(), type: snippet.type() });
-          }
-        });
-
         var whenWorkerIsReady = function (callback) {
         var whenWorkerIsReady = function (callback) {
           if (!workerIsReady) {
           if (!workerIsReady) {
             aceSqlWorker.postMessage({ ping: true });
             aceSqlWorker.postMessage({ ping: true });
@@ -3507,13 +3521,17 @@
           }
           }
         };
         };
 
 
-        huePubSub.subscribe('editor.refresh.locations', function () {
+        var refreshSub = huePubSub.subscribe('editor.refresh.locations', function () {
           if (snippet.getAceMode() === 'ace/mode/hive' || snippet.getAceMode() === 'ace/mode/impala') {
           if (snippet.getAceMode() === 'ace/mode/hive' || snippet.getAceMode() === 'ace/mode/impala') {
             whenWorkerIsReady(function () {
             whenWorkerIsReady(function () {
               aceSqlWorker.postMessage({ text: editor.getValue(), type: snippet.type() });
               aceSqlWorker.postMessage({ text: editor.getValue(), type: snippet.type() });
             });
             });
           }
           }
         });
         });
+
+        disposeFunctions.push(function () {
+          refreshSub.remove();
+        });
       }
       }
 
 
       editorOptions['enableBasicAutocompletion'] = snippet.getApiHelper().getFromTotalStorage('hue.ace', 'enableBasicAutocompletion', true);
       editorOptions['enableBasicAutocompletion'] = snippet.getApiHelper().getFromTotalStorage('hue.ace', 'enableBasicAutocompletion', true);
@@ -3551,7 +3569,6 @@
       var langTools = ace.require("ace/ext/language_tools");
       var langTools = ace.require("ace/ext/language_tools");
       langTools.textCompleter.setSqlMode(snippet.isSqlDialect());
       langTools.textCompleter.setSqlMode(snippet.isSqlDialect());
 
 
-      editor.on("focus", initAutocompleters);
       initAutocompleters();
       initAutocompleters();
 
 
       var removeUnicodes = function (value) {
       var removeUnicodes = function (value) {
@@ -3575,7 +3592,7 @@
 
 
       var lastEditorValue = null;
       var lastEditorValue = null;
       var checkEditorValueInterval = -1;
       var checkEditorValueInterval = -1;
-      editor.on('paste', function (e) {
+      var pasteListener = editor.on('paste', function (e) {
         window.clearInterval(checkEditorValueInterval);
         window.clearInterval(checkEditorValueInterval);
         checkEditorValueInterval = window.setInterval(function () {
         checkEditorValueInterval = window.setInterval(function () {
           if (lastEditorValue !== editor.getValue()) {
           if (lastEditorValue !== editor.getValue()) {
@@ -3588,7 +3605,11 @@
         }, 10);
         }, 10);
       });
       });
 
 
-      editor.on("input", function () {
+      disposeFunctions.push(function () {
+        editor.off('paste', pasteListener);
+      });
+
+      var inputListener = editor.on('input', function () {
         if (editor.getValue().length == 0) {
         if (editor.getValue().length == 0) {
           if (!placeHolderVisible && placeHolderElement) {
           if (!placeHolderVisible && placeHolderElement) {
             placeHolderElement.appendTo(editor.renderer.scroller);
             placeHolderElement.appendTo(editor.renderer.scroller);
@@ -3603,7 +3624,12 @@
         }
         }
       });
       });
 
 
-      editor.on("focus", function () {
+      disposeFunctions.push(function () {
+        editor.off('input', inputListener);
+      });
+
+      var focusListener = editor.on('focus', function () {
+        initAutocompleters();
         snippet.inFocus(true);
         snippet.inFocus(true);
         $(".ace-editor").data("last-active-editor", false);
         $(".ace-editor").data("last-active-editor", false);
         $el.data("last-active-editor", true);
         $el.data("last-active-editor", true);
@@ -3616,23 +3642,32 @@
         }
         }
       });
       });
 
 
+      disposeFunctions.push(function () {
+        editor.off('focus', focusListener);
+      });
+
       var changeSelectionThrottle = -1;
       var changeSelectionThrottle = -1;
-      editor.selection.on("changeSelection", function () {
+      var changeSelectionListener = editor.selection.on('changeSelection', function () {
         window.clearTimeout(changeSelectionThrottle);
         window.clearTimeout(changeSelectionThrottle);
         changeSelectionThrottle = window.setTimeout(function () {
         changeSelectionThrottle = window.setTimeout(function () {
           huePubSub.publish('editor.active.cursor.location', { id: $el.attr("id"), position: editor.getCursorPosition() });
           huePubSub.publish('editor.active.cursor.location', { id: $el.attr("id"), position: editor.getCursorPosition() });
         }, 100);
         }, 100);
+        snippet.selectedStatement(editor.getSelectedText());
       });
       });
 
 
-      huePubSub.subscribe('get.active.editor.cursor.location', function () {
+      disposeFunctions.push(function () {
+        editor.selection.off('changeSelection', changeSelectionListener);
+      });
+
+      var cursorLocationSub = huePubSub.subscribe('get.active.editor.cursor.location', function () {
         huePubSub.publish('editor.active.cursor.location', { id: $el.attr("id"), position: editor.getCursorPosition() });
         huePubSub.publish('editor.active.cursor.location', { id: $el.attr("id"), position: editor.getCursorPosition() });
       });
       });
 
 
-      editor.selection.on("changeSelection", function () {
-        snippet.selectedStatement(editor.getSelectedText());
+      disposeFunctions.push(function () {
+        cursorLocationSub.remove();
       });
       });
 
 
-      editor.on("blur", function () {
+      var blurListener = editor.on('blur', function () {
         snippet.inFocus(false);
         snippet.inFocus(false);
         snippet.statement_raw(removeUnicodes(editor.getValue()));
         snippet.statement_raw(removeUnicodes(editor.getValue()));
         if (options.onBlur) {
         if (options.onBlur) {
@@ -3640,6 +3675,10 @@
         }
         }
       });
       });
 
 
+      disposeFunctions.push(function () {
+        editor.off('blur', blurListener);
+      });
+
       // TODO: Move context menu logic to separate module
       // TODO: Move context menu logic to separate module
       (function () {
       (function () {
         var Tooltip = ace.require("ace/tooltip").Tooltip;
         var Tooltip = ace.require("ace/tooltip").Tooltip;
@@ -3675,19 +3714,27 @@
           return range;
           return range;
         };
         };
 
 
-        huePubSub.subscribe('sql.context.popover.shown', function () {
+        var popoverShownSub = huePubSub.subscribe('sql.context.popover.shown', function () {
           hideContextTooltip();
           hideContextTooltip();
           keepLastMarker = true;
           keepLastMarker = true;
           disableTooltip = true;
           disableTooltip = true;
         });
         });
 
 
-        huePubSub.subscribe('sql.context.popover.hidden', function () {
+        disposeFunctions.push(function () {
+          popoverShownSub.remove();
+        });
+
+        var popoverHiddenSub = huePubSub.subscribe('sql.context.popover.hidden', function () {
           disableTooltip = false;
           disableTooltip = false;
           clearActiveMarkers();
           clearActiveMarkers();
           keepLastMarker = false;
           keepLastMarker = false;
         });
         });
 
 
-        editor.on("mousemove", function (e) {
+        disposeFunctions.push(function () {
+          popoverHiddenSub.remove();
+        });
+
+        var mousemoveListener = editor.on('mousemove', function (e) {
           clearTimeout(tooltipTimeout);
           clearTimeout(tooltipTimeout);
           var selectionRange = editor.selection.getRange();
           var selectionRange = editor.selection.getRange();
           if (selectionRange.isEmpty()) {
           if (selectionRange.isEmpty()) {
@@ -3724,19 +3771,33 @@
           }
           }
         });
         });
 
 
-        editor.on("input", function (e) {
+        disposeFunctions.push(function () {
+          editor.off('mousemove', mousemoveListener);
+        });
+
+        var inputListener = editor.on('input', function (e) {
           clearActiveMarkers();
           clearActiveMarkers();
           lastHoveredToken = null;
           lastHoveredToken = null;
         });
         });
 
 
-        editor.container.addEventListener("mouseout", function (e) {
+        disposeFunctions.push(function () {
+          editor.off('input', mousemoveListener);
+        });
+
+        var mouseoutListener = function (e) {
           clearActiveMarkers();
           clearActiveMarkers();
           clearTimeout(tooltipTimeout);
           clearTimeout(tooltipTimeout);
           contextTooltip.hide();
           contextTooltip.hide();
           lastHoveredToken = null;
           lastHoveredToken = null;
+        };
+
+        editor.container.addEventListener('mouseout', mouseoutListener);
+
+        disposeFunctions.push(function () {
+          editor.container.removeEventListener('mouseout', mouseoutListener);
         });
         });
 
 
-        editor.container.addEventListener("contextmenu", function (e) {
+        var contextmenuListener = function (e) {
           var selectionRange = editor.selection.getRange();
           var selectionRange = editor.selection.getRange();
           huePubSub.publish('sql.context.popover.hide');
           huePubSub.publish('sql.context.popover.hide');
           if (selectionRange.isEmpty()) {
           if (selectionRange.isEmpty()) {
@@ -3763,18 +3824,29 @@
               return false;
               return false;
             }
             }
           }
           }
+        };
+
+        var contextmenuListener = editor.container.addEventListener('contextmenu', contextmenuListener);
+
+        disposeFunctions.push(function () {
+          editor.container.removeEventListener('contextmenu', contextmenuListener);
         });
         });
+
       }());
       }());
 
 
       editor.previousSize = 0;
       editor.previousSize = 0;
 
 
       // TODO: Get rid of this
       // TODO: Get rid of this
-      window.setInterval(function(){
+      var idInterval = window.setInterval(function(){
         editor.session.getMode().$id = snippet.getAceMode(); // forces the id again because of Ace command internals
         editor.session.getMode().$id = snippet.getAceMode(); // forces the id again because of Ace command internals
       }, 100);
       }, 100);
 
 
+      disposeFunctions.push(function () {
+        window.clearInterval(idInterval);
+      });
+
       editor.middleClick = false;
       editor.middleClick = false;
-      editor.on("mousedown", function (e) {
+      var mousedownListener = editor.on('mousedown', function (e) {
         if (e.domEvent.which == 2) { // middle click
         if (e.domEvent.which == 2) { // middle click
           editor.middleClick = true;
           editor.middleClick = true;
           var tempText = editor.getSelectedText();
           var tempText = editor.getSelectedText();
@@ -3790,17 +3862,33 @@
         }
         }
       });
       });
 
 
-      huePubSub.subscribe('ace.replace', function (data) {
+      disposeFunctions.push(function () {
+        editor.off('mousedown', mousedownListener);
+      });
+
+      var aceReplaceSub = huePubSub.subscribe('ace.replace', function (data) {
         var Range = ace.require('ace/range').Range;
         var Range = ace.require('ace/range').Range;
         var range = new Range(data.location.first_line - 1, data.location.first_column - 1, data.location.last_line - 1, data.location.last_column - 1);
         var range = new Range(data.location.first_line - 1, data.location.first_column - 1, data.location.last_line - 1, data.location.last_column - 1);
         editor.getSession().getDocument().replace(range, data.text);
         editor.getSession().getDocument().replace(range, data.text);
       });
       });
 
 
-      editor.on("click", function (e) {
+      disposeFunctions.push(function () {
+        aceReplaceSub.remove();
+      });
+
+      var clickListener = editor.on('click', function (e) {
         editor.clearErrorsAndWarnings();
         editor.clearErrorsAndWarnings();
       });
       });
 
 
-      editor.on("change", function (e) {
+      disposeFunctions.push(function () {
+        editor.off('click', clickListener);
+      });
+
+      var changeListener = editor.on("change", function (e) {
+        if (snippet.getAceMode() === 'ace/mode/hive' || snippet.getAceMode() === 'ace/mode/impala') {
+          aceSqlWorker.postMessage({ text: editor.getValue(), type: snippet.type() });
+        }
+
         snippet.statement_raw(removeUnicodes(editor.getValue()));
         snippet.statement_raw(removeUnicodes(editor.getValue()));
         editor.session.getMode().$id = snippet.getAceMode();
         editor.session.getMode().$id = snippet.getAceMode();
         var currentSize = editor.session.getLength();
         var currentSize = editor.session.getLength();
@@ -3826,6 +3914,10 @@
         }
         }
       });
       });
 
 
+      disposeFunctions.push(function () {
+        editor.off("change", changeListener);
+      });
+
       editor.commands.addCommand({
       editor.commands.addCommand({
         name: "execute",
         name: "execute",
         bindKey: {win: "Ctrl-Enter", mac: "Command-Enter|Ctrl-Enter"},
         bindKey: {win: "Ctrl-Enter", mac: "Command-Enter|Ctrl-Enter"},
@@ -3883,7 +3975,7 @@
         return /^\s*$/.test(editor.getValue()) || /^.*;\s*$/.test(editor.getTextBeforeCursor());
         return /^\s*$/.test(editor.getValue()) || /^.*;\s*$/.test(editor.getTextBeforeCursor());
       };
       };
 
 
-      huePubSub.subscribe('editor.insert.table.at.cursor', function(details) {
+      var insertTableAtCursorSub = huePubSub.subscribe('editor.insert.table.at.cursor', function(details) {
         if ($el.data('last-active-editor')) {
         if ($el.data('last-active-editor')) {
           var qualifiedName = snippet.database() == details.database ? details.name : details.database + '.' + details.name;
           var qualifiedName = snippet.database() == details.database ? details.name : details.database + '.' + details.name;
           if (isNewStatement()) {
           if (isNewStatement()) {
@@ -3894,7 +3986,11 @@
         }
         }
       });
       });
 
 
-      huePubSub.subscribe('editor.insert.column.at.cursor', function(details) {
+      disposeFunctions.push(function () {
+        insertTableAtCursorSub.remove();
+      });
+
+      var insertColumnAtCursorSub = huePubSub.subscribe('editor.insert.column.at.cursor', function(details) {
         if ($el.data('last-active-editor')) {
         if ($el.data('last-active-editor')) {
           if (isNewStatement()) {
           if (isNewStatement()) {
             var qualifiedFromName = snippet.database() == details.database ? details.table : details.database + '.' + details.table;
             var qualifiedFromName = snippet.database() == details.database ? details.table : details.database + '.' + details.table;
@@ -3905,30 +4001,51 @@
         }
         }
       });
       });
 
 
-      huePubSub.subscribe("assist.dblClickHdfsItem", function(assistHdfsEntry) {
+      disposeFunctions.push(function () {
+        insertColumnAtCursorSub.remove();
+      });
+
+      var dblClickHdfsItemSub = huePubSub.subscribe("assist.dblClickHdfsItem", function(assistHdfsEntry) {
         if ($el.data("last-active-editor")) {
         if ($el.data("last-active-editor")) {
           editor.session.insert(editor.getCursorPosition(), "'" + assistHdfsEntry.path + "'");
           editor.session.insert(editor.getCursorPosition(), "'" + assistHdfsEntry.path + "'");
         }
         }
       });
       });
 
 
-      huePubSub.subscribe("assist.dblClickGitItem", function(assistGitEntry) {
+      disposeFunctions.push(function () {
+        dblClickHdfsItemSub.remove();
+      });
+
+
+      var dblClickGitItemSub = huePubSub.subscribe("assist.dblClickGitItem", function(assistGitEntry) {
         if ($el.data("last-active-editor")) {
         if ($el.data("last-active-editor")) {
           editor.session.setValue(assistGitEntry.fileContent());
           editor.session.setValue(assistGitEntry.fileContent());
         }
         }
       });
       });
 
 
-      huePubSub.subscribe("assist.dblClickS3Item", function(assistS3Entry) {
+      disposeFunctions.push(function () {
+        dblClickGitItemSub.remove();
+      });
+
+      var dblClickS3ItemSub = huePubSub.subscribe("assist.dblClickS3Item", function(assistS3Entry) {
         if ($el.data("last-active-editor")) {
         if ($el.data("last-active-editor")) {
           editor.session.insert(editor.getCursorPosition(), "'S3A://" + assistS3Entry.path + "'");
           editor.session.insert(editor.getCursorPosition(), "'S3A://" + assistS3Entry.path + "'");
         }
         }
       });
       });
 
 
-      huePubSub.subscribe('sample.error.insert.click', function(popoverEntry) {
+      disposeFunctions.push(function () {
+        dblClickS3ItemSub.remove();
+      });
+
+      var sampleErrorInsertSub = huePubSub.subscribe('sample.error.insert.click', function(popoverEntry) {
           var table = popoverEntry.identifierChain[popoverEntry.identifierChain.length - 1]['name'];
           var table = popoverEntry.identifierChain[popoverEntry.identifierChain.length - 1]['name'];
           var text = "SELECT * FROM " + table + " LIMIT 100";
           var text = "SELECT * FROM " + table + " LIMIT 100";
           editor.session.insert(editor.getCursorPosition(), text);
           editor.session.insert(editor.getCursorPosition(), text);
       });
       });
 
 
+      disposeFunctions.push(function () {
+        sampleErrorInsertSub.remove();
+      });
+
       var $tableDropMenu = $el.next('.table-drop-menu');
       var $tableDropMenu = $el.next('.table-drop-menu');
       var $identifierDropMenu = $tableDropMenu.find('.editor-drop-identifier');
       var $identifierDropMenu = $tableDropMenu.find('.editor-drop-identifier');
 
 
@@ -3940,20 +4057,31 @@
         }, 300);
         }, 300);
       };
       };
 
 
-      $(document).click(function (event) {
+      var documentClickListener = function (event) {
         if ($tableDropMenu.find($(event.target)).length === 0) {
         if ($tableDropMenu.find($(event.target)).length === 0) {
           hideDropMenu();
           hideDropMenu();
         }
         }
+      };
+
+      $(document).on('click', documentClickListener);
+
+      disposeFunctions.push(function () {
+        $(document).off('click', documentClickListener);
       });
       });
 
 
+
       var lastMeta = {};
       var lastMeta = {};
-      huePubSub.subscribe('draggable.text.meta', function (meta) {
+      var draggableTextSub = huePubSub.subscribe('draggable.text.meta', function (meta) {
         lastMeta = meta;
         lastMeta = meta;
         if (typeof meta !== 'undefined' && typeof meta.table !== 'undefined') {
         if (typeof meta !== 'undefined' && typeof meta.table !== 'undefined') {
           $identifierDropMenu.text(meta.table)
           $identifierDropMenu.text(meta.table)
         }
         }
       });
       });
 
 
+      disposeFunctions.push(function () {
+        draggableTextSub.remove();
+      });
+
       var menu = ko.bindingHandlers.contextMenu.initContextMenu($tableDropMenu, $('.content-panel'));
       var menu = ko.bindingHandlers.contextMenu.initContextMenu($tableDropMenu, $('.content-panel'));
 
 
       var setFromDropMenu = function (text) {
       var setFromDropMenu = function (text) {
@@ -3987,22 +4115,17 @@
         setFromDropMenu('DROP TABLE ' + lastMeta.table + ';');
         setFromDropMenu('DROP TABLE ' + lastMeta.table + ';');
       });
       });
 
 
-      var draggableMeta = {};
-      huePubSub.subscribe('draggable.text.meta', function (meta) {
-        draggableMeta = meta;
-      });
-
       $el.droppable({
       $el.droppable({
         accept: ".draggableText",
         accept: ".draggableText",
         drop: function (e, ui) {
         drop: function (e, ui) {
           var position = editor.renderer.screenToTextCoordinates(e.clientX, e.clientY);
           var position = editor.renderer.screenToTextCoordinates(e.clientX, e.clientY);
           var text = ui.helper.text();
           var text = ui.helper.text();
-          if (draggableMeta.type === 's3' || draggableMeta.type === 'hdfs'){
-            text = "'" + draggableMeta.definition.path + "'";
+          if (lastMeta.type === 's3' || lastMeta.type === 'hdfs'){
+            text = "'" + lastMeta.definition.path + "'";
           }
           }
           editor.moveCursorToPosition(position);
           editor.moveCursorToPosition(position);
           var before = editor.getTextBeforeCursor();
           var before = editor.getTextBeforeCursor();
-          if (draggableMeta.table && ! draggableMeta.column && /.*;|^\s*$/.test(before)) {
+          if (lastMeta.table && ! lastMeta.column && /.*;|^\s*$/.test(before)) {
             menu.show(e);
             menu.show(e);
           } else {
           } else {
             if (/\S+$/.test(before) && before.charAt(before.length - 1) !== '.') {
             if (/\S+$/.test(before) && before.charAt(before.length - 1) !== '.') {
@@ -4021,7 +4144,7 @@
 
 
       var autocompleteTemporarilyDisabled = false;
       var autocompleteTemporarilyDisabled = false;
       var autocompleteThrottle = -1;
       var autocompleteThrottle = -1;
-      editor.commands.on("afterExec", function (e) {
+      var afterExecListener = editor.commands.on('afterExec', function (e) {
         if (editor.getOption('enableLiveAutocompletion') && e.command.name === "insertstring") {
         if (editor.getOption('enableLiveAutocompletion') && e.command.name === "insertstring") {
           if (/\S+\(\)$/.test(e.args)) {
           if (/\S+\(\)$/.test(e.args)) {
             editor.moveCursorTo(editor.getCursorPosition().row, editor.getCursorPosition().column - 1);
             editor.moveCursorTo(editor.getCursorPosition().row, editor.getCursorPosition().column - 1);
@@ -4102,6 +4225,9 @@
         }
         }
       });
       });
 
 
+      disposeFunctions.push(function () {
+        editor.commands.off('afterExec', afterExecListener);
+      });
       editor.$blockScrolling = Infinity;
       editor.$blockScrolling = Infinity;
       snippet.ace(editor);
       snippet.ace(editor);
     },
     },

+ 23 - 3
desktop/libs/notebook/src/notebook/templates/hue_ace_autocompleter.mako

@@ -276,6 +276,7 @@ from desktop.views import _ko
 
 
       function HueAceAutocompleter (params, element) {
       function HueAceAutocompleter (params, element) {
         var self = this;
         var self = this;
+        self.disposeFunctions = [];
         self.editor = params.editor;
         self.editor = params.editor;
         self.snippet = params.snippet;
         self.snippet = params.snippet;
 
 
@@ -415,7 +416,7 @@ from desktop.views import _ko
           }, 300);
           }, 300);
         };
         };
 
 
-        huePubSub.subscribe('hue.ace.autocompleter.done', function () {
+        var autocompleterDoneSub = huePubSub.subscribe('hue.ace.autocompleter.done', function () {
           window.setTimeout(function () {
           window.setTimeout(function () {
             if (self.active() && self.suggestions.filtered().length === 0) {
             if (self.active() && self.suggestions.filtered().length === 0) {
               self.detach();
               self.detach();
@@ -423,7 +424,11 @@ from desktop.views import _ko
           }, 0);
           }, 0);
         });
         });
 
 
-        huePubSub.subscribe('hue.ace.autocompleter.show', function (data) {
+        self.disposeFunctions.push(function () {
+          autocompleterDoneSub.remove();
+        });
+
+        var autocompleterShowSub = huePubSub.subscribe('hue.ace.autocompleter.show', function (data) {
           var session = self.editor().getSession();
           var session = self.editor().getSession();
           var pos = self.editor().getCursorPosition();
           var pos = self.editor().getCursorPosition();
           var line = session.getLine(pos.row);
           var line = session.getLine(pos.row);
@@ -442,12 +447,27 @@ from desktop.views import _ko
           self.selectedIndex(0);
           self.selectedIndex(0);
         });
         });
 
 
-        huePubSub.subscribe('hue.ace.autocompleter.hide', function () {
+        self.disposeFunctions.push(function () {
+          autocompleterShowSub.remove();
+        });
+
+        var autocompleterHideSub = huePubSub.subscribe('hue.ace.autocompleter.hide', function () {
           self.detach();
           self.detach();
         });
         });
 
 
+        self.disposeFunctions.push(function () {
+          autocompleterHideSub.remove();
+        });
       }
       }
 
 
+      HueAceAutocompleter.prototype.dispose = function () {
+        var self = this;
+        self.disposeFunctions.forEach(function (disposeFunction) {
+          disposeFunction();
+        })
+        self.detach();
+      };
+
       HueAceAutocompleter.prototype.insertSuggestion = function () {
       HueAceAutocompleter.prototype.insertSuggestion = function () {
         var self = this;
         var self = this;
         if (self.suggestions.filtered().length === 0) {
         if (self.suggestions.filtered().length === 0) {