Confirm a share also by pressing enter on the input field

Besides confirming a share by clicking on the confirm button now it is
possible to do it by pressing enter on the input field.

Clicking on the confirm button implicitly hides the autocomplete
dropdown. On the other hand, pressing enter on the input field does not,
so the autocompletion must be disabled and closed when the confirmation
begins and then enabled again once it finishes. Otherwise the
autocomplete dropdown would be visible and it would be possible to
interact with it while the share is being confirmed.

The order in which the input field and the autompletion are disabled is
important. Internally, the autocompletion sets a timeout when the input
field is modified that requests the suggestions to the server and then
shows them in the dropdown. That timeout is not cancelled when the
autocompletion is disabled, but when the input field loses its focus and
the autocompletion is not disabled. Therefore, the input field has to be
disabled (which causes it to lose the focus) before the autocompletion
is disabled. Otherwise it could happen that while a share is being
confirmed the timeout ends, so an autocompletion request is sent and
then, once the share is successfully confirmed and thus the
autocompletion is enabled again, the request is received and the
autocomplete dropdown is shown with the old suggestions. Strange, but
possible nevertheless ;-)

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This commit is contained in:
Daniel Calviño Sánchez 2018-03-20 12:02:49 +01:00
parent 9371b61c4d
commit 10a4f8e45e
2 changed files with 47 additions and 0 deletions

View File

@ -415,6 +415,10 @@
_onSelectRecipient: function(e, s) { _onSelectRecipient: function(e, s) {
e.preventDefault(); e.preventDefault();
// Ensure that the keydown handler for the input field is not
// called; otherwise it would try to add the recipient again, which
// would fail.
e.stopImmediatePropagation();
$(e.target).attr('disabled', true) $(e.target).attr('disabled', true)
.val(s.item.label); .val(s.item.label);
var $loading = this.$el.find('.shareWithLoading'); var $loading = this.$el.find('.shareWithLoading');
@ -451,6 +455,15 @@
$shareWithField.prop('disabled', true); $shareWithField.prop('disabled', true);
// Disabling the autocompletion does not clear its search timeout;
// removing the focus from the input field does, but only if the
// autocompletion is not disabled when the field loses the focus.
// Thus, the field has to be disabled before disabling the
// autocompletion to prevent an old pending search result from
// appearing once the field is enabled again.
$shareWithField.autocomplete('close');
$shareWithField.autocomplete('disable');
var perPage = 200; var perPage = 200;
var onlyExactMatches = true; var onlyExactMatches = true;
this._getSuggestions( this._getSuggestions(
@ -467,6 +480,8 @@
$shareWithField.prop('disabled', false); $shareWithField.prop('disabled', false);
$shareWithField.focus(); $shareWithField.focus();
$shareWithField.autocomplete('enable');
// There is no need to show an error message here; it will // There is no need to show an error message here; it will
// be automatically shown when the autocomplete is activated // be automatically shown when the autocomplete is activated
// again (due to the focus on the field) and it finds no // again (due to the focus on the field) and it finds no
@ -483,6 +498,8 @@
$shareWithField.prop('disabled', false); $shareWithField.prop('disabled', false);
$shareWithField.focus(); $shareWithField.focus();
$shareWithField.autocomplete('enable');
return; return;
} }
@ -494,6 +511,8 @@
$shareWithField.val(''); $shareWithField.val('');
$shareWithField.prop('disabled', false); $shareWithField.prop('disabled', false);
$shareWithField.focus(); $shareWithField.focus();
$shareWithField.autocomplete('enable');
}; };
var actionError = function(obj, msg) { var actionError = function(obj, msg) {
@ -504,6 +523,8 @@
$shareWithField.prop('disabled', false); $shareWithField.prop('disabled', false);
$shareWithField.focus(); $shareWithField.focus();
$shareWithField.autocomplete('enable');
OC.Notification.showTemporary(msg); OC.Notification.showTemporary(msg);
}; };
@ -519,6 +540,8 @@
$shareWithField.prop('disabled', false); $shareWithField.prop('disabled', false);
$shareWithField.focus(); $shareWithField.focus();
$shareWithField.autocomplete('enable');
// There is no need to show an error message here; it will be // There is no need to show an error message here; it will be
// automatically shown when the autocomplete is activated again // automatically shown when the autocomplete is activated again
// (due to the focus on the field) and getting the suggestions // (due to the focus on the field) and getting the suggestions
@ -554,6 +577,7 @@
}, },
render: function() { render: function() {
var self = this;
var baseTemplate = this._getTemplate('base', TEMPLATE_BASE); var baseTemplate = this._getTemplate('base', TEMPLATE_BASE);
this.$el.html(baseTemplate({ this.$el.html(baseTemplate({
@ -565,6 +589,16 @@
var $shareField = this.$el.find('.shareWithField'); var $shareField = this.$el.find('.shareWithField');
if ($shareField.length) { if ($shareField.length) {
var shareFieldKeydownHandler = function(event) {
if (event.keyCode !== 13) {
return true;
}
self._confirmShare();
return false;
};
$shareField.autocomplete({ $shareField.autocomplete({
minLength: 1, minLength: 1,
delay: 750, delay: 750,
@ -574,6 +608,8 @@
source: this.autocompleteHandler, source: this.autocompleteHandler,
select: this._onSelectRecipient select: this._onSelectRecipient
}).data('ui-autocomplete')._renderItem = this.autocompleteRenderItem; }).data('ui-autocomplete')._renderItem = this.autocompleteRenderItem;
$shareField.on('keydown', null, shareFieldKeydownHandler);
} }
this.resharerInfoView.$el = this.$el.find('.resharerInfoView'); this.resharerInfoView.$el = this.$el.find('.resharerInfoView');

View File

@ -1872,6 +1872,8 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(false);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(true);
expect(autocompleteStub.lastCall.args[0]).toEqual('disable');
expect(autocompleteStub.calledWith('close')).toEqual(true);
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');
}); });
@ -1918,6 +1920,7 @@ describe('OC.Share.ShareDialogView', function() {
// Ensure that the UI is not restored before adding the share // Ensure that the UI is not restored before adding the share
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(false);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(true);
expect(autocompleteStub.lastCall.args[0]).toEqual('disable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');
@ -1933,6 +1936,7 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false);
expect(autocompleteStub.lastCall.args[0]).toEqual('enable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false);
expect(dialog.$el.find('.shareWithField').val()).toEqual(''); expect(dialog.$el.find('.shareWithField').val()).toEqual('');
}); });
@ -1981,6 +1985,7 @@ describe('OC.Share.ShareDialogView', function() {
// Ensure that the UI is not restored before adding the share // Ensure that the UI is not restored before adding the share
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(false);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(true);
expect(autocompleteStub.lastCall.args[0]).toEqual('disable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');
@ -1996,6 +2001,7 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false);
expect(autocompleteStub.lastCall.args[0]).toEqual('enable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');
@ -2037,6 +2043,7 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false);
expect(autocompleteStub.lastCall.args[0]).toEqual('enable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');
@ -2088,6 +2095,7 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false);
expect(autocompleteStub.lastCall.args[0]).toEqual('enable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bo'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bo');
}); });
@ -2143,6 +2151,7 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false);
expect(autocompleteStub.lastCall.args[0]).toEqual('enable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');
}); });
@ -2171,6 +2180,7 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false);
expect(autocompleteStub.lastCall.args[0]).toEqual('enable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');
@ -2188,6 +2198,7 @@ describe('OC.Share.ShareDialogView', function() {
expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true); expect(dialog.$el.find('.shareWithLoading').hasClass('hidden')).toEqual(true);
expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false); expect(dialog.$el.find('.shareWithConfirm').hasClass('hidden')).toEqual(false);
expect(autocompleteStub.lastCall.args[0]).toEqual('enable');
expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false); expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(false);
expect(dialog.$el.find('.shareWithField').val()).toEqual('bob'); expect(dialog.$el.find('.shareWithField').val()).toEqual('bob');