[FIX] mass_mailing: use another iframe to inline a mailing

This commit fixes two issues:
If the user click on a form tab (e.g. A/B Tests) before `toInline`
finishes, `toInline` would not be able to work properly. The reason
is that a parent element is being removed by owl when changing tab.

Similarly, changing the view from the breadcrumb could save a wrong
version in body_arch as the `toInline` could not fully finish because of
the same reason (a parent element being removed).

To solve that issue, this commit inline the `body_html` from another
iframe appended in the body.
This fix also ensure:
- no stale state for the body_arch
- no dependency of owl rendering lifecycle

task-3052658

X-original-commit: f429e8465adcddac5a24d8e178b39f1d20bfe15c
Part-of: odoo/odoo#112908
This commit is contained in:
Nicolas Bayet
2023-02-16 17:57:18 +01:00
parent a0a0f06ce3
commit 1173733ba7
@@ -4,7 +4,7 @@ import { registry } from "@web/core/registry";
import { _lt } from "@web/core/l10n/translation";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
import { initializeDesignTabCss } from "mass_mailing.design_constants";
import { toInline } from "web_editor.convertInline";
import { toInline, getCSSRules } from "web_editor.convertInline";
import { loadBundle, loadJS } from "@web/core/assets";
import { qweb } from 'web.core';
import { useService } from "@web/core/utils/hooks";
@@ -97,7 +97,7 @@ export class MassMailingHtmlField extends HtmlField {
}
const $editable = this.wysiwyg.getEditable();
const initialHtml = $editable.html();
this.wysiwyg.odooEditor.historyPauseSteps();
await this.wysiwyg.cleanForSave();
await this.wysiwyg.savePendingImages(this.$content);
@@ -107,11 +107,31 @@ export class MassMailingHtmlField extends HtmlField {
$editorEnable.removeClass('editor_enable');
// Prevent history reverts.
this.wysiwyg.odooEditor.observerUnactive('toInline');
await toInline($editable, this.cssRules, this.wysiwyg.$iframe);
const iframe = document.createElement('iframe');
iframe.style.height = '0px';
iframe.style.visibility = 'hidden';
const clonedHtmlNode = $editable[0].closest('html').cloneNode(true);
// Replace the body to only contain the target as we do not care for
// other elements (e.g. sidebar, toolbar, ...)
const clonedBody = clonedHtmlNode.querySelector('body');
const clonedIframeTarget = clonedHtmlNode.querySelector('#iframe_target');
clonedBody.replaceChildren(clonedIframeTarget);
const editableClone = clonedHtmlNode.querySelector('.note-editable');
const iframePromise = new Promise((resolve) => {
iframe.addEventListener("load", resolve);
});
document.body.append(iframe);
iframe.contentDocument.firstChild.replaceWith(clonedHtmlNode);
// Wait for the css and images to be loaded.
await iframePromise;
this.cssRules = this.cssRules || getCSSRules($editable[0].ownerDocument);
await toInline($(editableClone), this.cssRules, $(iframe));
iframe.remove();
this.wysiwyg.odooEditor.observerActive('toInline');
const inlineHtml = $editable.html();
const inlineHtml = editableClone.innerHTML;
$editorEnable.addClass('editor_enable');
this.wysiwyg.odooEditor.resetContent(initialHtml);
this.wysiwyg.odooEditor.historyUnpauseSteps();
this.wysiwyg.odooEditor.historyRevertCurrentStep();
const fieldName = this.props.inlineField;
return this.props.record.update({[fieldName]: this._unWrap(inlineHtml)});