diff --git a/public/app/core/components/code_editor/code_editor.ts b/public/app/core/components/code_editor/code_editor.ts index 708df27b942..989c353cdf5 100644 --- a/public/app/core/components/code_editor/code_editor.ts +++ b/public/app/core/components/code_editor/code_editor.ts @@ -3,13 +3,22 @@ * https://github.com/ajaxorg/ace * * Basic usage: - * + * + * + * + * Params: + * content: Editor content. + * onChange: Function called on content change (invoked on editor blur, ctrl+enter, not on every change). * * Some Ace editor options available via data-* attributes: * data-lang-mode - Language mode (text, sql, javascript, etc.). Default is 'text'. * data-theme - Editor theme (eg 'solarized_dark'). * data-max-lines - Max editor height in lines. Editor grows automatically from 1 to maxLines. * data-show-gutter - Show gutter (contains line numbers and additional info). + * + * Keybindings: + * Ctrl-Enter (Command-Enter): run onChange() function */ /// @@ -65,15 +74,14 @@ function link(scope, elem, attrs) { codeEditor.renderer.setPadding(10); setThemeMode(theme); setLangMode(langMode); - - codeEditor.setValue(scope.content); - codeEditor.clearSelection(); + setEditorContent(scope.content); // Add classes elem.addClass("gf-code-editor"); let textarea = elem.find("textarea"); textarea.addClass('gf-form-input'); + // Event handlers editorSession.on('change', (e) => { scope.$apply(() => { let newValue = codeEditor.getValue(); @@ -81,6 +89,29 @@ function link(scope, elem, attrs) { }); }); + // Sync with outer scope - update editor content if model has been changed from outside of directive. + scope.$watch('content', (newValue, oldValue) => { + let editorValue = codeEditor.getValue(); + if (newValue !== editorValue && newValue !== oldValue) { + scope.$$postDigest(function() { + setEditorContent(newValue); + }); + } + }); + + codeEditor.on('blur', () => { + scope.onChange(); + }); + + // Keybindings + codeEditor.commands.addCommand({ + name: 'executeQuery', + bindKey: {win: 'Ctrl-Enter', mac: 'Command-Enter'}, + exec: () => { + scope.onChange(); + } + }); + function setLangMode(lang) { let aceModeName = `ace/mode/${lang}`; fixModuleUrl("mode", lang); @@ -100,6 +131,11 @@ function link(scope, elem, attrs) { let aceThemeName = `ace/theme/${theme}`; codeEditor.setTheme(aceThemeName); } + + function setEditorContent(value) { + codeEditor.setValue(value); + codeEditor.clearSelection(); + } } export function codeEditorDirective() { @@ -107,7 +143,8 @@ export function codeEditorDirective() { restrict: 'E', template: editorTemplate, scope: { - content: "=" + content: "=", + onChange: "&" }, link: link };