[FIX] barcodes: fix several issues when scanning barcodes
Since the new views, most of the barcodes feature was broken. This commit re-enables the support of commands like 'edit', 'save', 'cancel', 'previous' and 'next'. Also changed javascript event handler to jquery event handler to make barcodes testable in phantomjs.
This commit is contained in:
committed by
Aaron Bohy
parent
7095c32f1c
commit
b131e9b0ef
@@ -77,13 +77,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
'bubbles': old_event.bubbles,
|
||||
'cancelable': old_event.cancelable,
|
||||
};
|
||||
try {
|
||||
new_event = new Event("keypress", params);
|
||||
} catch(error) {
|
||||
// For IE >= 9, use new CustomEvent(), instead of new Event()
|
||||
new_event = new CustomEvent("keypress", params);
|
||||
}
|
||||
|
||||
new_event = $.Event('keypress', params);
|
||||
new_event.viewArg = old_event.viewArg;
|
||||
new_event.ctrl = old_event.ctrl;
|
||||
new_event.alt = old_event.alt;
|
||||
@@ -96,7 +90,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
new_event.which = old_event.which;
|
||||
new_event.dispatched_by_barcode_reader = true;
|
||||
|
||||
old_event.target.dispatchEvent(new_event);
|
||||
$(old_event.target).trigger(new_event);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -173,17 +167,17 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
},
|
||||
|
||||
start: function(prevent_key_repeat){
|
||||
document.body.addEventListener('keypress', this.__handler, true);
|
||||
$('body').bind("keypress", this.__handler);
|
||||
if (prevent_key_repeat === true) {
|
||||
document.body.addEventListener('keydown', this.__keydown_handler, true);
|
||||
document.body.addEventListener('keyup', this.__keyup_handler, true);
|
||||
$('body').bind("keydown", this.__keydown_handler);
|
||||
$('body').bind('keyup', this.__keyup_handler);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function(){
|
||||
document.body.removeEventListener('keypress', this.__handler, true);
|
||||
document.body.removeEventListener('keydown', this.__keydown_handler, true);
|
||||
document.body.removeEventListener('keyup', this.__keyup_handler, true);
|
||||
$('body').unbind("keypress", this.__handler);
|
||||
$('body').unbind("keydown", this.__keydown_handler);
|
||||
$('body').unbind('keyup', this.__keyup_handler);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ var FieldFloatScannable = basicFields.FieldFloat.extend({
|
||||
*/
|
||||
_onKeypress: function (e) {
|
||||
/* only simulate a keypress if it has been previously prevented */
|
||||
if (e.originalEvent.dispatched_by_barcode_reader !== true) {
|
||||
if (e.dispatched_by_barcode_reader !== true) {
|
||||
e.preventDefault();
|
||||
this.$input.blur();
|
||||
return;
|
||||
|
||||
@@ -26,19 +26,21 @@ FormController.include({
|
||||
this.activeBarcode = {
|
||||
form_view: {
|
||||
commands: {
|
||||
'O-CMD.NEW': 'createRecord',
|
||||
'O-CMD.EDIT': 'toEditMode',
|
||||
'O-CMD.CANCEL': 'discardChange',
|
||||
'O-CMD.SAVE': function () { return this.saveRecord({reload: true}); },
|
||||
// 'O-CMD.PAGER-PREV':
|
||||
// 'O-CMD.PAGER-NEXT':
|
||||
}
|
||||
}
|
||||
'O-CMD.EDIT': this._onEdit.bind(this),
|
||||
'O-CMD.CANCEL': this._onDiscard.bind(this),
|
||||
'O-CMD.SAVE': this._onCommandSave.bind(this),
|
||||
'O-CMD.PAGER-PREV': this._onCommandPrevious.bind(this),
|
||||
'O-CMD.PAGER-NEXT': this._onCommandNext.bind(this),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
this.barcodeMutex = new concurrency.Mutex();
|
||||
this._barcodeStartListening();
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
destroy: function () {
|
||||
this._barcodeStopListening();
|
||||
this._super();
|
||||
@@ -70,6 +72,8 @@ FormController.include({
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Returns true iff the given barcode matches the given record (candidate).
|
||||
*
|
||||
* @private
|
||||
* @param {Object} candidate: record in the x2m
|
||||
* @param {string} barcode sent by the scanner (string generate from keypress series)
|
||||
@@ -128,7 +132,7 @@ FormController.include({
|
||||
*/
|
||||
_getBarCodeRecord: function (record, barcode, activeBarcode) {
|
||||
var self = this;
|
||||
if (!activeBarcode.fieldName) {
|
||||
if (!activeBarcode.fieldName || !record.data[activeBarcode.fieldName]) {
|
||||
return;
|
||||
}
|
||||
return _.find(record.data[activeBarcode.fieldName].data, function (record) {
|
||||
@@ -237,6 +241,24 @@ FormController.include({
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onCommandNext: function () {
|
||||
return this.mutex.exec(function () {}).then(this.pager.next.bind(this.pager));
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onCommandPrevious: function () {
|
||||
return this.mutex.exec(function () {}).then(this.pager.previous.bind(this.pager));
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onCommandSave: function () {
|
||||
return this.saveRecord();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {KeyEvent} event
|
||||
@@ -359,6 +381,21 @@ FormRenderer.include({
|
||||
}
|
||||
return $button;
|
||||
},
|
||||
/**
|
||||
* Add barcode event handler
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @param {Object} node
|
||||
* @returns {jQueryElement}
|
||||
*/
|
||||
_renderTagButton: function (node) {
|
||||
var $button = this._super.apply(this, arguments);
|
||||
if (node.attrs.barcode_trigger) {
|
||||
this._barcodeButtonHandler($button, node);
|
||||
}
|
||||
return $button;
|
||||
}
|
||||
});
|
||||
|
||||
BarcodeEvents.ReservedBarcodePrefixes.push('O-BTN');
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
odoo.define('barcodes.tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var testUtils = require('web.test_utils');
|
||||
var FormView = require('web.FormView');
|
||||
|
||||
var createView = testUtils.createView;
|
||||
var triggerKeypressEvent = testUtils.triggerKeypressEvent;
|
||||
|
||||
QUnit.module('Barcodes', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
product: {
|
||||
fields: {
|
||||
name: {string : "Product name", type: "char"},
|
||||
},
|
||||
records: [
|
||||
{id: 1, name: "iPad Mini"},
|
||||
{id: 2, name: "Mouse, Optical"},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('Button with barcode_trigger', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'product',
|
||||
data: this.data,
|
||||
arch: '<form>' +
|
||||
'<header>' +
|
||||
'<button name="do_something" string="Validate" type="object" barcode_trigger="doit"/>' +
|
||||
'</header>' +
|
||||
'</form>',
|
||||
res_id: 2,
|
||||
intercepts: {
|
||||
execute_action: function (event) {
|
||||
assert.strictEqual(event.data.action_data.name, 'do_something',
|
||||
"do_something method call verified");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// O-BTN.doit
|
||||
_.each(['O','-','B','T','N','.','d','o','i','t','Enter'], triggerKeypressEvent);
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('edit, save and cancel buttons', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'product',
|
||||
data: this.data,
|
||||
arch: '<form><field name="display_name"/></form>',
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'write') {
|
||||
assert.step('save');
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
res_id: 1,
|
||||
});
|
||||
|
||||
// O-CMD.EDIT
|
||||
_.each(["O","-","C","M","D",".","E","D","I","T","Enter"], triggerKeypressEvent);
|
||||
assert.strictEqual(form.$(".o_form_editable").length, 1,
|
||||
"should have switched to 'edit' mode");
|
||||
// dummy change to check that it actually saves
|
||||
form.$('.o_field_widget').val('test').trigger('input');
|
||||
// O-CMD.SAVE
|
||||
_.each(["O","-","C","M","D",".","S","A","V","E","Enter"], triggerKeypressEvent);
|
||||
assert.strictEqual(form.$(".o_form_readonly").length, 1,
|
||||
"should have switched to 'readonly' mode");
|
||||
assert.verifySteps(['save'], 'should have saved');
|
||||
|
||||
// O-CMD.EDIT
|
||||
_.each(["O","-","C","M","D",".","E","D","I","T","Enter"], triggerKeypressEvent);
|
||||
// dummy change to check that it correctly discards
|
||||
form.$('.o_field_widget').val('test').trigger('input');
|
||||
// O-CMD.CANCEL
|
||||
_.each(["O","-","C","M","D",".","C","A","N","C","E","L","Enter"], triggerKeypressEvent);
|
||||
assert.strictEqual(form.$(".o_form_readonly").length, 1,
|
||||
"should have switched to 'readonly' mode");
|
||||
assert.verifySteps(['save'], 'should not have saved');
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('pager buttons', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'product',
|
||||
data: this.data,
|
||||
arch: '<form><field name="display_name"/></form>',
|
||||
res_id: 1,
|
||||
viewOptions: {
|
||||
ids: [1, 2],
|
||||
index: 0,
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'iPad Mini');
|
||||
// O-CMD.PAGER-NEXT
|
||||
_.each(["O","-","C","M","D",".","P","A","G","E","R","-","N","E","X","T","Enter"], triggerKeypressEvent);
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Mouse, Optical');
|
||||
// O-CMD.PAGER-PREV
|
||||
_.each(["O","-","C","M","D",".","P","A","G","E","R","-","P","R","E","V","Enter"], triggerKeypressEvent);
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'iPad Mini');
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -10,4 +10,10 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="qunit_suite" name="barcode_tests" inherit_id="web.qunit_suite">
|
||||
<xpath expr="//t[@t-set='head']" position="inside">
|
||||
<script type="text/javascript" src="/barcodes/static/tests/barcode_tests.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -457,6 +457,20 @@ function triggerPositionalMouseEvent(x, y, type){
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* simulate a keypress event for a given character
|
||||
* @param {string} the character
|
||||
*/
|
||||
function triggerKeypressEvent(char) {
|
||||
var keycode;
|
||||
if (char === "Enter") {
|
||||
keycode = $.ui.keyCode.ENTER;
|
||||
} else {
|
||||
keycode = char.charCodeAt(0);
|
||||
}
|
||||
return $('body').trigger($.Event('keypress', {which: keycode, keyCode: keycode}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the src attribute on images and iframes to prevent not found errors,
|
||||
* and optionally triggers an rpc with the src url as route on a widget.
|
||||
@@ -498,6 +512,7 @@ return session.is_bound.then(function () {
|
||||
dragAndDrop: dragAndDrop,
|
||||
triggerMouseEvent: triggerMouseEvent,
|
||||
triggerPositionalMouseEvent: triggerPositionalMouseEvent,
|
||||
triggerKeypressEvent: triggerKeypressEvent,
|
||||
removeSrcAttribute: removeSrcAttribute,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user