[FIX] search view: autocomplete: further improve support for rapid barcode scanning

This patch removes the asynchronous code that was
still used to open the autocompletion drawer.
Even with the setTimeout delay forced to 0, the
asynchronous handling meant the final ENTER
keyUp event could be processed before the opening
of the autocompletion drawer related to the last
key pressed. This would trigger the search with
the search string of the previous autocompletion
popup, missing the last few keys.

Also handle ENTER at keyDown, because in some
rare cases a barcode scanner may emit only
the keyDown event for ENTER, without the
corresponding keyUp, causing a merge of two
successive scanned barcodes.

Based on many tests conducted with different
barcode scanners, the only thing that
is guaranteed is the correct order of the keyPress
events for all regular characters, and the
fact that the ENTER keyDown and/or keyUp will
always be sent after them.

All other events can be mixed or simply missing
if you make a rapid succession of scans, especially
if done with a long series of barcodes.

Scanners tested (with 1ms data transmission delay):
 - Honeywell Eclipse MS5145
 - Dacomex Slim 50mm CCD scanner
This commit is contained in:
Olivier Dony 2015-03-11 17:42:54 +01:00
parent db45099a27
commit df4bd736f1
1 changed files with 10 additions and 14 deletions

View File

@ -490,7 +490,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
this.autocomplete = new instance.web.search.AutoComplete(this, {
source: this.proxy('complete_global_search'),
select: this.proxy('select_completion'),
delay: 0,
get_search_string: function () {
return self.$('div.oe_searchview_input').text();
},
@ -2337,8 +2336,6 @@ instance.web.search.AutoComplete = instance.web.Widget.extend({
// options.source: function ({term:query}, callback). This function will be called to
// obtain the search results corresponding to the query string. It is assumed that
// options.source will call callback with the results.
// options.delay: delay in millisecond before calling source. Useful if you don't want
// to make too many rpc calls
// options.select: function (ev, {item: {facet:facet}}). Autocomplete widget will call
// that function when a selection is made by the user
// options.get_search_string: function (). This function will be called by autocomplete
@ -2347,15 +2344,14 @@ instance.web.search.AutoComplete = instance.web.Widget.extend({
this._super(parent);
this.$input = parent.$el;
this.source = options.source;
this.delay = options.delay;
this.select = options.select,
this.select = options.select;
this.get_search_string = options.get_search_string;
this.width = options.width || 400;
this.current_result = null;
this.searching = true;
this.search_string = null;
this.search_string = '';
this.current_search = null;
},
start: function () {
@ -2367,10 +2363,8 @@ instance.web.search.AutoComplete = instance.web.Widget.extend({
ev.preventDefault();
return;
}
// ENTER is caugth at KeyUp rather than KeyDown to avoid firing
// before all regular keystrokes have been processed
if (ev.which === $.ui.keyCode.ENTER) {
if (self.current_result && self.get_search_string().length) {
if (self.search_string.length) {
self.select_item(ev);
}
return;
@ -2379,29 +2373,31 @@ instance.web.search.AutoComplete = instance.web.Widget.extend({
if (self.search_string !== search_string) {
if (search_string.length) {
self.search_string = search_string;
setTimeout(function () { self.initiate_search(search_string);}, self.delay);
self.initiate_search(search_string);
} else {
self.close();
}
}
});
this.$input.on('keypress', function (ev) {
self.search_string = self.get_search_string() + String.fromCharCode(ev.which);
self.search_string = self.search_string + String.fromCharCode(ev.which);
if (self.search_string.length) {
self.searching = true;
var search_string = self.search_string;
setTimeout(function () { self.initiate_search(search_string);}, self.delay);
self.initiate_search(search_string);
} else {
self.close();
}
});
this.$input.on('keydown', function (ev) {
switch (ev.which) {
case $.ui.keyCode.ENTER:
// TAB and direction keys are handled at KeyDown because KeyUp
// is not guaranteed to fire.
// See e.g. https://github.com/aef-/jquery.masterblaster/issues/13
case $.ui.keyCode.TAB:
if (self.current_result && self.get_search_string().length) {
if (self.search_string.length) {
self.select_item(ev);
}
break;
@ -2532,7 +2528,7 @@ instance.web.search.AutoComplete = instance.web.Widget.extend({
},
close: function () {
this.current_search = null;
this.search_string = null;
this.search_string = '';
this.searching = true;
this.$el.hide();
},