[FIX] mail,project: remove chatter flickering
Before this commit, when a form view was re-rendered (e.g. when switching to "edit" or "readonly" modes, when using the pager...), the chatter briefly disappeared and then reappeared, which produced a flickering. This has been introduced by the adaptation of the JS codebase to owl 2 [1]: when the form view had to be re-rendered, we reused the DOM element containing the chatter in the new rendering (done in memory), which was thus detached from the DOM. That element was re-inserted into the DOM later on, alongside the rest of the newly rendered elements. This commit fixes the issue by using a specific "hook" element when rendering the form view, and replacing that hook by the actual (unchanged) chatter container element when the rendering is done and the DOM is patched. This commit also removes unnecessary overrides in project: - _renderNode was dead code, classname "oe_project_sharing_chatter" no longer exists in the codebase since [2] - _makeChatterContainerTarget replicated what was originally already done in the mail FormRenderer (for appearently no valid reason), so obviously, that override wasn't synchronized with this fix. [1]edd79ff560[2]a28cc6333acloses odoo/odoo#84429 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
@@ -27,6 +27,12 @@ FormRenderer.include({
|
||||
* This is set when arch contains `div.oe_chatter`.
|
||||
*/
|
||||
this._chatterContainerTarget = undefined;
|
||||
/**
|
||||
* This jQuery element will be set when rendering the form view, and
|
||||
* used as a hook to insert the ChatterContainer in the right place,
|
||||
* when applying the rendering into the DOM.
|
||||
*/
|
||||
this.$chatterContainerHook = undefined;
|
||||
// Do not load chatter in form view dialogs
|
||||
this._isFromFormViewDialog = params.isFromFormViewDialog;
|
||||
},
|
||||
@@ -105,12 +111,12 @@ FormRenderer.include({
|
||||
* @returns {jQuery.Element}
|
||||
*/
|
||||
_makeChatterContainerTarget() {
|
||||
if (this._chatterContainerTarget) {
|
||||
return $(this._chatterContainerTarget);
|
||||
if (!this._chatterContainerTarget) {
|
||||
this._chatterContainerTarget = document.createElement("div");
|
||||
this._chatterContainerTarget.classList.add("o_FormRenderer_chatterContainer");
|
||||
}
|
||||
const $el = $('<div class="o_FormRenderer_chatterContainer"/>');
|
||||
this._chatterContainerTarget = $el[0];
|
||||
return $el;
|
||||
this.$chatterContainerHook = $('<div class="o_FormRenderer_chatterContainer"/>');
|
||||
return this.$chatterContainerHook;
|
||||
},
|
||||
/**
|
||||
* Mount the chatter
|
||||
@@ -142,6 +148,18 @@ FormRenderer.include({
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
/**
|
||||
* The last rendering of the form view has just been applied into the DOM,
|
||||
* so we replace our chatter container hook by the actual chatter container.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_updateView() {
|
||||
this._super(...arguments);
|
||||
if (this._hasChatter()) {
|
||||
this.$chatterContainerHook.replaceWith(this._chatterContainerTarget);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Overrides the function to render the chatter once the form view is
|
||||
* rendered.
|
||||
|
||||
@@ -10,8 +10,10 @@ import {
|
||||
} from '@mail/utils/test_utils';
|
||||
|
||||
import config from 'web.config';
|
||||
import fieldRegistry from 'web.field_registry';
|
||||
import FormView from 'web.FormView';
|
||||
import { dom } from 'web.test_utils';
|
||||
import { dom, nextTick } from 'web.test_utils';
|
||||
import { registerCleanup } from "@web/../tests/helpers/cleanup";
|
||||
|
||||
const { triggerEvent } = dom;
|
||||
|
||||
@@ -1048,6 +1050,68 @@ QUnit.test('[TECHNICAL] unfolded read more/less links should not fold on message
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('chatter does not flicker when the form view is re-rendered', async function (assert) {
|
||||
this.data['res.partner'].records.push(
|
||||
{ display_name: "first partner", id: 11 },
|
||||
{ display_name: "second partner", id: 12 }
|
||||
);
|
||||
|
||||
// define an asynchronous field and use it in the form to ease testing
|
||||
let def;
|
||||
const FieldChar = fieldRegistry.get("char");
|
||||
const AsyncWidget = FieldChar.extend({
|
||||
willStart() {
|
||||
return Promise.resolve(def);
|
||||
},
|
||||
});
|
||||
fieldRegistry.add("async_widget", AsyncWidget);
|
||||
registerCleanup(() => {
|
||||
delete fieldRegistry.map.async_widget;
|
||||
});
|
||||
|
||||
await this.createView({
|
||||
data: this.data,
|
||||
hasView: true,
|
||||
// View params
|
||||
View: FormView,
|
||||
model: 'res.partner',
|
||||
arch: `
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="name" widget="async_widget"/>
|
||||
</sheet>
|
||||
<div class="oe_chatter"></div>
|
||||
</form>
|
||||
`,
|
||||
viewOptions: {
|
||||
currentId: 11,
|
||||
ids: [11, 12],
|
||||
},
|
||||
});
|
||||
assert.strictEqual(
|
||||
document.querySelectorAll(`.o_Chatter`).length,
|
||||
1,
|
||||
"there should be a chatter"
|
||||
);
|
||||
def = makeDeferred();
|
||||
document.querySelector('.o_pager_next').click();
|
||||
await nextTick();
|
||||
|
||||
assert.strictEqual(
|
||||
document.querySelectorAll(`.o_Chatter`).length,
|
||||
1,
|
||||
"there should be a chatter"
|
||||
);
|
||||
def.resolve();
|
||||
await nextTick();
|
||||
|
||||
assert.strictEqual(
|
||||
document.querySelectorAll(`.o_Chatter`).length,
|
||||
1,
|
||||
"there should be a chatter"
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,30 +25,7 @@ export default FormRenderer.extend({
|
||||
project_sharing_id: session.project_id,
|
||||
};
|
||||
},
|
||||
_makeChatterContainerTarget() {
|
||||
const $el = $('<div class="o_FormRenderer_chatterContainer"/>');
|
||||
this._chatterContainerTarget = $el[0];
|
||||
return $el;
|
||||
},
|
||||
_mountChatterContainerComponent() {
|
||||
this._chatterContainerComponent.appendTo(this._chatterContainerTarget);
|
||||
},
|
||||
_renderNode(node) {
|
||||
if (node.tag === 'div' && node.attrs.class === 'oe_project_sharing_chatter') {
|
||||
let isVisible = true;
|
||||
if (node.attrs.modifiers && node.attrs.modifiers.invisible) {
|
||||
const record = this._getRecord(this.state.id);
|
||||
if (record) {
|
||||
isVisible = !record.evalModifiers(node.attrs.modifiers).invisible;
|
||||
}
|
||||
}
|
||||
if (isVisible) {
|
||||
if (this._isFromFormViewDialog) {
|
||||
return $('<div/>');
|
||||
}
|
||||
return this._makeChatterContainerTarget();
|
||||
}
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user