[IMP] barcode_events: implement a new way of dealing with barcode events
Implement a new way of dealing with barcode events. This was necessary because the old way of dealing with input coming from barcode devices did not stop keyevents. This lead to all kinds of issues (eg. barcode reader output being inserted as tender in a paymentline). This new class inserts itself so that it handles all keyevents before everything else. This means that it has authority on what keypress events pass and which ones do not. It differentiates between 'real' keyboard input and input coming from devices by buffering events. When a certain amount of events come in fast enough, it is handled as a barcode and a 'barcode_scanned' event is emitted on core.bus. When buffered events are decided to not be a barcode, they are recreated and redispatched.
This commit is contained in:
committed by
Frédéric van der Essen
parent
930a427ffa
commit
49d4ddd422
@@ -0,0 +1,118 @@
|
||||
odoo.define('web.BarcodeEvents', function(require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var mixins = core.mixins;
|
||||
|
||||
return core.Class.extend(mixins.PropertiesMixin, {
|
||||
timeout: null,
|
||||
key_released: true,
|
||||
buffered_key_events: [],
|
||||
|
||||
init: function(parent) {
|
||||
mixins.PropertiesMixin.init.call(this);
|
||||
},
|
||||
|
||||
handle_buffered_keys: function() {
|
||||
var code = "";
|
||||
|
||||
if (this.buffered_key_events.length >= 3) {
|
||||
for (var i = 0; i < this.buffered_key_events.length; i++) {
|
||||
code += String.fromCharCode(this.buffered_key_events[i].which);
|
||||
}
|
||||
|
||||
core.bus.trigger('barcode_scanned', code);
|
||||
|
||||
// Dispatch a barcode_scanned DOM event to elements that have
|
||||
// barcode_events="true" set.
|
||||
if (this.element_is_editable(this.buffered_key_events[0].target)) {
|
||||
$(this.buffered_key_events[0].target).trigger('barcode_scanned', code);
|
||||
}
|
||||
} else {
|
||||
this.resend_buffered_keys();
|
||||
}
|
||||
|
||||
this.buffered_key_events = [];
|
||||
},
|
||||
|
||||
resend_buffered_keys: function() {
|
||||
for(var i = 0; i < this.buffered_key_events.length; i++) {
|
||||
var old_event = this.buffered_key_events[i];
|
||||
|
||||
if(old_event.which !== 13) { // ignore returns
|
||||
// We do not create a 'real' keypress event through
|
||||
// eg. KeyboardEvent because there are several issues
|
||||
// with them that make them very different from
|
||||
// genuine keypresses. Chrome per example has had a
|
||||
// bug for the longest time that causes keyCode and
|
||||
// charCode to not be set for events created this way:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=16735
|
||||
var new_event = new Event("keypress", {
|
||||
'bubbles': old_event.bubbles,
|
||||
'cancelable': old_event.cancelable,
|
||||
});
|
||||
|
||||
new_event.viewArg = old_event.viewArg;
|
||||
new_event.ctrl = old_event.ctrl;
|
||||
new_event.alt = old_event.alt;
|
||||
new_event.shift = old_event.shift;
|
||||
new_event.meta = old_event.meta;
|
||||
new_event.char = old_event.char;
|
||||
new_event.key = old_event.key;
|
||||
new_event.charCode = old_event.charCode;
|
||||
new_event.keyCode = old_event.keyCode || old_event.which; // Firefox doesn't set keyCode for keypresses, only keyup/down
|
||||
new_event.which = old_event.which;
|
||||
new_event.dispatched_by_barcode_reader = true;
|
||||
|
||||
old_event.target.dispatchEvent(new_event);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
element_is_editable: function(element) {
|
||||
return $(element).is('input,textarea,[contenteditable="true"]');
|
||||
},
|
||||
|
||||
keyup_handler: function(e){
|
||||
this.key_released = true;
|
||||
},
|
||||
|
||||
handler: function(e){
|
||||
if (! e.dispatched_by_barcode_reader) {
|
||||
if (! this.key_released) { // don't allow key repeat
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
this.key_released = false;
|
||||
|
||||
// We only stop events targeting body (meaning nothing is
|
||||
// focused). We do not stop events targeting other elements
|
||||
// because we have no way of redispatching 'genuine' key events
|
||||
// that trigger native event handlers of elements. So this means
|
||||
// that our fake events will not appear in eg. an <input>
|
||||
// element. The addition of the contentEditable attribute in HTML5
|
||||
// means that this is not only limited to <input>, <textarea>,...
|
||||
if (! this.element_is_editable(e.target) || e.target.getAttribute("barcode_events") === "true") {
|
||||
this.buffered_key_events.push(e);
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(this.handle_buffered_keys.bind(this), 100);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
start: function(){
|
||||
document.body.addEventListener('keypress', this.handler.bind(this), true);
|
||||
document.body.addEventListener('keyup', this.keyup_handler.bind(this), true);
|
||||
},
|
||||
|
||||
stop: function(){
|
||||
document.body.removeEventListener('keypress', this.handler.bind(this), true);
|
||||
document.body.removeEventListener('keyup', this.keyup_handler.bind(this), true);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -14,6 +14,7 @@ var SystrayMenu = require('web.SystrayMenu');
|
||||
var UserMenu = require('web.UserMenu');
|
||||
var utils = require('web.utils');
|
||||
var Widget = require('web.Widget');
|
||||
var BarcodeEvents = require('web.BarcodeEvents');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
@@ -36,6 +37,7 @@ var WebClient = Widget.extend({
|
||||
this.menu_dm = new utils.DropMisordered();
|
||||
this.action_mutex = new utils.Mutex();
|
||||
this.set('title_part', {"zopenerp": "Odoo"});
|
||||
this.barcode_events = new BarcodeEvents();
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
@@ -339,6 +341,9 @@ var WebClient = Widget.extend({
|
||||
this.$('.oe_webclient').toggleClass(
|
||||
'oe_content_full_screen', fullscreen);
|
||||
},
|
||||
get_barcode_events: function() {
|
||||
return this.barcode_events;
|
||||
}
|
||||
});
|
||||
|
||||
return WebClient;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<script type="text/javascript" src="/web/static/src/js/framework/session.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/framework/model.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/framework/utils.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/framework/barcode_events.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/framework/core.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/tour.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/menu.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user