From 6c39b566d691cc5aa63733e849358500698ff6cb Mon Sep 17 00:00:00 2001 From: "Achraf (abz)" Date: Wed, 1 Dec 2021 12:47:27 +0000 Subject: [PATCH] [FIX] mass_mailing,project: Prevents crash on form views When a user double clicks on a record in the kanban view of the form view of project a crash occurs. This happens because there is an init which is called twice and during the second time the component created during the first click is destroyed and a DOM_updated event is still trigger which leads to a crash because in the case of project_form there is has a use of the element's dom which is then no longer available. There is the same case in "FieldHtmlWithAction" and in "MassMailingFullWidthFormController" The problem can be easily fixed by using on_attached_callback and on_detach_callback instead of setting a listener on DOM_updated in the init method. opw-2685867 closes odoo/odoo#81680 X-original-commit: 8d83433d463dd3d1aef321921939962883f57d68 Signed-off-by: Aaron Bohy (aab) Signed-off-by: Achraf --- .../mailing_mailing_view_form_full_width.js | 3 +- addons/project/__manifest__.py | 1 + addons/project/static/src/js/project_form.js | 23 +++++----- .../static/tests/project_form_tests.js | 43 +++++++++++++++++++ 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 addons/project/static/tests/project_form_tests.js diff --git a/addons/mass_mailing/static/src/js/mailing_mailing_view_form_full_width.js b/addons/mass_mailing/static/src/js/mailing_mailing_view_form_full_width.js index 98c9533f697..946885533aa 100644 --- a/addons/mass_mailing/static/src/js/mailing_mailing_view_form_full_width.js +++ b/addons/mass_mailing/static/src/js/mailing_mailing_view_form_full_width.js @@ -17,7 +17,6 @@ const MassMailingFullWidthFormController = FormController.extend({ */ init() { this._super(...arguments); - this._boundOnDomUpdated = this._onDomUpdated.bind(this); bus.on('DOM_updated', this, this._onDomUpdated); this._resizeObserver = new ResizeObserver(entries => { // We wrap this in requestAnimationFrame to greatly mitigate @@ -34,7 +33,7 @@ const MassMailingFullWidthFormController = FormController.extend({ * @override */ destroy() { - bus.off('DOM_updated', this, this._boundOnDomUpdated); + bus.off('DOM_updated', this, this._onDomUpdated); this._super(...arguments); }, diff --git a/addons/project/__manifest__.py b/addons/project/__manifest__.py index fc30d6266d4..f5fff81552c 100644 --- a/addons/project/__manifest__.py +++ b/addons/project/__manifest__.py @@ -95,6 +95,7 @@ ], 'web.qunit_suite_tests': [ 'project/static/tests/burndown_chart_tests.js', + 'project/static/tests/project_form_tests.js', ], 'web.assets_tests': [ 'project/static/tests/tours/**/*', diff --git a/addons/project/static/src/js/project_form.js b/addons/project/static/src/js/project_form.js index 8289ad235b2..f371a8b6880 100644 --- a/addons/project/static/src/js/project_form.js +++ b/addons/project/static/src/js/project_form.js @@ -8,19 +8,22 @@ import { device } from 'web.config'; import viewRegistry from 'web.view_registry'; const ProjectFormController = FormController.extend({ - init() { - this._super(...arguments); + on_attach_callback() { if (!device.isMobile) { - bus.on("DOM_updated", this, () => { - const $editable = this.$el.find('.note-editable'); - if ($editable.length) { - const resizerHeight = this.$el.find('.o_wysiwyg_resizer').outerHeight(); - const newHeight = window.innerHeight - $editable.offset().top - resizerHeight - 1; - $editable.outerHeight(newHeight); - } - }); + bus.on("DOM_updated", this, this._onDomUpdated); } }, + _onDomUpdated() { + const $editable = this.$el.find('.note-editable'); + if ($editable.length) { + const resizerHeight = this.$el.find('.o_wysiwyg_resizer').outerHeight(); + const newHeight = window.innerHeight - $editable.offset().top - resizerHeight - 1; + $editable.outerHeight(newHeight); + } + }, + on_detach_callback() { + bus.off('DOM_updated', this._onDomUpdated); + }, _getActionMenuItems(state) { if (!this.archiveEnabled || !state.data['recurrence_id']) { return this._super(...arguments); diff --git a/addons/project/static/tests/project_form_tests.js b/addons/project/static/tests/project_form_tests.js new file mode 100644 index 00000000000..0497d344239 --- /dev/null +++ b/addons/project/static/tests/project_form_tests.js @@ -0,0 +1,43 @@ +/** @odoo-module */ +import { createView } from 'web.test_utils'; +import {ProjectFormView} from "@project/js/project_form"; +import {patch} from "@web/core/utils/patch"; +import core from "web.core"; +let serverData = null; + +const ProjectFormController = ProjectFormView.prototype.config.Controller; +QUnit.module("Project", hooks => { + hooks.beforeEach(() => { + serverData = { + project: { + fields: { + id: { string: "Id", type: "integer" }, + }, + records: [ + { id: 1, display_name: "First record"}, + ], + }, + } + }) + QUnit.module("Form"); + QUnit.test("project form view", async function (assert) { + /* + This is a test whitebox because the flow cannot be reproduced correctly otherwise. + The idea is to check that the DOM_updated event is not triggered twice to avoid a crash. + */ + patch(ProjectFormController.prototype, "patchedInit", { + init: function () { + this._super(...arguments); + core.bus.trigger("DOM_updated"); + } + }); + const form = await createView({ + View: ProjectFormView, + model: 'project', + data: serverData, + arch: '
', + }); + assert.containsOnce(document.body, form.el); + form.destroy() + }) +});