From f4ee61f950dc1eeb7b3653ca96ea72721512b5e5 Mon Sep 17 00:00:00 2001 From: Vandan Shah Date: Mon, 9 Oct 2017 18:10:07 +0530 Subject: [PATCH] [IMP] web: mobile: add swipe support in form views This rev. allows to navigate, in mobile, through records in form views by swiping. We also moved mobile-specific tests involving a form view to the mobile test suite, since those tests became async because of the lazy loading of the swipe lib (in the mobile suite, that lib is already loaded). Related to task #34727 Co-authored-by: Mohammed Shekha --- .../src/js/views/form/form_controller.js | 26 +++ .../static/src/js/views/form/form_renderer.js | 33 +++- .../web/static/src/js/views/form/form_view.js | 5 + .../tests/fields/basic_fields_mobile_tests.js | 178 ++++++++++++++++++ .../static/tests/fields/basic_fields_tests.js | 141 +------------- .../fields/relational_fields_mobile_tests.js | 119 ++++++++++++ .../tests/fields/relational_fields_tests.js | 68 ------- .../static/tests/views/form_mobile_tests.js | 92 +++++++++ addons/web/static/tests/views/form_tests.js | 1 - addons/web/views/webclient_templates.xml | 3 + 10 files changed, 456 insertions(+), 210 deletions(-) create mode 100644 addons/web/static/tests/fields/basic_fields_mobile_tests.js create mode 100644 addons/web/static/tests/fields/relational_fields_mobile_tests.js create mode 100644 addons/web/static/tests/views/form_mobile_tests.js diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 5e669e0aa57..5f43b04f7cd 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -21,6 +21,8 @@ var FormController = BasicController.extend({ toggle_column_order: '_onToggleColumnOrder', focus_control_button: '_onFocusControlButton', form_dialog_discarded: '_onFormDialogDiscarded', + swipe_left: '_onSwipeLeft', + swipe_right: '_onSwipeRight', }), /** * @override @@ -644,6 +646,30 @@ var FormController = BasicController.extend({ self._enableButtons(); }); }, + /** + * Called when user swipes left. Move to next record. + * + * @private + * @param {OdooEvent} ev + */ + _onSwipeLeft: function (ev) { + ev.stopPropagation(); + if (this.pager) { + this.pager.next(); + } + }, + /** + * Called when user swipes right. Move to previous record. + * + * @private + * @param {OdooEvent} ev + */ + _onSwipeRight: function (ev) { + ev.stopPropagation(); + if (this.pager) { + this.pager.previous(); + } + }, /** * This method is called when someone tries to sort a column, most likely * in a x2many list view 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 6e9952c81d7..ac8ff541544 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -86,7 +86,7 @@ var FormRenderer = BasicRenderer.extend({ * @param {string} recordID * @returns {string[]} */ - canBeSaved: function (recordID) { + canBeSaved: function () { var self = this; var fieldNames = this._super.apply(this, arguments); @@ -130,7 +130,7 @@ var FormRenderer = BasicRenderer.extend({ * * @override */ - confirmChange: function (state, id, fields, e) { + confirmChange: function () { var self = this; return this._super.apply(this, arguments).then(function (resetWidgets) { _.each(resetWidgets, function (widget) { @@ -288,6 +288,30 @@ var FormRenderer = BasicRenderer.extend({ }); }); }, + /** + * Enable swipe event to allow navigating through records + * + * @private + */ + _enableSwipe: function () { + var self = this; + this.$('.o_form_sheet').swipe({ + swipeLeft: function () { + this.css({ + transform: 'translateX(-100%)', + transition: '350ms' + }); + self.trigger_up('swipe_left'); + }, + swipeRight: function () { + this.css({ + transform: 'translateX(100%)', + transition: '350ms' + }); + self.trigger_up('swipe_right'); + }, + }); + }, /** * @private * @param {string} name @@ -895,6 +919,11 @@ var FormRenderer = BasicRenderer.extend({ this.$el.toggleClass('o_form_editable', this.mode === 'edit'); this.$el.toggleClass('o_form_readonly', this.mode === 'readonly'); + // Enable swipe for mobile when formview is in readonly mode and there are multiple records + if (config.device.isMobile && this.mode === 'readonly' && this.state.count > 1) { + this._enableSwipe(); + } + // Attach the tooltips on the fields' label _.each(this.allFieldWidgets[this.state.id], function (widget) { var idForLabel = self.idsForLabels[widget.name]; diff --git a/addons/web/static/src/js/views/form/form_view.js b/addons/web/static/src/js/views/form/form_view.js index c688a997581..01474a01180 100644 --- a/addons/web/static/src/js/views/form/form_view.js +++ b/addons/web/static/src/js/views/form/form_view.js @@ -2,6 +2,7 @@ odoo.define('web.FormView', function (require) { "use strict"; var BasicView = require('web.BasicView'); +var config = require('web.config'); var Context = require('web.Context'); var core = require('web.core'); var FormController = require('web.FormController'); @@ -18,6 +19,7 @@ var FormView = BasicView.extend({ icon: 'fa-edit', multi_record: false, searchable: false, + jsLibs: [], viewType: 'form', /** * @override @@ -41,6 +43,9 @@ var FormView = BasicView.extend({ this.controllerParams.mode = mode; this.rendererParams.mode = mode; + if (config.device.isMobile) { + this.jsLibs.push('/web/static/lib/jquery.touchSwipe/jquery.touchSwipe.js'); + } }, //-------------------------------------------------------------------------- diff --git a/addons/web/static/tests/fields/basic_fields_mobile_tests.js b/addons/web/static/tests/fields/basic_fields_mobile_tests.js new file mode 100644 index 00000000000..76482a71e83 --- /dev/null +++ b/addons/web/static/tests/fields/basic_fields_mobile_tests.js @@ -0,0 +1,178 @@ +odoo.define('web.basic_fields_tests', function (require) { +"use strict"; + +var FormView = require('web.FormView'); +var ListView = require('web.ListView'); +var testUtils = require('web.test_utils'); + +var createView = testUtils.createView; + +QUnit.module('fields', {}, function () { + +QUnit.module('basic_fields', { + beforeEach: function () { + this.data = { + partner: { + fields: { + date: {string: "A date", type: "date", searchable: true}, + datetime: {string: "A datetime", type: "datetime", searchable: true}, + display_name: {string: "Displayed name", type: "char", searchable: true}, + foo: {string: "Foo", type: "char", default: "My little Foo Value", searchable: true, trim: true}, + bar: {string: "Bar", type: "boolean", default: true, searchable: true}, + int_field: {string: "int_field", type: "integer", sortable: true, searchable: true}, + qux: {string: "Qux", type: "float", digits: [16,1], searchable: true}, + }, + records: [{ + id: 1, + date: "2017-02-03", + datetime: "2017-02-08 10:00:00", + display_name: "first record", + bar: true, + foo: "yop", + int_field: 10, + qux: 0.44444, + }, { + id: 2, + display_name: "second record", + bar: true, + foo: "blip", + int_field: 0, + qux: 0, + }, { + id: 4, + display_name: "aaa", + foo: "abc", + int_field: false, + qux: false, + }], + onchanges: {}, + }, + }; + } +}, function () { + + QUnit.module('PhoneWidget'); + + QUnit.test('phone field in form view on extra small screens', function (assert) { + assert.expect(7); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'
' + + '' + + '' + + '' + + '' + + '' + + '
', + res_id: 1, + }); + + var $phoneLink = form.$('a.o_form_uri.o_field_widget'); + assert.strictEqual($phoneLink.length, 1, + "should have a anchor with correct classes"); + assert.strictEqual($phoneLink.text(), 'yop', + "value should be displayed properly"); + assert.strictEqual($phoneLink.attr('href'), 'tel:yop', + "should have proper tel prefix"); + + // switch to edit mode and check the result + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, + "should have an int for the phone field"); + assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', + "input should contain field value in edit mode"); + + // change value in edit mode + form.$('input[type="text"].o_field_widget').val('new').trigger('input'); + + // save + form.$buttons.find('.o_form_button_save').click(); + $phoneLink = form.$('a.o_form_uri.o_field_widget'); + assert.strictEqual($phoneLink.text(), 'new', + "new value should be displayed properly"); + assert.strictEqual($phoneLink.attr('href'), 'tel:new', + "should still have proper tel prefix"); + + form.destroy(); + }); + + QUnit.test('phone field in editable list view on extra small screens', function (assert) { + assert.expect(10); + + var list = createView({ + View: ListView, + model: 'partner', + data: this.data, + arch: '', + }); + + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').length, 5, + "should have 5 cells"); + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop', + "value should be displayed properly"); + + var $phoneLink = list.$('a.o_form_uri.o_field_widget'); + assert.strictEqual($phoneLink.length, 5, + "should have anchors with correct classes"); + assert.strictEqual($phoneLink.first().attr('href'), 'tel:yop', + "should have proper tel prefix"); + + // Edit a line and check the result + var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); + $cell.click(); + assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); + assert.strictEqual($cell.find('input').val(), 'yop', + 'should have the corect value in internal input'); + $cell.find('input').val('new').trigger('input'); + + // save + list.$buttons.find('.o_list_button_save').click(); + $cell = list.$('tbody td:not(.o_list_record_selector)').first(); + assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new', + "value should be properly updated"); + $phoneLink = list.$('a.o_form_uri.o_field_widget'); + assert.strictEqual($phoneLink.length, 5, + "should still have anchors with correct classes"); + assert.strictEqual($phoneLink.first().attr('href'), 'tel:new', + "should still have proper tel prefix"); + + list.destroy(); + }); + + QUnit.test('phone field does not allow html injections', function (assert) { + assert.expect(1); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'
' + + '' + + '' + + '' + + '' + + '' + + '
', + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + var val = ''; + form.$('input').val(val).trigger('input'); + + // save + form.$buttons.find('.o_form_button_save').click(); + assert.strictEqual(form.$('.o_field_widget').text(), val, + "value should have been correctly escaped"); + + form.destroy(); + }); +}); +}); +}); diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index 68643f7b48d..4036594609f 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -3269,7 +3269,6 @@ QUnit.module('basic_fields', { list.destroy(); }); - QUnit.module('FieldFloatTime'); QUnit.test('float_time field in form view', function (assert) { @@ -3400,106 +3399,6 @@ QUnit.module('basic_fields', { QUnit.module('PhoneWidget'); - QUnit.test('phone field in form view on extra small screens', function (assert) { - assert.expect(7); - - var form = createView({ - View: FormView, - model: 'partner', - data: this.data, - arch:'
' + - '' + - '' + - '' + - '' + - '' + - '
', - res_id: 1, - config: { - device: { - size_class: config.device.SIZES.VSM, - }, - }, - }); - - var $phoneLink = form.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.length, 1, - "should have a anchor with correct classes"); - assert.strictEqual($phoneLink.text(), 'yop', - "value should be displayed properly"); - assert.strictEqual($phoneLink.attr('href'), 'tel:yop', - "should have proper tel prefix"); - - // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, - "should have an input for the phone field"); - assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', - "input should contain field value in edit mode"); - - // change value in edit mode - form.$('input[type="text"].o_field_widget').val('new').trigger('input'); - - // save - form.$buttons.find('.o_form_button_save').click(); - $phoneLink = form.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.text(), 'new', - "new value should be displayed properly"); - assert.strictEqual($phoneLink.attr('href'), 'tel:new', - "should still have proper tel prefix"); - - form.destroy(); - }); - - QUnit.test('phone field in editable list view on extra small screens', function (assert) { - assert.expect(10); - - var list = createView({ - View: ListView, - model: 'partner', - data: this.data, - arch: '', - config: { - device: { - size_class: config.device.SIZES.VSM, - }, - }, - }); - - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').length, 5, - "should have 5 cells"); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop', - "value should be displayed properly"); - - var $phoneLink = list.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.length, 5, - "should have anchors with correct classes"); - assert.strictEqual($phoneLink.first().attr('href'), 'tel:yop', - "should have proper tel prefix"); - - // Edit a line and check the result - var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); - assert.strictEqual($cell.find('input').val(), 'yop', - 'should have the corect value in internal input'); - $cell.find('input').val('new').trigger('input'); - - // save - list.$buttons.find('.o_list_button_save').click(); - $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new', - "value should be properly updated"); - $phoneLink = list.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.length, 5, - "should still have anchors with correct classes"); - assert.strictEqual($phoneLink.first().attr('href'), 'tel:new', - "should still have proper tel prefix"); - - list.destroy(); - }); - QUnit.test('phone field in form view on normal screens', function (assert) { assert.expect(5); @@ -3517,7 +3416,7 @@ QUnit.module('basic_fields', { res_id: 1, config: { device: { - size_class: config.device.SIZES.MD, + size_class: config.device.SIZES.LG, }, }, }); @@ -3556,7 +3455,7 @@ QUnit.module('basic_fields', { arch: '', config: { device: { - size_class: config.device.SIZES.MD, + size_class: config.device.SIZES.LG, }, }, }); @@ -3589,42 +3488,6 @@ QUnit.module('basic_fields', { list.destroy(); }); - QUnit.test('phone field does not allow html injections', function (assert) { - assert.expect(1); - - var form = createView({ - View: FormView, - model: 'partner', - data: this.data, - arch:'
' + - '' + - '' + - '' + - '' + - '' + - '
', - res_id: 1, - viewOptions: { - mode: 'edit', - }, - config: { - device: { - size_class: config.device.SIZES.VSM, - }, - }, - }); - - var val = ''; - form.$('input').val(val).trigger('input'); - - // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_widget').text(), val, - "value should have been correctly escaped"); - - form.destroy(); - }); - QUnit.test('use TAB to navigate to a phone field', function (assert) { assert.expect(2); diff --git a/addons/web/static/tests/fields/relational_fields_mobile_tests.js b/addons/web/static/tests/fields/relational_fields_mobile_tests.js new file mode 100644 index 00000000000..8a1ab7ce1a5 --- /dev/null +++ b/addons/web/static/tests/fields/relational_fields_mobile_tests.js @@ -0,0 +1,119 @@ +odoo.define('web.relational_fields_tests', function (require) { +"use strict"; + +var FormView = require('web.FormView'); +var testUtils = require('web.test_utils'); + +var createView = testUtils.createView; + +QUnit.module('fields', {}, function () { + +QUnit.module('relational_fields', { + beforeEach: function () { + this.data = { + partner: { + fields: { + display_name: { string: "Displayed name", type: "char" }, + foo: {string: "Foo", type: "char", default: "My little Foo Value"}, + bar: {string: "Bar", type: "boolean", default: true}, + int_field: {string: "int_field", type: "integer", sortable: true}, + qux: {string: "Qux", type: "float", digits: [16,1] }, + p: {string: "one2many field", type: "one2many", relation: 'partner', relation_field: 'trululu'}, + trululu: {string: "Trululu", type: "many2one", relation: 'partner'}, + }, + records: [{ + id: 1, + display_name: "first record", + bar: true, + foo: "yop", + int_field: 10, + qux: 0.44, + p: [], + trululu: 4, + }, { + id: 2, + display_name: "second record", + bar: true, + foo: "blip", + int_field: 9, + qux: 13, + p: [], + trululu: 1, + }, { + id: 4, + display_name: "aaa", + bar: false, + }], + onchanges: {}, + }, + }; + } +}, function () { + + QUnit.module('FieldOne2Many'); + + QUnit.test('one2many kanban: deletion in mobile', function (assert) { + assert.expect(9); + + this.data.partner.records[0].p = [1, 2]; + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '', + res_id: 1, + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/partner/write') { + var commands = args.args[1].p; + assert.strictEqual(commands.length, 2, + 'should have generated two commands'); + assert.ok(commands[0][0] === 4 && commands[0][1] === 2, + 'should have generated the command 2 (DELETE) with id 1'); + assert.ok(commands[1][0] === 2 && commands[1][1] === 1, + 'should have generated the command 2 (DELETE) with id 2'); + } + return this._super.apply(this, arguments); + }, + }); + + assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 0, + '"Create" button should not be visible in readonly'); + + form.$buttons.find('.o_form_button_edit').click(); + + assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 1, + '"Create" button should be visible in edit'); + assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, + "should have 2 records"); + + // open and delete record + form.$('.oe_kanban_global_click').first().click(); + assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1, + 'there should be a Remove button in the modal footer'); + $('.modal .modal-footer .o_btn_remove').click(); + assert.strictEqual($('.o_modal').length, 0, "there shoul be no more modal"); + assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1, + 'should contain 1 records'); + + // save and check that the correct command has been generated + form.$buttons.find('.o_form_button_save').click(); + form.destroy(); + }); +}); +}); +}); diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index bb7b4a446e6..245ff8f7a07 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -4909,74 +4909,6 @@ QUnit.module('relational_fields', { form.destroy(); }); - QUnit.test('one2many kanban: deletion in mobile', function (assert) { - assert.expect(9); - - this.data.partner.records[0].p = [1, 2]; - var form = createView({ - View: FormView, - model: 'partner', - data: this.data, - arch: '
' + - '' + - '' + - '' + - '' + - '
' + - '' + - '
' + - '
' + - '
' + - '
' + - '' + - '' + - '' + - '' + - '', - res_id: 1, - mockRPC: function (route, args) { - if (route === '/web/dataset/call_kw/partner/write') { - var commands = args.args[1].p; - assert.strictEqual(commands.length, 2, - 'should have generated two commands'); - assert.ok(commands[0][0] === 4 && commands[0][1] === 2, - 'should have generated the command 2 (DELETE) with id 1'); - assert.ok(commands[1][0] === 2 && commands[1][1] === 1, - 'should have generated the command 2 (DELETE) with id 2'); - } - return this._super.apply(this, arguments); - }, - config: { - device: { - size_class: config.device.SIZES.XS, - }, - }, - }); - - assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 0, - '"Create" button should not be visible in readonly'); - - form.$buttons.find('.o_form_button_edit').click(); - - assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 1, - '"Create" button should be visible in edit'); - assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, - "should have 2 records"); - - // open and delete record - form.$('.oe_kanban_global_click').first().click(); - assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1, - 'there should be a Remove button in the modal footer'); - $('.modal .modal-footer .o_btn_remove').click(); - assert.strictEqual($('.o_modal').length, 0, "there shoul be no more modal"); - assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1, - 'should contain 1 records'); - - // save and check that the correct command has been generated - form.$buttons.find('.o_form_button_save').click(); - form.destroy(); - }); - QUnit.test('one2many kanban: create action disabled', function (assert) { assert.expect(3); diff --git a/addons/web/static/tests/views/form_mobile_tests.js b/addons/web/static/tests/views/form_mobile_tests.js new file mode 100644 index 00000000000..05a19a27668 --- /dev/null +++ b/addons/web/static/tests/views/form_mobile_tests.js @@ -0,0 +1,92 @@ +odoo.define('web.form_mobile_tests', function (require) { +"use strict"; + +var FormView = require('web.FormView'); +var testUtils = require('web.test_utils'); + +var createView = testUtils.createView; + +QUnit.module('Views', { + beforeEach: function () { + this.data = { + partner: { + fields: { + display_name: { string: "Displayed name", type: "char" }, + foo: {string: "Foo", type: "char", default: "My little Foo Value"}, + bar: {string: "Bar", type: "boolean"}, + }, + records: [{ + id: 1, + display_name: "first record", + bar: true, + foo: "yop", + }, { + id: 2, + display_name: "second record", + bar: true, + foo: "blip", + }, { + id: 4, + display_name: "aaa", + state: "ef", + }, { + id: 5, + display_name: "aaa", + foo:'', + bar: false, + }], + onchanges: {}, + }, + }; + } +}, function () { + + QUnit.module('FormView'); + + QUnit.test('switching to next/previous record on swipe in readonly mode', function (assert) { + assert.expect(6); + + // mimic touchSwipe library's swipe method + var oldSwipe = $.fn.swipe; + var swipeLeft, swipeRight; + $.fn.swipe = function (params) { + swipeLeft = params.swipeLeft.bind(this); + swipeRight = params.swipeRight.bind(this); + }; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '
', + viewOptions: { + ids: [1, 2], + index: 0, + }, + res_id: 1, + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/partner/read') { + assert.step(args.args[0][0]); + } + return this._super(route, args); + }, + }); + + swipeLeft(); + assert.strictEqual(form.pager.$('.o_pager_value').text(), '2', 'pager value should be 2'); + + swipeRight(); + assert.strictEqual(form.pager.$('.o_pager_value').text(), '1', 'pager value should be 1'); + + assert.verifySteps([1, 2, 1]); + + $.fn.swipe = oldSwipe; + form.destroy(); + }); +}); + +}); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 219972f46c9..222317ae3e4 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -7036,7 +7036,6 @@ QUnit.module('Views', { form.destroy(); }); - QUnit.module('FormViewTABMainButtons'); QUnit.test('using tab in an empty required string field should not move to the next field',function(assert) { diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index a33592a602a..975d5fc63ec 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -625,6 +625,9 @@ + + +