From 96b1db4cd44ab70c5a7014ee36a8b475e1c5e38a Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Wed, 30 Aug 2017 09:24:31 +0200 Subject: [PATCH] [FIX] web: prevent 'reload' event from being handled twice When the external button of a many2one field is clicked, the related record is opened in a dialog. When the user clicks on 'Save' in this dialog, a 'reload' event is triggered to reload the parent view (the one in the background), as the display name might have changed. However, when there is another many2one field in the opened dialog, and if its external button is clicked, there are 2 opened dialogs, and thus 3 nested form views. If the user clicks on 'Save' in the third one, only the direct parent view must be reloaded (the one in the first dialog). Before this rev., the 'reload' event wasn't stopPropagated, so it was handled by the view in the dialog, and by the one in the background, which produced a crash. This could happen for instance in Sales Order, edit a sale order line, click on the external button of the product, in the dialog, click on the external button of the category, edit some field and click on 'Save'. Closes #19052 --- .../src/js/views/basic/basic_controller.js | 1 + addons/web/static/tests/views/form_tests.js | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js index 32570038987..67de3ec8ad9 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -539,6 +539,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { * reload */ _onReload: function (event) { + event.stopPropagation(); // prevent other controllers from handling this request var data = event && event.data || {}; var handle = data.db_id; if (handle) { diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 6bd2b4ca7b5..69e9e3696f7 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -5734,5 +5734,60 @@ QUnit.module('Views', { config.debug = initialDebugMode; form.destroy(); }); + + QUnit.test('reload event is handled only once', function (assert) { + // In this test, several form controllers are nested (two of them are + // opened in dialogs). When the users clicks on save in the last + // opened dialog, a 'reload' event is triggered up to reload the (direct) + // parent view. If this event isn't stopPropagated by the first controller + // catching it, it will crash when the other one will try to handle it, + // as this one doesn't know at all the dataPointID to reload. + assert.expect(9); + + var arch = '
' + + '' + + '' + + ''; + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: arch, + archs: { + 'partner,false,form': arch, + }, + res_id: 2, + mockRPC: function (route, args) { + assert.step(args.method); + if (args.method === 'get_formview_id') { + return $.when(false); + } + return this._super.apply(this, arguments); + }, + viewOptions: { + mode: 'edit', + }, + }); + + form.$('.o_external_button').click(); // open the many2one record in a modal + $('.modal .o_external_button').click(); // in the modal, open the many2one record in another modal + + $('.modal:nth(1) .o_field_widget[name=display_name]').val('new name').trigger('input'); + $('.modal:nth(1) .modal-footer .btn-primary').first().click(); // save changes + + assert.strictEqual($('.modal .o_field_widget[name=trululu] input').val(), 'new name', + "record should have been reloaded"); + assert.verifySteps([ + "read", // main record + "get_formview_id", // id of first form view opened in a dialog + "read", // first dialog + "get_formview_id", // id of second form view opened in a dialog + "read", // second dialog + "write", // save second dialog + "read", // reload first dialog + ]); + + form.destroy(); + }); }); });