Modify autocomplete esc behavior
As a component of allowing arbitrary CCs, we must allow for the Esc key
to be pressed to clear autocomplete suggestions. The default behavior of
gr-autocomplete is to emit a 'cancel' event when Esc is pressed.
This change modifies the behavior of the autocomplete to emit 'cancel'
only when suggestions are empty. The new workflow is to tap Esc once to
clear suggestions, and again to emit the cancel event.
Feature: Issue 5832
Change-Id: I53d4f1485c2e6c013a957f09413c149ae219d2e4
diff --git a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
index 46f2ed2..7082000 100644
--- a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
+++ b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
@@ -22,7 +22,6 @@
*
* @event add
*/
-
properties: {
borderless: Boolean,
change: Object,
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index 9ebb794..e55ceb6 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -236,8 +236,11 @@
},
_cancel: function() {
- this._suggestions = [];
- this.fire('cancel');
+ if (this._suggestions.length) {
+ this._suggestions = [];
+ } else {
+ this.fire('cancel');
+ }
},
_updateValue: function(suggestions, index) {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index 4234388..debff60 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -35,14 +35,20 @@
<script>
suite('gr-autocomplete tests', function() {
var element;
+ var sandbox;
setup(function() {
element = fixture('basic');
+ sandbox = sinon.sandbox.create();
+ });
+
+ teardown(function() {
+ sandbox.restore();
});
test('renders', function(done) {
var promise;
- var queryStub = sinon.spy(function(input) {
+ var queryStub = sandbox.spy(function(input) {
return promise = Promise.resolve([
{name: input + ' 0', value: 0},
{name: input + ' 1', value: 1},
@@ -76,9 +82,9 @@
});
});
- test('emits cancel', function(done) {
+ test('esc key behavior', function(done) {
var promise;
- var queryStub = sinon.spy(function() {
+ var queryStub = sandbox.spy(function() {
return promise = Promise.resolve([
{name: 'blah', value: 123},
]);
@@ -93,20 +99,23 @@
promise.then(function() {
assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
- var cancelHandler = sinon.spy();
+ var cancelHandler = sandbox.spy();
element.addEventListener('cancel', cancelHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 27, null, 'esc');
- assert.isTrue(cancelHandler.called);
+ assert.isFalse(cancelHandler.called);
assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
+ assert.equal(element._suggestions.length, 0);
+ MockInteractions.pressAndReleaseKeyOn(element.$.input, 27, null, 'esc');
+ assert.isTrue(cancelHandler.called);
done();
});
});
test('emits commit and handles cursor movement', function(done) {
var promise;
- var queryStub = sinon.spy(function(input) {
+ var queryStub = sandbox.spy(function(input) {
return promise = Promise.resolve([
{name: input + ' 0', value: 0},
{name: input + ' 1', value: 1},
@@ -125,7 +134,7 @@
promise.then(function() {
assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
- var commitHandler = sinon.spy();
+ var commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler);
assert.equal(element.$.cursor.index, 0);
@@ -158,14 +167,14 @@
test('clear-on-commit behavior (off)', function(done) {
var promise;
- var queryStub = sinon.spy(function() {
+ var queryStub = sandbox.spy(function() {
return promise = Promise.resolve([{name: 'suggestion', value: 0}]);
});
element.query = queryStub;
element.text = 'blah';
promise.then(function() {
- var commitHandler = sinon.spy();
+ var commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
@@ -179,7 +188,7 @@
test('clear-on-commit behavior (on)', function(done) {
var promise;
- var queryStub = sinon.spy(function() {
+ var queryStub = sandbox.spy(function() {
return promise = Promise.resolve([{name: 'suggestion', value: 0}]);
});
element.query = queryStub;
@@ -187,7 +196,7 @@
element.clearOnCommit = true;
promise.then(function() {
- var commitHandler = sinon.spy();
+ var commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
@@ -200,7 +209,7 @@
});
test('threshold guards the query', function() {
- var queryStub = sinon.spy(function() {
+ var queryStub = sandbox.spy(function() {
return Promise.resolve([]);
});
element.query = queryStub;
@@ -223,7 +232,7 @@
});
test('undefined or empty text results in no suggestions', function() {
- sinon.spy(element, '_updateSuggestions');
+ sandbox.spy(element, '_updateSuggestions');
element.text = undefined;
assert(element._updateSuggestions.calledOnce);
assert.equal(element._suggestions.length, 0);
@@ -231,14 +240,14 @@
test('multi completes only the last part of the query', function(done) {
var promise;
- var queryStub = sinon.stub()
+ var queryStub = sandbox.stub()
.returns(promise = Promise.resolve([{name: 'suggestion', value: 0}]));
element.query = queryStub;
element.text = 'blah blah';
element.multi = true;
promise.then(function() {
- var commitHandler = sinon.spy();
+ var commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
@@ -251,18 +260,17 @@
});
test('tab key completes only when suggestions exist', function() {
- var commitStub = sinon.stub(element, '_commit');
+ var commitStub = sandbox.stub(element, '_commit');
element._suggestions = [];
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
assert.isFalse(commitStub.called);
element._suggestions = ['tunnel snakes rule!'];
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
assert.isTrue(commitStub.called);
- commitStub.restore();
});
test('tabCompleteWithoutCommit flag functions', function() {
- var commitHandler = sinon.spy();
+ var commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler);
element._suggestions = ['tunnel snakes rule!'];
element.tabCompleteWithoutCommit = true;
@@ -291,8 +299,8 @@
});
test('tap on suggestion commits and refocuses on input', function() {
- var focusSpy = sinon.spy(element, 'focus');
- var commitSpy = sinon.spy(element, '_commit');
+ var focusSpy = sandbox.spy(element, 'focus');
+ var commitSpy = sandbox.spy(element, '_commit');
element._focused = true;
element._suggestions = [{name: 'first suggestion'}];
assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
@@ -302,12 +310,10 @@
assert.isTrue(commitSpy.called);
assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
assert.isTrue(element._focused);
- focusSpy.restore();
- commitSpy.restore();
});
test('input-keydown event fired', function() {
- var listener = sinon.spy();
+ var listener = sandbox.spy();
element.addEventListener('input-keydown', listener);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
flushAsynchronousOperations();