Skip to content

Commit 7c4053e

Browse files
committed
feat: Remove inline JS code for CSP support
1 parent 6928aa9 commit 7c4053e

File tree

2 files changed

+166
-158
lines changed

2 files changed

+166
-158
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Get the error message from the script tag that loaded this script
2+
function getErrorMessage() {
3+
const currentScript = document.currentScript || document.querySelector('script[src*="ajax_form.js"]');
4+
if (currentScript && currentScript.dataset.errorMsg) {
5+
return currentScript.dataset.errorMsg;
6+
}
7+
return "Network connection or server error. Please try again later. We apologize for the inconvenience.";
8+
}
9+
10+
function djangocms_form_builder_form(form) {
11+
function feedback(node, data) {
12+
if (data.result === 'success') {
13+
node.outerHTML = data.content;
14+
node.style.transition='';
15+
node.style.opacity = 0;
16+
node.style.transition='opacity 0.3s';
17+
node.style.opacity = 1;
18+
} else if (data.result === 'result') {
19+
for (let invalid of node.getElementsByClassName('all-invalid')) {
20+
invalid.classList.add('d-none');
21+
let li = invalid.getElementsByTagName('li');
22+
while (li !== undefined && li.length > 0) {
23+
li[0].remove();
24+
}
25+
}
26+
for (let group of node.getElementsByClassName('.form-group')) {
27+
group.classList.add('has-feedback has-success is-valid');
28+
group.classList.remove('has-error is-invalid');
29+
let invalid = group.getElementsByClassName('invalid-feedback');
30+
while (invalid !== undefined && invalid.length > 0) {
31+
invalid[0].remove();
32+
}
33+
}
34+
if (node.dataset.results) {
35+
let target = document.getElementById(node.dataset.results);
36+
target.innerHTML = data.content;
37+
}
38+
} else if (data.result === 'invalid form') {
39+
for (let invalid of node.getElementsByClassName('all-invalid')) {
40+
invalid.classList.add('d-none');
41+
let li = invalid.getElementsByTagName('li');
42+
while (li !== undefined && li.length > 0) {
43+
li[0].remove();
44+
}
45+
}
46+
let invalid = node.getElementsByClassName('invalid-feedback');
47+
while (invalid !== undefined && invalid.length > 0) {
48+
invalid[0].remove();
49+
}
50+
for (const [key, value] of Object.entries(data.field_errors)) {
51+
for (const err of value) {
52+
if (key.substring(0,7) !== "__all__") {
53+
let msg = document.createElement('template');
54+
msg.innerHTML = "<div class='invalid-feedback'><strong>" + err + "</strong></div>";
55+
document.getElementById(key).after(msg.content);
56+
} else {
57+
let msg = document.createElement('template');
58+
msg.innerHTML = "<li>" + err + "</li>";
59+
for (let invalid of node.getElementsByClassName('all-invalid')) {
60+
invalid.classList.remove('d-none');
61+
let ul = invalid.getElementsByTagName("ul");
62+
if (ul.length > 0) {
63+
ul[0].appendChild(msg.content);
64+
}
65+
}
66+
}
67+
}
68+
}
69+
// make invalid fields visible in collapsed sections
70+
for(let collapse of node.getElementsByClassName('collapse')) {
71+
if (collapse.getElementsByClassName('invalid-feedback').length > 0) {
72+
collapse.classList.add('show');
73+
}
74+
}
75+
node.classList.add('was-validated');
76+
} else if (data.result === 'error') {
77+
alert(data.errors[0]);
78+
}
79+
if ('redirect' in data) {
80+
if (data.redirect !== '' && data.redirect !== 'result') {
81+
window.location.href = data.redirect;
82+
} else if (data.redirect !== '') {
83+
window.location.reload();
84+
}
85+
}
86+
}
87+
88+
function submitEvent(event) {
89+
event.preventDefault();
90+
post_ajax(form);
91+
}
92+
93+
function post_ajax(node) {
94+
fetch(node.getAttribute('action'),{
95+
method: 'POST',
96+
body: new URLSearchParams(new FormData(node)),
97+
}
98+
).then(function (response) {
99+
return response.json();
100+
}
101+
).then(function (data) {
102+
feedback(node, data);
103+
}).catch(function (json) {
104+
console.error(json);
105+
alert(getErrorMessage());
106+
});
107+
}
108+
109+
let recaptcha = form.getElementsByClassName('g-recaptcha');
110+
if (recaptcha.length === 1) {
111+
let submitButton = form.querySelector('input[type="submit"]');
112+
submitButton.setAttribute("disabled", "");
113+
let checkExist = setInterval(function () {
114+
if (window.hasOwnProperty("recaptcha_loaded")) {
115+
clearInterval(checkExist);
116+
submitButton.removeAttribute("disabled");
117+
let gid = grecaptcha.render(recaptcha[0], {
118+
"callback": function (token) {
119+
form.getElementsByClassName("g-recaptcha-response")[0].value = token;
120+
post_ajax(form);
121+
grecaptcha.reset(gid);
122+
},
123+
});
124+
if(!form.dataset.submitEvent) {
125+
form.dataset.submitEvent = true;
126+
form.addEventListener('submit', function (event) {
127+
event.preventDefault();
128+
console.log("recaptcha submit")
129+
grecaptcha.execute(gid);
130+
});
131+
}
132+
}
133+
}, 100);
134+
} else {
135+
if(!form.dataset.submitEvent) {
136+
form.dataset.submitEvent = true;
137+
form.addEventListener('submit', function (event) {
138+
event.preventDefault();
139+
post_ajax(form);
140+
});
141+
}
142+
}
143+
}
144+
145+
function reCaptchaOnLoadCallback() {
146+
window.recaptcha_loaded = true;
147+
};
148+
149+
(function () {
150+
function initForms() {
151+
for (let form of document.getElementsByClassName('djangocms-form-builder-ajax-form')) {
152+
djangocms_form_builder_form(form);
153+
}
154+
}
155+
window.addEventListener('load', initForms);
156+
})();
Lines changed: 10 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% load sekizai_tags i18n form_builder_tags cms_tags %}{% spaceless %}
1+
{% load static sekizai_tags i18n form_builder_tags cms_tags %}{% spaceless %}
22
<div id="data{{ uid }}" class="form-div{% if form.bound %} was-validated{% endif %}">
33
<div class="all-invalid alert alert-block alert-danger d-none">
44
<ul class="m-0">
@@ -12,162 +12,14 @@
1212
{% if instance.child_plugin_instances %}
1313
{% render_recaptcha_widget form %}
1414
{% endif %}
15-
</div>{% endspaceless %}
15+
</div>
16+
{% endspaceless %}
17+
{% addtoblock 'js' %}
18+
<script
19+
data-error-msg="{% translate 'Network connection or server error. Please try again later. We apologize for the inconvenience.' %}"
20+
src="{% static 'djangocms_form_builder/js/ajax_form.js' %}"></script>
21+
{% endaddtoblock %}
22+
1623
{% if instance.config.captcha_widget %}
17-
{% addtoblock 'js' %}{% spaceless %}
18-
<script type="text/javascript">
19-
var reCaptchaOnLoadCallback = function () {
20-
window.recaptcha_loaded = true;
21-
};
22-
</script>
23-
<script src="https://www.google.com/recaptcha/api.js?onload=reCaptchaOnLoadCallback&render=explicit" async defer></script>
24-
{% endspaceless %}{% endaddtoblock %}
24+
{% addtoblock 'js' %}<script src="https://www.google.com/recaptcha/api.js?onload=reCaptchaOnLoadCallback&render=explicit" async defer></script>{% endaddtoblock %}
2525
{% endif %}
26-
{% addtoblock 'js' %}{% spaceless %}
27-
<script>
28-
function djangocms_form_builder_form(form) {
29-
function feedback(node, data) {
30-
console.log(data);
31-
if (data.result === 'success') {
32-
node.outerHTML = data.content;
33-
node.style.transition='';
34-
node.style.opacity = 0;
35-
node.style.transition='opacity 0.3s';
36-
node.style.opacity = 1;
37-
} else if (data.result === 'result') {
38-
for (let invalid of node.getElementsByClassName('all-invalid')) {
39-
invalid.classList.add('d-none');
40-
let li = invalid.getElementsByTagName('li');
41-
while (li !== undefined && li.length > 0) {
42-
li[0].remove();
43-
}
44-
}
45-
for (let group of node.getElementsByClassName('.form-group')) {
46-
group.classList.add('has-feedback has-success is-valid');
47-
group.classList.remove('has-error is-invalid');
48-
let invalid = group.getElementsByClassName('invalid-feedback');
49-
while (invalid !== undefined && invalid.length > 0) {
50-
invalid[0].remove();
51-
}
52-
}
53-
if (node.dataset.results) {
54-
let target = document.getElementById(node.dataset.results);
55-
target.innerHTML = data.content;
56-
}
57-
} else if (data.result === 'invalid form') {
58-
for (let invalid of node.getElementsByClassName('all-invalid')) {
59-
invalid.classList.add('d-none');
60-
let li = invalid.getElementsByTagName('li');
61-
while (li !== undefined && li.length > 0) {
62-
li[0].remove();
63-
}
64-
}
65-
let invalid = node.getElementsByClassName('invalid-feedback');
66-
while (invalid !== undefined && invalid.length > 0) {
67-
invalid[0].remove();
68-
}
69-
for (const [key, value] of Object.entries(data.field_errors)) {
70-
for (const err of value) {
71-
if (key.substring(0,7) !== "__all__") {
72-
let msg = document.createElement('template');
73-
msg.innerHTML = "<div class='invalid-feedback'><strong>" + err + "</strong></div>";
74-
document.getElementById(key).after(msg.content);
75-
} else {
76-
let msg = document.createElement('template');
77-
msg.innerHTML = "<li>" + err + "</li>";
78-
for (let invalid of node.getElementsByClassName('all-invalid')) {
79-
invalid.classList.remove('d-none');
80-
let ul = invalid.getElementsByTagName("ul");
81-
if (ul.length > 0) {
82-
ul[0].appendChild(msg.content);
83-
}
84-
}
85-
}
86-
}
87-
}
88-
// make invalid fields visible in collapsed sections
89-
for(let collapse of node.getElementsByClassName('collapse')) {
90-
if (collapse.getElementsByClassName('invalid-feedback').length > 0) {
91-
collapse.classList.add('show');
92-
}
93-
}
94-
node.classList.add('was-validated');
95-
} else if (data.result === 'error') {
96-
alert(data.errors[0]);
97-
}
98-
if ('redirect' in data) {
99-
if (data.redirect !== '' && data.redirect !== 'result') {
100-
window.location.href = data.redirect;
101-
} else if (data.redirect !== '') {
102-
window.location.reload();
103-
}
104-
}
105-
}
106-
107-
function post_ajax(node) {
108-
fetch(node.getAttribute('action'),{
109-
method: 'POST',
110-
body: new URLSearchParams(new FormData(node)),
111-
}
112-
).then(function (response) {
113-
return response.json();
114-
}
115-
).then(function (data) {
116-
feedback(node, data);
117-
}).catch(function (json) {
118-
console.log(json);
119-
alert("{% trans 'Network connection or server error. Please try again later. We apologize for the inconvenience.' %}");
120-
});
121-
}
122-
123-
let recaptcha = form.getElementsByClassName('g-recaptcha');
124-
if (recaptcha.length === 1) {
125-
let submitButton = form.querySelector('input[type="submit"]');
126-
submitButton.setAttribute("disabled", "");
127-
let checkExist = setInterval(function () {
128-
if (window.hasOwnProperty("recaptcha_loaded")) {
129-
clearInterval(checkExist);
130-
submitButton.removeAttribute("disabled");
131-
let gid = grecaptcha.render(recaptcha[0], {
132-
"callback": function (token) {
133-
form.getElementsByClassName("g-recaptcha-response")[0].value = token;
134-
post_ajax(form);
135-
grecaptcha.reset(gid);
136-
},
137-
});
138-
if(!form.dataset.submitEvent) {
139-
form.dataset.submitEvent = true;
140-
form.addEventListener('submit', function (event) {
141-
event.preventDefault();
142-
console.log("recaptcha submit")
143-
grecaptcha.execute(gid);
144-
});
145-
}
146-
}
147-
}, 100);
148-
} else {
149-
if(!form.dataset.submitEvent) {
150-
form.dataset.submitEvent = true;
151-
form.addEventListener('submit', function (event) {
152-
event.preventDefault();
153-
post_ajax(form);
154-
});
155-
}
156-
}
157-
}
158-
</script>
159-
{% endspaceless %}{% endaddtoblock %}
160-
{% addtoblock 'js' %}<script>
161-
(function () {
162-
function initForms() {
163-
for (let form of document.getElementsByClassName('djangocms-form-builder-ajax-form')) {
164-
165-
djangocms_form_builder_form(form);
166-
}
167-
}
168-
window.addEventListener('DOMContentLoaded', initForms);
169-
{% if request.toolbar and request.toolbar.edit_mode_active %}
170-
CMS.$(window).on('cms-content-refresh', initForms);
171-
{% endif %}
172-
})();
173-
</script>{% endaddtoblock %}

0 commit comments

Comments
 (0)