diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js index 7aca0c6c9..b1b19b248 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js @@ -153,7 +153,7 @@ RED.editor.codeEditor.monaco = (function() { //@see https://github.com/microsoft/monaco-editor/issues/2382 //This is fixed in commit microsoft/vscode@49cad9a however it is not yet present monaco-editor //Remove the below addEventListener once monaco-editor V0.23.1 or greater is published - window.addEventListener('unhandledrejection', (evt) => { + window.addEventListener('unhandledrejection', function(evt) { if(evt && evt.reason && evt.reason.stack) { if (evt.reason.name === 'Canceled' && evt.reason.stack.indexOf('vendor/monaco/dist') >= 0) { evt.preventDefault(); @@ -681,8 +681,7 @@ RED.editor.codeEditor.monaco = (function() { var editorSettings = RED.editor.codeEditor.settings || {}; var loadedLibs = {JS:{}, TS:{}};//for tracking and later disposing of loaded type libs - - + var watchTimer, elVisible, elVisibleMem; var createThemeMenuOption = function (theme, keybinding) { return { // An unique identifier of the contributed action. @@ -883,7 +882,7 @@ RED.editor.codeEditor.monaco = (function() { } Object.values(loadExtraModules).forEach(function(m) { _loadModuleDTS(m, false, loadedLibs, function(err, extraLib) { - loadList = loadList.filter(e => e.module != extraLib.module ); + loadList = loadList.filter(function(e) {return e.module != extraLib.module} ); if(loadList.length == 0) { var _imports = imports.join(""); var _defs = "\ndeclare global {\n" + defs.join("") + "\n}"; @@ -931,14 +930,21 @@ RED.editor.codeEditor.monaco = (function() { var newModel if (oldModel) { + var oldScrollTop = ed.getScrollTop(); + var oldScrollLeft = ed.getScrollLeft(); + var oldSelections = ed.getSelections(); + var oldPosition = ed.getPosition(); oldValue = oldModel.getValue() || ""; newModel = monaco.editor.createModel((oldValue || ""), mode); ed.setModel(newModel); oldModel.dispose(); + ed.setScrollTop(oldScrollTop, 1/* immediate */); + ed.setScrollLeft(oldScrollLeft, 1/* immediate */); + ed.setPosition(oldPosition); + ed.setSelections(oldSelections); } else { newModel = monaco.editor.createModel((oldValue || ""), mode); ed.setModel(newModel); - oldModel.dispose(); } if (cb && typeof cb == "function") { cb(); @@ -996,6 +1002,7 @@ RED.editor.codeEditor.monaco = (function() { } ed.destroy = function destroy() { + if(watchTimer) { clearInterval(watchTimer); } try { //dispose serverside addExtraLib disposible we added - this is the only way (https://github.com/microsoft/monaco-editor/issues/1002#issuecomment-564123586) if(Object.keys(loadedLibs.JS).length) { @@ -1024,6 +1031,8 @@ RED.editor.codeEditor.monaco = (function() { } } catch (error) { } try { + var m = this.getModel(); + m.dispose(); this.setModel(null); } catch (e) { } @@ -1171,6 +1180,80 @@ RED.editor.codeEditor.monaco = (function() { } ed._mode = editorOptions.language; + //as models are signleton, consts and let are avialable to other javascript instances + //so when not focused, set editor mode to text temporarily to avoid multiple defs + ed.onDidBlurEditorWidget(function() { + if(isVisible(el) == false) { + if(ed._mode == "javascript") { + ed.setMode('text'); + ed._tempMode = "text"; + } + } + }); + + ed.onDidFocusEditorWidget(function() { + if(ed._mode == "javascript" && ed._tempMode == "text") { + ed._tempMode = ""; + setTimeout(function() { + ed.setMode('javascript'); + }, 5); + } + }); + + watchVisibility(el, function(visible, element) { + if(visible) { + if(ed._mode == "javascript" && ed._tempMode == "text") { + ed._tempMode = ""; + setTimeout(function() { + ed.setMode('javascript'); + }, 5); + } + } else { + if(ed._mode == "javascript") { + ed.setMode('text'); + ed._tempMode = "text"; + } + } + }); + + function watchVisibility(element, callback) { + try { + var options = { + root: $(element).closest("div.red-ui-tray-content")[0] || document, + attributes: true, + childList: true, + }; + var observer = new IntersectionObserver(function(entries, observer) { + entries.forEach(function(entry) { + callback(entry.intersectionRatio > 0, entry); + }); + }, options); + observer.observe(element); + } catch (e1) { + //browser not supporting IntersectionObserver? + //fall back to polling + try { + watchTimer = setInterval(function() { + elVisible = isVisible(el); + if(elVisible != elVisibleMem) { + callback(elVisible, element); + } + elVisible = elVisibleMem; + }, 200); + } catch (e2) { } + } + + } + + //by default, set javascript editors to text mode. + //when elemt becomes visible, it will be (re) set to javascript mode + //this is to ensure multiple editors sharing the model dont presnet its + //consts & lets to each other + if(ed._mode == "javascript") { + ed.setMode('text'); + ed._tempMode = "text"; + } + if (editorOptions.language === 'markdown') { $(el).addClass("red-ui-editor-text-container-toolbar"); ed.toolbar = RED.editor.customEditTypes['_markdown'].buildToolbar(toolbarRow, ed); @@ -1209,6 +1292,12 @@ RED.editor.codeEditor.monaco = (function() { return ed; } + function isVisible(el) { + if(!el.offsetHeight && !el.offsetWidth) { return false; } + if(getComputedStyle(el).visibility === 'hidden') { return false; } + return true; + } + return { /** * Editor type