diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index e4f5ef9d9f8..01de5fb334c 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -348,7 +348,7 @@ var AbstractField = Widget.extend({ */ _onKeydown: function (event) { if (event.which === $.ui.keyCode.TAB) { - this.trigger_up('move_next'); + this.trigger_up(event.shiftKey ? 'move_previous' : 'move_next'); event.preventDefault(); } }, diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 2370b1af19a..751923c3b9f 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -15,6 +15,10 @@ var FIELD_CLASSES = { return BasicRenderer.extend({ className: "o_form_view", + custom_events: { + move_next: '_onMoveNext', + move_previous: '_onMovePrevious', + }, /** * @override method from BasicRenderer * @param {Object} params @@ -716,6 +720,40 @@ return BasicRenderer.extend({ }); }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * When someone presses TAB in a widget, it is nice to be able to go to the + * next widget, especially since the TAB key event is preventDefaulted + * + * @private + * @param {OdooEvent} event + */ + _onMoveNext: function (event) { + event.stopPropagation(); + var index = this.widgets.indexOf(event.target); + if (index + 1 < this.widgets.length) { + this.widgets[index + 1].activate(); + } + }, + /** + * When someone presses SHIFT+TAB in a widget, it is nice to be able to go + * back to the previous widget, especially since the TAB key event is + * preventDefaulted + * + * @private + * @param {OdooEvent} event + */ + _onMovePrevious: function (event) { + event.stopPropagation(); + var index = this.widgets.indexOf(event.target); + if (index >= 1) { + this.widgets[index - 1].activate(); + } + }, }); }); diff --git a/addons/web/static/test/views/form_tests.js b/addons/web/static/test/views/form_tests.js index 66d9d64090c..3140310cc82 100644 --- a/addons/web/static/test/views/form_tests.js +++ b/addons/web/static/test/views/form_tests.js @@ -2110,5 +2110,40 @@ QUnit.module('Views', { form.destroy(); }); + + QUnit.test('navigation with tab key in form view', function (assert) { + assert.expect(2); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
', + res_id: 2, + }); + + // go to edit mode + form.$buttons.find('.o_form_button_edit').click(); + + // focus first input, trigger tab + form.$('input[name="foo"]').focus(); + form.$('input[name="foo"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); + assert.ok($.contains(form.$('div[name="bar"]')[0], document.activeElement), + "bar checkbox should be focused"); + + // simulate shift+tab on active element + $(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB, shiftKey: true})); + assert.strictEqual(document.activeElement, form.$('input[name="foo"]')[0], + "first input should be focused"); + + form.destroy(); + }); }); });