[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) <aab@odoo.com>
Signed-off-by: Achraf <abz@odoo.com>
This commit is contained in:
Achraf (abz)
2021-12-20 16:53:09 +00:00
parent 927dd2d371
commit 6c39b566d6
4 changed files with 58 additions and 12 deletions
@@ -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);
},
+1
View File
@@ -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/**/*',
+13 -10
View File
@@ -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);
@@ -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: '<form><field name="display_name"/></form>',
});
assert.containsOnce(document.body, form.el);
form.destroy()
})
});