Fix bug where ESC was closing the Console autocompletion suggestions menu, but then also exiting edit mode. (#16500)

This commit is contained in:
CJ Cenizal 2018-02-02 16:01:40 -08:00 committed by GitHub
parent 090866c514
commit e5a10edb38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 53 deletions

View file

@ -409,7 +409,7 @@ var SnippetManager = function() {
return; return;
var value = tokens.slice(i + 1, i1); var value = tokens.slice(i + 1, i1);
var isNested = value.some(function(t) {return typeof t === "object"}); var isNested = value.some(function(t) {return typeof t === "object"});
if (isNested && !ts.value) { if (isNested && !ts.value) {
ts.value = value; ts.value = value;
} else if (value.length && (!ts.value || typeof ts.value !== "string")) { } else if (value.length && (!ts.value || typeof ts.value !== "string")) {
@ -438,11 +438,11 @@ var SnippetManager = function() {
continue; continue;
var id = p.tabstopId; var id = p.tabstopId;
var i1 = tokens.indexOf(p, i + 1); var i1 = tokens.indexOf(p, i + 1);
if (expanding[id] == p) { if (expanding[id] == p) {
expanding[id] = null; expanding[id] = null;
continue; continue;
} }
var ts = tabstops[id]; var ts = tabstops[id];
var arg = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); var arg = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value);
arg.unshift(i + 1, Math.max(0, i1 - i)); arg.unshift(i + 1, Math.max(0, i1 - i));
@ -482,7 +482,7 @@ var SnippetManager = function() {
var scope = editor.session.$mode.$id || ""; var scope = editor.session.$mode.$id || "";
scope = scope.split("/").pop(); scope = scope.split("/").pop();
if (scope === "html" || scope === "php") { if (scope === "html" || scope === "php") {
if (scope === "php") if (scope === "php")
scope = "html"; scope = "html";
var c = editor.getCursorPosition() var c = editor.getCursorPosition()
var state = editor.session.getState(c.row); var state = editor.session.getState(c.row);
@ -498,7 +498,7 @@ var SnippetManager = function() {
scope = "php"; scope = "php";
} }
} }
return scope; return scope;
}; };
@ -834,9 +834,9 @@ var TabstopManager = function(editor) {
ts = this.tabstops[this.index]; ts = this.tabstops[this.index];
if (!ts || !ts.length) if (!ts || !ts.length)
return; return;
this.selectedTabstop = ts; this.selectedTabstop = ts;
if (!this.editor.inVirtualSelectionMode) { if (!this.editor.inVirtualSelectionMode) {
var sel = this.editor.multiSelect; var sel = this.editor.multiSelect;
sel.toSingleRange(ts.firstNonLinked.clone()); sel.toSingleRange(ts.firstNonLinked.clone());
for (var i = ts.length; i--;) { for (var i = ts.length; i--;) {
@ -847,7 +847,7 @@ var TabstopManager = function(editor) {
} else { } else {
this.editor.selection.setRange(ts.firstNonLinked); this.editor.selection.setRange(ts.firstNonLinked);
} }
this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler);
}; };
this.addTabstops = function(tabstops, start, end) { this.addTabstops = function(tabstops, start, end) {
@ -978,7 +978,7 @@ var Autocomplete = function() {
this.changeListener = this.changeListener.bind(this); this.changeListener = this.changeListener.bind(this);
this.mousedownListener = this.mousedownListener.bind(this); this.mousedownListener = this.mousedownListener.bind(this);
this.mousewheelListener = this.mousewheelListener.bind(this); this.mousewheelListener = this.mousewheelListener.bind(this);
this.changeTimer = lang.delayedCall(function() { this.changeTimer = lang.delayedCall(function() {
this.updateCompletions(true); this.updateCompletions(true);
}.bind(this)) }.bind(this))
@ -1005,10 +1005,10 @@ var Autocomplete = function() {
this.popup.setFontSize(editor.getFontSize()); this.popup.setFontSize(editor.getFontSize());
var lineHeight = renderer.layerConfig.lineHeight; var lineHeight = renderer.layerConfig.lineHeight;
var pos = renderer.$cursorLayer.getPixelPosition(this.base, true); var pos = renderer.$cursorLayer.getPixelPosition(this.base, true);
pos.left -= this.popup.getTextLeftOffset(); pos.left -= this.popup.getTextLeftOffset();
var rect = editor.container.getBoundingClientRect(); var rect = editor.container.getBoundingClientRect();
pos.top += rect.top - renderer.layerConfig.offset; pos.top += rect.top - renderer.layerConfig.offset;
pos.left += rect.left - editor.renderer.scrollLeft; pos.left += rect.left - editor.renderer.scrollLeft;
@ -1025,7 +1025,7 @@ var Autocomplete = function() {
this.editor.off("mousedown", this.mousedownListener); this.editor.off("mousedown", this.mousedownListener);
this.editor.off("mousewheel", this.mousewheelListener); this.editor.off("mousewheel", this.mousewheelListener);
this.changeTimer.cancel(); this.changeTimer.cancel();
if (this.popup) if (this.popup)
this.popup.hide(); this.popup.hide();
@ -1113,10 +1113,10 @@ var Autocomplete = function() {
this.gatherCompletions = function(editor, callback) { this.gatherCompletions = function(editor, callback) {
var session = editor.getSession(); var session = editor.getSession();
var pos = editor.getCursorPosition(); var pos = editor.getCursorPosition();
var line = session.getLine(pos.row); var line = session.getLine(pos.row);
var prefix = util.retrievePrecedingIdentifier(line, pos.column); var prefix = util.retrievePrecedingIdentifier(line, pos.column);
this.base = editor.getCursorPosition(); this.base = editor.getCursorPosition();
this.base.column -= prefix.length; this.base.column -= prefix.length;
@ -1139,7 +1139,7 @@ var Autocomplete = function() {
this.showPopup = function(editor) { this.showPopup = function(editor) {
if (this.editor) if (this.editor)
this.detach(); this.detach();
this.activated = true; this.activated = true;
this.editor = editor; this.editor = editor;
@ -1154,10 +1154,10 @@ var Autocomplete = function() {
editor.on("blur", this.blurListener); editor.on("blur", this.blurListener);
editor.on("mousedown", this.mousedownListener); editor.on("mousedown", this.mousedownListener);
editor.on("mousewheel", this.mousewheelListener); editor.on("mousewheel", this.mousewheelListener);
this.updateCompletions(); this.updateCompletions();
}; };
this.updateCompletions = function(keepPopupPosition) { this.updateCompletions = function(keepPopupPosition) {
if (keepPopupPosition && this.base && this.completions) { if (keepPopupPosition && this.base && this.completions) {
var pos = this.editor.getCursorPosition(); var pos = this.editor.getCursorPosition();
@ -1228,12 +1228,12 @@ var FilteredList = function(array, filterText, mutateData) {
}); });
var prev = null; var prev = null;
matches = matches.filter(function(item){ matches = matches.filter(function(item){
var caption = item.value || item.caption || item.snippet; var caption = item.value || item.caption || item.snippet;
if (caption === prev) return false; if (caption === prev) return false;
prev = caption; prev = caption;
return true; return true;
}); });
this.filtered = matches; this.filtered = matches;
}; };
this.filterCompletions = function(items, needle) { this.filterCompletions = function(items, needle) {
@ -1291,7 +1291,7 @@ var $singleLineEditor = function(el) {
var renderer = new Renderer(el); var renderer = new Renderer(el);
renderer.$maxLines = 4; renderer.$maxLines = 4;
var editor = new Editor(renderer); var editor = new Editor(renderer);
editor.setHighlightActiveLine(false); editor.setHighlightActiveLine(false);
@ -1307,13 +1307,13 @@ var $singleLineEditor = function(el) {
var AcePopup = function(parentNode) { var AcePopup = function(parentNode) {
var el = dom.createElement("div"); var el = dom.createElement("div");
var popup = new $singleLineEditor(el); var popup = new $singleLineEditor(el);
if (parentNode) if (parentNode)
parentNode.appendChild(el); parentNode.appendChild(el);
el.style.display = "none"; el.style.display = "none";
popup.renderer.content.style.cursor = "default"; popup.renderer.content.style.cursor = "default";
popup.renderer.setStyle("ace_autocomplete"); popup.renderer.setStyle("ace_autocomplete");
popup.setOption("displayIndentGuides", false); popup.setOption("displayIndentGuides", false);
var noop = function(){}; var noop = function(){};
@ -1402,11 +1402,11 @@ var AcePopup = function(parentNode) {
popup.getHoveredRow = function() { popup.getHoveredRow = function() {
return hoverMarker.start.row; return hoverMarker.start.row;
}; };
event.addListener(popup.container, "mouseout", hideHoverMarker); event.addListener(popup.container, "mouseout", hideHoverMarker);
popup.on("hide", hideHoverMarker); popup.on("hide", hideHoverMarker);
popup.on("changeSelection", hideHoverMarker); popup.on("changeSelection", hideHoverMarker);
popup.session.doc.getLength = function() { popup.session.doc.getLength = function() {
return popup.data.length; return popup.data.length;
}; };
@ -1450,13 +1450,13 @@ var AcePopup = function(parentNode) {
}; };
bgTokenizer.$updateOnChange = noop; bgTokenizer.$updateOnChange = noop;
bgTokenizer.start = noop; bgTokenizer.start = noop;
popup.session.$computeWidth = function() { popup.session.$computeWidth = function() {
return this.screenWidth = 0; return this.screenWidth = 0;
} }
popup.isOpen = false; popup.isOpen = false;
popup.isTopdown = false; popup.isTopdown = false;
popup.data = []; popup.data = [];
popup.setData = function(list) { popup.setData = function(list) {
popup.data = list || []; popup.data = list || [];
@ -1481,7 +1481,7 @@ var AcePopup = function(parentNode) {
popup._signal("select"); popup._signal("select");
} }
}; };
popup.on("changeSelection", function() { popup.on("changeSelection", function() {
if (popup.isOpen) if (popup.isOpen)
popup.setRow(popup.selection.lead.row); popup.setRow(popup.selection.lead.row);
@ -1512,22 +1512,22 @@ var AcePopup = function(parentNode) {
el.style.display = ""; el.style.display = "";
this.renderer.$textLayer.checkForSizeChanges(); this.renderer.$textLayer.checkForSizeChanges();
var left = pos.left; var left = pos.left;
if (left + el.offsetWidth > screenWidth) if (left + el.offsetWidth > screenWidth)
left = screenWidth - el.offsetWidth; left = screenWidth - el.offsetWidth;
el.style.left = left + "px"; el.style.left = left + "px";
this._signal("show"); this._signal("show");
lastMouseEvent = null; lastMouseEvent = null;
popup.isOpen = true; popup.isOpen = true;
}; };
popup.getTextLeftOffset = function() { popup.getTextLeftOffset = function() {
return this.$borderSize + this.renderer.$padding + this.$imageSize; return this.$borderSize + this.renderer.$padding + this.$imageSize;
}; };
popup.$imageSize = 0; popup.$imageSize = 0;
popup.$borderSize = 1; popup.$borderSize = 1;
@ -1622,7 +1622,7 @@ exports.retrieveFollowingIdentifier = function(text, pos, regex) {
consoleAce.define('ace/autocomplete/text_completer', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { consoleAce.define('ace/autocomplete/text_completer', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) {
var Range = require("ace/range").Range; var Range = require("ace/range").Range;
var splitRegex = /[^a-zA-Z_0-9\$\-]+/; var splitRegex = /[^a-zA-Z_0-9\$\-]+/;
function getWordIndex(doc, pos) { function getWordIndex(doc, pos) {
@ -1633,7 +1633,7 @@ consoleAce.define('ace/autocomplete/text_completer', ['require', 'exports', 'mod
var prefixPos = getWordIndex(doc, pos); var prefixPos = getWordIndex(doc, pos);
var words = doc.getValue().split(splitRegex); var words = doc.getValue().split(splitRegex);
var wordScores = Object.create(null); var wordScores = Object.create(null);
var currentWord = words[prefixPos]; var currentWord = words[prefixPos];
words.forEach(function(word, idx) { words.forEach(function(word, idx) {

View file

@ -26,24 +26,24 @@ uiModules.get('kibana')
const hint = angular.element( const hint = angular.element(
`<div `<div
class="uiAceKeyboardHint" class="uiAceKeyboardHint"
id="${uniqueId}" id="${uniqueId}"
tabindex="0" tabindex="0"
role="application" role="application"
> >
<p class="kuiText kuiVerticalRhythmSmall"> <p class="kuiText kuiVerticalRhythmSmall">
Press Enter to start editing. Press Enter to start editing.
</p> </p>
<p class="kuiText kuiVerticalRhythmSmall"> <p class="kuiText kuiVerticalRhythmSmall">
When you&rsquo;re done, press Escape to stop editing. When you&rsquo;re done, press Escape to stop editing.
</p> </p>
</div> </div>`
`); );
const uiAceTextbox = element.find('textarea'); const uiAceTextbox = element.find('textarea');
function startEditing() { function startEditing() {
// We are not using ng-class in the element, so that we won't need to $compile it // We are not using ng-class in the element, so that we won't need to $compile it
hint.addClass('uiAceKeyboardHint-isInactive'); hint.addClass('uiAceKeyboardHint-isInactive');
uiAceTextbox.focus(); uiAceTextbox.focus();
} }
@ -63,12 +63,32 @@ uiModules.get('kibana')
enableOverlay(); enableOverlay();
}); });
let isAutoCompleterOpen;
// We have to capture this event on the 'capture' phase, otherewise Ace will have already
// dismissed the autocompleter when the user hits ESC.
document.addEventListener('keydown', () => {
const autoCompleter = document.querySelector('.ace_autocomplete');
if (!autoCompleter) {
isAutoCompleterOpen = false;
return;
}
// The autoComplete is just hidden when it's closed, not removed from the DOM.
isAutoCompleterOpen = autoCompleter.style.display !== 'none';
}, { capture: true });
uiAceTextbox.keydown((ev) => { uiAceTextbox.keydown((ev) => {
if (ev.keyCode === keyCodes.ESCAPE) { if (ev.keyCode === keyCodes.ESCAPE) {
ev.preventDefault(); // If the autocompletion context menu is open then we want to let ESC close it but
ev.stopPropagation(); // **not** exit out of editing mode.
enableOverlay(); if (!isAutoCompleterOpen) {
hint.focus(); ev.preventDefault();
ev.stopPropagation();
enableOverlay();
hint.focus();
}
} }
}); });