diff --git a/addons/website/static/src/js/utils.js b/addons/website/static/src/js/utils.js
index 3a269e9c9f5..51a1dc37819 100644
--- a/addons/website/static/src/js/utils.js
+++ b/addons/website/static/src/js/utils.js
@@ -414,6 +414,30 @@ function isMobile(self) {
return isMobile;
}
+/**
+ * Returns the parsed data coming from the data-for element for the given form.
+ *
+ * @param {string} formId
+ * @param {HTMLElement} parentEl
+ * @returns {Object|undefined} the parsed data
+ */
+function getParsedDataFor(formId, parentEl) {
+ const dataForEl = parentEl.querySelector(`[data-for='${formId}']`);
+ if (!dataForEl) {
+ return;
+ }
+ return JSON.parse(dataForEl.dataset.values
+ // replaces `True` by `true` if they are after `,` or `:` or `[`
+ .replace(/([,:\[]\s*)True/g, '$1true')
+ // replaces `False` and `None` by `""` if they are after `,` or `:` or `[`
+ .replace(/([,:\[]\s*)(False|None)/g, '$1""')
+ // replaces the `'` by `"` if they are before `,` or `:` or `]` or `}`
+ .replace(/'(\s*[,:\]}])/g, '"$1')
+ // replaces the `'` by `"` if they are after `{` or `[` or `,` or `:`
+ .replace(/([{\[:,]\s*)'/g, '$1"')
+ );
+}
+
export default {
loadAnchors: loadAnchors,
autocompleteWithPages: autocompleteWithPages,
@@ -427,4 +451,5 @@ export default {
generateGMapIframe: generateGMapIframe,
generateGMapLink: generateGMapLink,
isMobile: isMobile,
+ getParsedDataFor: getParsedDataFor,
};
diff --git a/addons/website/static/src/snippets/s_website_form/000.js b/addons/website/static/src/snippets/s_website_form/000.js
index 1fea0d616db..9b94f121110 100644
--- a/addons/website/static/src/snippets/s_website_form/000.js
+++ b/addons/website/static/src/snippets/s_website_form/000.js
@@ -18,6 +18,7 @@ import {
serializeDateTime,
} from "@web/core/l10n/dates";
const { DateTime } = luxon;
+import wUtils from '@website/js/utils';
publicWidget.registry.EditModeWebsiteForm = publicWidget.Widget.extend({
selector: '.s_website_form form, form.s_website_form', // !compatibility
@@ -124,26 +125,17 @@ const { DateTime } = luxon;
// Because, using t-att- inside form make it non-editable
// Data-fill-with attribute is given during registry and is used by
// to know which user data should be used to prfill fields.
- const dataForEl = document.querySelector(`[data-for='${this.el.id}']`);
+ let dataForValues = wUtils.getParsedDataFor(this.el.id, document);
this.editTranslations = !!this._getContext(true).edit_translations;
// On the "edit_translations" mode, a with a translated term
// will replace the attribute value, leading to some inconsistencies
// (setting again the on the attributes after the editor's
// cleanup, setting wrong values on the attributes after translating
// default values...)
- if (!this.editTranslations && (dataForEl || Object.keys(this.preFillValues).length)) {
- const dataForValues = dataForEl ?
- JSON.parse(dataForEl.dataset.values
- // replaces `True` by `true` if they are after `,` or `:` or `[`
- .replace(/([,:\[]\s*)True/g, '$1true')
- // replaces `False` and `None` by `""` if they are after `,` or `:` or `[`
- .replace(/([,:\[]\s*)(False|None)/g, '$1""')
- // replaces the `'` by `"` if they are before `,` or `:` or `]` or `}`
- .replace(/'(\s*[,:\]}])/g, '"$1')
- // replaces the `'` by `"` if they are after `{` or `[` or `,` or `:`
- .replace(/([{\[:,]\s*)'/g, '$1"')
- ) : {};
- const fieldNames = this.$el.serializeArray().map(el => el.name);
+ if (!this.editTranslations
+ && (dataForValues || Object.keys(this.preFillValues).length)) {
+ dataForValues = dataForValues || {};
+ const fieldNames = this.$target.serializeArray().map(el => el.name);
// All types of inputs do not have a value property (eg:hidden),
// for these inputs any function that is supposed to put a value
// property actually puts a HTML value attribute. Because of
diff --git a/addons/website/static/src/snippets/s_website_form/options.js b/addons/website/static/src/snippets/s_website_form/options.js
index fa08489cbbe..51b8072c577 100644
--- a/addons/website/static/src/snippets/s_website_form/options.js
+++ b/addons/website/static/src/snippets/s_website_form/options.js
@@ -9,6 +9,7 @@ import { unique } from "@web/core/utils/arrays";
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
import { formatDate, formatDateTime } from "@web/core/l10n/dates";
+import wUtils from '@website/js/utils';
let currentActionName;
@@ -415,6 +416,14 @@ options.registry.WebsiteFormEditor = FormEditor.extend({
if (!this.$target[0].dataset.model_name) {
proms.push(this._applyFormModel());
}
+ // Get the email_to value from the data-for attribute if it exists. We
+ // use it if there is no value on the email_to input.
+ const formId = this.$target[0].id;
+ const dataForValues = wUtils.getParsedDataFor(formId, this.$target[0].ownerDocument);
+ if (dataForValues) {
+ this.dataForEmailTo = dataForValues['email_to'];
+ }
+ this.defaultEmailToValue = "info@yourcompany.example.com";
return Promise.all(proms);
},
/**
@@ -601,6 +610,16 @@ options.registry.WebsiteFormEditor = FormEditor.extend({
return this.activeForm.id;
case 'addActionField': {
const value = this.$target.find(`.s_website_form_dnone input[name="${params.fieldName}"]`).val();
+ if (params.fieldName === 'email_to') {
+ // For email_to, we try to find a value in this order:
+ // 1. The current value of the input
+ // 2. The data-for value if it exists
+ // 3. The default value (`defaultEmailToValue`)
+ if (value && value !== this.defaultEmailToValue) {
+ return value;
+ }
+ return this.dataForEmailTo || this.defaultEmailToValue;
+ }
if (value) {
return value;
} else {
@@ -672,7 +691,12 @@ options.registry.WebsiteFormEditor = FormEditor.extend({
*/
_addHiddenField: function (value, fieldName) {
this.$target.find(`.s_website_form_dnone:has(input[name="${fieldName}"])`).remove();
- if (value) {
+ // For the email_to field, we keep the field even if it has no value so
+ // that the email is sent to data-for value or to the default email.
+ if (fieldName === 'email_to' && !value && !this.dataForEmailTo) {
+ value = this.defaultEmailToValue;
+ }
+ if (value || fieldName === 'email_to') {
const hiddenField = renderToElement('website.form_field_hidden', {
field: {
name: fieldName,
diff --git a/addons/website/static/tests/tours/website_form_editor.js b/addons/website/static/tests/tours/website_form_editor.js
index 48f8715e2a8..8087354ee5b 100644
--- a/addons/website/static/tests/tours/website_form_editor.js
+++ b/addons/website/static/tests/tours/website_form_editor.js
@@ -590,6 +590,10 @@
content: "Change a random option",
trigger: '[data-set-mark] input',
run: 'text_blur **',
+ }, {
+ content: "Check that the recipient email is correct",
+ trigger: 'we-input[data-field-name="email_to"] input:propValue("website_form_contactus_edition_no_email@mail.com")',
+ isCheck: true,
},
]));
diff --git a/addons/website/tests/test_website_form_editor.py b/addons/website/tests/test_website_form_editor.py
index 445cbb6191c..b807e0b1b62 100644
--- a/addons/website/tests/test_website_form_editor.py
+++ b/addons/website/tests/test_website_form_editor.py
@@ -31,6 +31,7 @@ class TestWebsiteFormEditor(HttpCaseWithUserPortal):
'The email was edited, the form should have been sent to the configured email')
def test_website_form_contact_us_edition_no_email(self):
+ self.env.company.email = 'website_form_contactus_edition_no_email@mail.com'
self.start_tour('/web', 'website_form_contactus_edition_no_email', login="admin")
self.start_tour('/contactus', 'website_form_contactus_submit', login="portal")
mail = self.env['mail.mail'].search([], order='id desc', limit=1)