From df4bd736f10d8c8ca646fbef58927bf7446146f0 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 11 Mar 2015 17:42:54 +0100 Subject: [PATCH] [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 --- addons/web/static/src/js/search.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 514ab406e1d..5ab5952f161 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -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(); },