Skip to content

Commit 033e5fa

Browse files
committed
fix: prevent duplicate submit buttons in forms
1 parent a4889f5 commit 033e5fa

File tree

4 files changed

+95
-18
lines changed

4 files changed

+95
-18
lines changed

djangocms_form_builder/cms_plugins/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
EmailFieldPlugin,
1111
IntegerFieldPlugin,
1212
SelectPlugin,
13+
SubmitPlugin,
1314
TextareaPlugin,
1415
TimeFieldPlugin,
1516
URLFieldPlugin,
@@ -26,6 +27,7 @@
2627
"EmailFieldPlugin",
2728
"IntegerFieldPlugin",
2829
"SelectPlugin",
30+
"SubmitPlugin",
2931
"TextareaPlugin",
3032
"TimeFieldPlugin",
3133
"URLFieldPlugin",

djangocms_form_builder/cms_plugins/ajax_plugins.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,17 @@ def render(self, context, instance, placeholder):
240240
form = self.get_ajax_form()
241241
context.update(self.set_context(context, instance, placeholder))
242242
context["form_counter"] = context.get("form_counter", 0) + 1
243-
context.update({
244-
"instance": instance,
245-
"form": form,
246-
"uid": f"{instance.id}{getattr(form, 'slug', '')}-{context['form_counter']}",
247-
})
243+
has_submit_button = any(
244+
child.plugin_type == "SubmitPlugin" for child in instance.get_children()
245+
)
246+
context.update(
247+
{
248+
"instance": instance,
249+
"form": form,
250+
"uid": f"{instance.id}{getattr(form, 'slug', '')}-{context['form_counter']}",
251+
"auto_submit": not has_submit_button,
252+
}
253+
)
248254
return context
249255

250256

@@ -290,7 +296,9 @@ def get_parent_classes(cls, slot, page, instance=None):
290296

291297
def get_fieldsets(self, request, obj=None):
292298
fieldsets = super().get_fieldsets(request, obj)
293-
if obj is None or not obj.form_selection: # No Actions if a Django form has been selected
299+
if (
300+
obj is None or not obj.form_selection
301+
): # No Actions if a Django form has been selected
294302
fieldsets = insert_fields(
295303
fieldsets,
296304
("form_actions",),
@@ -362,22 +370,28 @@ def traverse(instance):
362370
meta_options = dict(form_name=self.instance.form_name)
363371
if self.instance.form_floating_labels:
364372
meta_options["floating_labels"] = True
365-
meta_options[
366-
"field_sep"
367-
] = f'{self.instance.form_spacing}'
368-
meta_options[
369-
"redirect"
370-
] = SAME_PAGE_REDIRECT # Default behavior: redirect to same page
373+
meta_options["field_sep"] = f"{self.instance.form_spacing}"
374+
meta_options["redirect"] = (
375+
SAME_PAGE_REDIRECT # Default behavior: redirect to same page
376+
)
371377
meta_options["login_required"] = self.instance.form_login_required
372378
meta_options["unique"] = self.instance.form_unique
373379
form_actions = self.instance.form_actions or "[]"
374380
meta_options["form_actions"] = json.loads(form_actions.replace("'", '"'))
375-
meta_options["form_parameters"] = getattr(self.instance, "action_parameters", {})
381+
meta_options["form_parameters"] = getattr(
382+
self.instance, "action_parameters", {}
383+
)
376384

377-
fields["Meta"] = type("Meta", (), dict(
378-
options=meta_options,
379-
verbose_name=self.instance.form_name.replace("-", " ").replace("_", " ").capitalize(),
380-
)) # Meta class with options and verbose name
385+
fields["Meta"] = type(
386+
"Meta",
387+
(),
388+
dict(
389+
options=meta_options,
390+
verbose_name=self.instance.form_name.replace("-", " ")
391+
.replace("_", " ")
392+
.capitalize(),
393+
),
394+
) # Meta class with options and verbose name
381395

382396
return type(
383397
"FrontendAutoForm",
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
<input type="submit" value="{{ instance.form_submit_message|default:_("Submit") }}" class="btn btn-{{ instance.form_submit_context|default:"primary" }}
1+
{% if auto_submit %}
2+
<input type="submit" value="{{ instance.form_submit_message|default:_("Submit") }}" class="btn btn-{{ instance.form_submit_context|default:"primary" }}">
3+
{% endif %}

tests/test_formeditor.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def test_form_editor(self):
2424
inspect.isclass(cls)
2525
and issubclass(cls, FormElementPlugin)
2626
and not issubclass(cls, cms_plugins.ChoicePlugin)
27+
and cls is not cms_plugins.SubmitPlugin
2728
):
2829
field = add_plugin(
2930
placeholder=self.placeholder,
@@ -48,5 +49,63 @@ def test_form_editor(self):
4849
inspect.isclass(cls)
4950
and issubclass(cls, FormElementPlugin)
5051
and not issubclass(cls, cms_plugins.ChoicePlugin)
52+
and cls is not cms_plugins.SubmitPlugin
5153
):
5254
self.assertContains(response, f'name="field_{item}"')
55+
56+
def test_auto_submit_button_appears_when_no_button(self):
57+
form = add_plugin(
58+
placeholder=self.placeholder,
59+
plugin_type=cms_plugins.FormPlugin.__name__,
60+
language=self.language,
61+
form_selection="",
62+
form_name="test-form",
63+
)
64+
add_plugin(
65+
placeholder=self.placeholder,
66+
plugin_type=cms_plugins.CharFieldPlugin.__name__,
67+
target=form,
68+
language=self.language,
69+
config=dict(
70+
field_name="text_field",
71+
),
72+
)
73+
self.publish(self.page, self.language)
74+
with self.login_user_context(self.superuser):
75+
response = self.client.get(self.request_url)
76+
77+
self.assertEqual(response.status_code, 200)
78+
self.assertEqual(response.content.decode().count('type="submit"'), 1)
79+
80+
def test_auto_submit_button_does_not_appear_when_button_exists(self):
81+
form = add_plugin(
82+
placeholder=self.placeholder,
83+
plugin_type=cms_plugins.FormPlugin.__name__,
84+
language=self.language,
85+
form_selection="",
86+
form_name="test-form",
87+
)
88+
add_plugin(
89+
placeholder=self.placeholder,
90+
plugin_type=cms_plugins.CharFieldPlugin.__name__,
91+
target=form,
92+
language=self.language,
93+
config=dict(
94+
field_name="text_field",
95+
),
96+
)
97+
add_plugin(
98+
placeholder=self.placeholder,
99+
plugin_type=cms_plugins.SubmitPlugin.__name__,
100+
target=form,
101+
language=self.language,
102+
config=dict(
103+
submit_cta="Submit Form",
104+
),
105+
)
106+
self.publish(self.page, self.language)
107+
with self.login_user_context(self.superuser):
108+
response = self.client.get(self.request_url)
109+
110+
self.assertEqual(response.status_code, 200)
111+
self.assertEqual(response.content.decode().count('type="submit"'), 1)

0 commit comments

Comments
 (0)