Skip to content

Commit 40fbd5c

Browse files
AlessandroLupoloco-odoo
authored andcommitted
Mailing List Subscribe Option
1 parent c03a931 commit 40fbd5c

16 files changed

+283
-37
lines changed

addons/html_builder/__manifest__.py

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
'html_builder/static/src/**/*',
4444
('remove', 'html_builder/static/src/website_preview/**/*'),
45-
('remove', 'html_builder/static/src/website_mass_mailing/**/*'),
4645
],
4746
'html_builder.inside_builder_style': [
4847
('include', 'web._assets_helpers'),

addons/html_builder/static/src/core/drop_zone_plugin.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,16 @@ export class DropZonePlugin extends Plugin {
297297
insertMethod = "appendChild";
298298
}
299299
this.clearDropZone();
300-
return (elementToAdd) => {
300+
return async (elementToAdd) => {
301+
// TODO: refactor if a new mutex system is implemented
301302
target[insertMethod](elementToAdd);
302-
this.dispatchTo("on_add_element_handlers", { elementToAdd: elementToAdd });
303+
const proms = [];
304+
for (const handler of this.getResource("on_add_element_handlers")) {
305+
proms.push(handler({ elementToAdd: elementToAdd }));
306+
}
307+
this.services.ui.block();
308+
await proms;
309+
this.services.ui.unblock();
303310
scrollToWindow(elementToAdd, { behavior: "smooth", offset: 50 });
304311
this.dependencies.history.addStep();
305312
};

addons/html_builder/static/src/plugins/background_option/background_option_plugin.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ class BackgroundOptionPlugin extends Plugin {
3535
applyFunDependOnSelectorAndExclude(
3636
this.markColorLevel,
3737
root,
38-
coloredLevelBackgroundParam.selector,
39-
coloredLevelBackgroundParam.exclude
38+
coloredLevelBackgroundParam
4039
);
4140
}
4241
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
export function applyFunDependOnSelectorAndExclude(fn, rootEl, selector, exclude) {
1+
export function applyFunDependOnSelectorAndExclude(fn, rootEl, { selector, exclude, applyTo }) {
22
const closestSelector = rootEl.closest(selector);
33
let editingEls = closestSelector ? [closestSelector] : [...rootEl.querySelectorAll(selector)];
44
if (exclude) {
55
editingEls = editingEls.filter((selectorEl) => !selectorEl.matches(exclude));
66
}
77
for (const editingEl of editingEls) {
8-
fn(editingEl);
8+
const targetEls = applyTo ? editingEl.querySelectorAll(applyTo) : [editingEl];
9+
for (const targetEl of targetEls) {
10+
fn(targetEl);
11+
}
912
}
1013
}

addons/html_builder/static/src/sidebar/block_tab.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,16 @@ export class BlockTab extends Component {
6868
onDrag: ({ element, x, y }) => {
6969
this.dropzonePlugin.dragElement(element, x, y);
7070
},
71-
onDrop: ({ element, x, y }) => {
71+
onDrop: async ({ element, x, y }) => {
7272
const { height, width } = element.getClientRects()[0];
7373

7474
const position = { x, y, height, width };
7575
const { category, snippet } = this.dragState;
7676
if (category === "snippet_groups") {
77-
this.openSnippetDialog(snippet, position);
77+
await this.openSnippetDialog(snippet, position);
7878
return;
7979
}
80-
const addElement = this.dropzonePlugin.getAddElement(position);
80+
const addElement = await this.dropzonePlugin.getAddElement(position);
8181
if (!addElement) {
8282
return;
8383
}
@@ -98,7 +98,7 @@ export class BlockTab extends Component {
9898
return this.env.editor.shared.disableSnippets;
9999
}
100100

101-
openSnippetDialog(snippet, position) {
101+
async openSnippetDialog(snippet, position) {
102102
if (snippet.moduleId) {
103103
return;
104104
}
@@ -107,7 +107,7 @@ export class BlockTab extends Component {
107107
this.dropzonePlugin.getSelectors(snippet);
108108
this.dropzonePlugin.displayDropZone(selectorSiblings, selectorChildren);
109109
}
110-
const addElement = this.dropzonePlugin.getAddElement(position);
110+
const addElement = await this.dropzonePlugin.getAddElement(position);
111111
if (!addElement) {
112112
return;
113113
}

addons/html_builder/static/src/website_builder/plugins/options/process_steps_option_plugin.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ class ProcessStepsOptionPlugin extends Plugin {
1919
// connectors even if there were no step added (e.g: a column of the
2020
// snippet is being resized).
2121
content_updated_handlers: (rootEl) =>
22-
applyFunDependOnSelectorAndExclude(reloadConnectors, rootEl, this.selector),
22+
applyFunDependOnSelectorAndExclude(reloadConnectors, rootEl, {
23+
selector: this.selector,
24+
}),
2325
};
2426
getActions() {
2527
return {

addons/html_builder/static/src/website_builder/plugins/options/table_of_content_option_plugin.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,9 @@ class TableOfContentOptionPlugin extends Plugin {
121121
for (const navbar of root.querySelectorAll(".s_table_of_content_navbar")) {
122122
navbar.setAttribute("contenteditable", "false");
123123
}
124-
applyFunDependOnSelectorAndExclude(
125-
this.updateTableOfContentNavbar.bind(this),
126-
root,
127-
".s_table_of_content_main"
128-
);
124+
applyFunDependOnSelectorAndExclude(this.updateTableOfContentNavbar.bind(this), root, {
125+
selector: ".s_table_of_content_main",
126+
});
129127
}
130128

131129
updateTableOfContentNavbar(tableOfContentMain) {

addons/html_builder/static/src/website_builder/plugins/parallax_option_plugin.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ class WebsiteParallaxPlugin extends Plugin {
8282
applyFunDependOnSelectorAndExclude(
8383
this.removeParallax.bind(this),
8484
rootEl,
85-
backgroundOptionSelector.selector,
86-
backgroundOptionSelector.exclude
85+
backgroundOptionSelector
8786
);
8887
}
8988
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.o_enable_preview {
2+
display: block !important;
3+
}
4+
.o_disable_preview {
5+
display: none !important;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { onWillStart } from "@odoo/owl";
2+
import { BaseOptionComponent } from "@html_builder/core/utils";
3+
4+
export class MailingListSubscribeOption extends BaseOptionComponent {
5+
static template = "html_builder.MailingListSubscribeOption";
6+
static props = {
7+
fetchMailingLists: Function,
8+
};
9+
10+
setup() {
11+
this.mailingLists = [];
12+
onWillStart(async () => {
13+
this.mailingLists = await this.props.fetchMailingLists();
14+
});
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates xml:space="preserve">
3+
4+
<!-- TODO: form_opt dependency -->
5+
6+
<t t-name="html_builder.MailingListSubscribeOption">
7+
8+
<BuilderRow label.translate="Newsletter">
9+
<BuilderSelect dataAttributeAction="'listId'">
10+
<t t-foreach="mailingLists" t-as="item" t-key="item.id">
11+
<BuilderSelectItem dataAttributeActionValue="item.id.toString()">
12+
<t t-out = "item.name"/>
13+
</BuilderSelectItem>
14+
</t>
15+
<t t-if="!mailingLists.length">
16+
<BuilderSelectItem>None</BuilderSelectItem>
17+
</t>
18+
</BuilderSelect>
19+
</BuilderRow>
20+
21+
<BuilderRow label.translate="Display Thanks Message">
22+
<BuilderCheckbox action="'toggleThanksMessage'"/>
23+
</BuilderRow>
24+
25+
</t>
26+
27+
<t t-name="html_builder.MailingListSubscribeFormOption">
28+
29+
<BuilderRow label.translate="Placeholder">
30+
<BuilderTextInput attributeAction="'placeholder'" applyTo="'.s_newsletter_subscribe_form_input'"/>
31+
</BuilderRow>
32+
33+
</t>
34+
35+
</templates>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
2+
import { Plugin } from "@html_editor/plugin";
3+
import { registry } from "@web/core/registry";
4+
import { user } from "@web/core/user";
5+
import { _t } from "@web/core/l10n/translation";
6+
import { NewsletterSubscribeCommonOption } from "./newsletter_subscribe_common_option";
7+
import { getSelectorParams } from "@html_builder/utils/utils";
8+
import { applyFunDependOnSelectorAndExclude } from "@html_builder/plugins/utils";
9+
10+
class MailingListSubscribeOptionPlugin extends Plugin {
11+
static id = "mailingListSubscribeOption";
12+
static dependencies = ["remove", "savePlugin"];
13+
static shared = ["fetchMailingLists"];
14+
resources = {
15+
builder_actions: [
16+
{
17+
toggleThanksMessage: {
18+
apply: ({ editingElement }) => {
19+
this.setThanksMessageVisibility(editingElement, true);
20+
},
21+
clean: ({ editingElement }) => {
22+
this.setThanksMessageVisibility(editingElement, false);
23+
},
24+
isApplied: ({ editingElement }) =>
25+
editingElement
26+
.querySelector(".js_subscribed_wrap")
27+
.classList.contains("o_enable_preview"),
28+
},
29+
},
30+
],
31+
on_add_element_handlers: this.onAddElement.bind(this),
32+
clean_for_save_handlers: this.cleanForSave.bind(this),
33+
};
34+
35+
setup() {
36+
this.mailingListSubscribeOptionSelectorParams = getSelectorParams(
37+
this.getResource("builder_options"),
38+
NewsletterSubscribeCommonOption
39+
);
40+
}
41+
42+
setThanksMessageVisibility(editingElement, isVisible) {
43+
const toSubscribeEl = editingElement.querySelector(".js_subscribe_wrap");
44+
const thanksMessageEl = editingElement.querySelector(".js_subscribed_wrap");
45+
thanksMessageEl.classList.toggle("o_enable_preview", isVisible);
46+
thanksMessageEl.classList.toggle("o_disable_preview", !isVisible);
47+
toSubscribeEl.classList.toggle("o_enable_preview", !isVisible);
48+
toSubscribeEl.classList.toggle("o_disable_preview", isVisible);
49+
}
50+
51+
async onAddElement({ elementToAdd }) {
52+
for (const mailingListSubscribeOptionSelector of this
53+
.mailingListSubscribeOptionSelectorParams) {
54+
applyFunDependOnSelectorAndExclude(
55+
this.addNewsletterListElement.bind(this),
56+
elementToAdd,
57+
mailingListSubscribeOptionSelector
58+
);
59+
}
60+
}
61+
62+
async addNewsletterListElement(elementToAdd) {
63+
await this.fetchMailingLists();
64+
if (this.mailingLists.length) {
65+
elementToAdd.dataset.listId = this.mailingLists[0].id;
66+
} else {
67+
this.services.dialog.add(ConfirmationDialog, {
68+
body: _t(
69+
"No mailing list found, do you want to create a new one? This will save all your changes, are you sure you want to proceed?"
70+
),
71+
confirm: async () => {
72+
await this.dependencies.savePlugin.save();
73+
window.location.href =
74+
"/odoo/action-mass_mailing.action_view_mass_mailing_lists";
75+
},
76+
cancel: () => {
77+
this.dependencies.remove.removeElement(elementToAdd);
78+
},
79+
});
80+
}
81+
}
82+
83+
async fetchMailingLists() {
84+
if (!this.mailingLists) {
85+
const context = Object.assign({}, user.context, {
86+
website_id: this.services.website.currentWebsite.id,
87+
lang: this.services.website.currentWebsite.metadata.lang,
88+
user_lang: user.context.lang,
89+
});
90+
const response = await this.services.orm.call(
91+
"mailing.list",
92+
"name_search",
93+
["", [["is_public", "=", true]]],
94+
{ context }
95+
);
96+
this.mailingLists = [];
97+
for (const entry of response) {
98+
this.mailingLists.push({ id: entry[0], name: entry[1] });
99+
}
100+
}
101+
return this.mailingLists;
102+
}
103+
104+
cleanForSave({ root }) {
105+
for (const mailingListSubscribeOptionSelector of this
106+
.mailingListSubscribeOptionSelectorParams) {
107+
applyFunDependOnSelectorAndExclude(
108+
this.removePreview.bind(this),
109+
root,
110+
mailingListSubscribeOptionSelector
111+
);
112+
}
113+
}
114+
115+
removePreview(editingElement) {
116+
const previewClasses = ["o_disable_preview", "o_enable_preview"];
117+
const toCleanElsSelector = ".js_subscribe_wrap, .js_subscribed_wrap";
118+
const toCleanEls = editingElement.querySelectorAll(toCleanElsSelector);
119+
for (const toCleanEl of toCleanEls) {
120+
toCleanEl.classList.remove(...previewClasses);
121+
}
122+
}
123+
}
124+
125+
registry
126+
.category("website-plugins")
127+
.add(MailingListSubscribeOptionPlugin.id, MailingListSubscribeOptionPlugin);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { BaseOptionComponent } from "@html_builder/core/utils";
2+
import { MailingListSubscribeOption } from "./mailing_list_subscribe_option";
3+
import { RecaptchaSubscribeOption } from "./recaptcha_subscribe_option";
4+
5+
export class NewsletterSubscribeCommonOption extends BaseOptionComponent {
6+
static template = "html_builder.NewsletterSubscribeCommonOption";
7+
static components = {
8+
MailingListSubscribeOption,
9+
RecaptchaSubscribeOption,
10+
};
11+
static props = {
12+
fetchMailingLists: Function,
13+
hasRecaptcha: Function,
14+
};
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<templates xml:space="preserve">
3+
4+
<t t-name="html_builder.NewsletterSubscribeCommonOption">
5+
6+
<MailingListSubscribeOption fetchMailingLists="props.fetchMailingLists"/>
7+
<RecaptchaSubscribeOption hasRecaptcha="props.hasRecaptcha"/>
8+
9+
</t>
10+
11+
</templates>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Plugin } from "@html_editor/plugin";
2+
import { registry } from "@web/core/registry";
3+
import { NewsletterSubscribeCommonOption } from "./newsletter_subscribe_common_option";
4+
5+
class NewsletterSubscribeCommonOptionPlugin extends Plugin {
6+
static id = "newsletterSubscribeCommonOption";
7+
static dependencies = ["mailingListSubscribeOption", "recaptchaSubscribeOption"];
8+
resources = {
9+
builder_options: [
10+
{
11+
OptionComponent: NewsletterSubscribeCommonOption,
12+
props: this.getProps(),
13+
selector: ".s_newsletter_list",
14+
exclude: [
15+
".s_newsletter_block .s_newsletter_list",
16+
".o_newsletter_popup .s_newsletter_list",
17+
".s_newsletter_box .s_newsletter_list",
18+
".s_newsletter_centered .s_newsletter_list",
19+
".s_newsletter_grid .s_newsletter_list",
20+
].join(", "),
21+
},
22+
{
23+
OptionComponent: NewsletterSubscribeCommonOption,
24+
props: this.getProps(),
25+
selector: ".o_newsletter_popup",
26+
applyTo: ".s_newsletter_list",
27+
},
28+
{
29+
template: "html_builder.MailingListSubscribeFormOption",
30+
selector: ".s_newsletter_subscribe_form",
31+
},
32+
],
33+
};
34+
35+
getProps() {
36+
return {
37+
fetchMailingLists: this.dependencies.mailingListSubscribeOption.fetchMailingLists,
38+
hasRecaptcha: this.dependencies.recaptchaSubscribeOption.hasRecaptcha,
39+
};
40+
}
41+
}
42+
43+
registry
44+
.category("website-plugins")
45+
.add(NewsletterSubscribeCommonOptionPlugin.id, NewsletterSubscribeCommonOptionPlugin);

0 commit comments

Comments
 (0)