diff --git a/.gitignore b/.gitignore
index 9f97022..8c1be6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,11 @@
-target/
\ No newline at end of file
+target/
+demo/lib
+demo/logs
+demo/modules
+demo/hosts/demo/modules_data
+demo/cms.pid
+demo/*.jar
+demo/LICENSE
+demo/log4j2.xml
+demo/README.md
+demo/server.yaml
\ No newline at end of file
diff --git a/demo/hosts/demo/assets/favicon.ico b/demo/hosts/demo/assets/favicon.ico
new file mode 100644
index 0000000..6848441
Binary files /dev/null and b/demo/hosts/demo/assets/favicon.ico differ
diff --git a/demo/hosts/demo/assets/form-1.css b/demo/hosts/demo/assets/form-1.css
new file mode 100644
index 0000000..df4d6dc
--- /dev/null
+++ b/demo/hosts/demo/assets/form-1.css
@@ -0,0 +1,3 @@
+span#reloadCaptcha:hover {
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/demo/hosts/demo/assets/form-1.js b/demo/hosts/demo/assets/form-1.js
new file mode 100644
index 0000000..618a3db
--- /dev/null
+++ b/demo/hosts/demo/assets/form-1.js
@@ -0,0 +1,105 @@
+// form.js
+const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+const generateString = (length) => {
+ let result = ''
+ const charactersLength = characters.length
+ for (let i = 0; i < length; i++) {
+ result += characters.charAt(Math.floor(Math.random() * charactersLength))
+ }
+
+ return result;
+}
+
+const validateCaptcha = async (event) => {
+ event.preventDefault();
+ let request = {
+ code: document.getElementById("inputCaptcha").value,
+ key: document.getElementById("captchaKey").value
+ }
+
+ const response = await fetch('/module/forms-module/captcha/validate', {
+ method: 'POST',
+ body: JSON.stringify(request)
+ })
+
+ const validationResponse = await response.json()
+
+ if (!validationResponse.valid) {
+ alert("captcha code is not valid")
+ event.preventDefault()
+ return false
+ } else {
+ console.log(event.target)
+ event.target.submit()
+ return true
+ }
+}
+
+const ajaxValidateCaptcha = async () => {
+ let request = {
+ code: document.getElementById("inputCaptcha").value,
+ key: document.getElementById("captchaKey").value
+ }
+
+ const response = await fetch('/module/forms-module/captcha/validate', {
+ method: 'POST',
+ body: JSON.stringify(request)
+ })
+
+ const validationResponse = await response.json()
+
+ if (!validationResponse.valid) {
+ return false
+ } else {
+ return true
+ }
+}
+
+document.addEventListener("DOMContentLoaded", () => {
+ if (document.getElementById("reloadCaptcha")) {
+ document.getElementById("reloadCaptcha").addEventListener("click", () => {
+ let href = new URL(document.getElementById("captchaImg").src)
+ let key = generateString(8)
+ href.searchParams.set('key', key)
+
+ document.getElementById("captchaKey").value = key
+ document.getElementById("captchaImg").src = href.toString()
+ })
+ }
+
+ if (document.getElementById("ajaxForm")) {
+ document.getElementById("ajaxForm").addEventListener("submit", (event) => {
+ event.preventDefault()
+ console.log("send form via ajax")
+ if (!ajaxValidateCaptcha()) {
+ alert("invalid captcha provided");
+ return false
+ }
+ var form = event.target;
+ var formData = new FormData(form);
+ fetch(form.action, {
+ method: "post",
+ body: formData
+ }).then(res => res.json()).then(console.log);
+
+ return false
+ })
+ document.getElementById("submit-btn-test").addEventListener("click", (event) => {
+ event.preventDefault()
+
+ if (ajaxValidateCaptcha()) {
+ alert("invalid captcha provided");
+ return false
+ }
+
+ var form = document.getElementById("ajaxForm")
+ var formData = new FormData(form);
+ fetch(form.action, {
+ method: "post",
+ body: formData
+ }).then(res => res.json()).then(console.log);
+ return false;
+ })
+ }
+
+})
diff --git a/demo/hosts/demo/assets/images/test.jpg b/demo/hosts/demo/assets/images/test.jpg
new file mode 100644
index 0000000..e473243
Binary files /dev/null and b/demo/hosts/demo/assets/images/test.jpg differ
diff --git a/demo/hosts/demo/config/forms.yaml b/demo/hosts/demo/config/forms.yaml
new file mode 100644
index 0000000..e73dc41
--- /dev/null
+++ b/demo/hosts/demo/config/forms.yaml
@@ -0,0 +1,19 @@
+mail:
+ smtp:
+ hostname: 127.0.0.1
+ port: 3025
+ username: test@example.test
+ password: password
+forms:
+ - name: contact
+ to: contact@example.com
+ subject: Ich suche Kontakt!
+ fields: [message]
+ redirects:
+ success: /forms/contact/success
+ - name: test-form
+ fields: [message]
+ redirects:
+ success: /forms/contact/success
+redirects:
+ error: /forms/error
\ No newline at end of file
diff --git a/demo/hosts/demo/content/.technical/404.md b/demo/hosts/demo/content/.technical/404.md
new file mode 100644
index 0000000..776ccf0
--- /dev/null
+++ b/demo/hosts/demo/content/.technical/404.md
@@ -0,0 +1,5 @@
+---
+title: Leider nichts gefunden
+template: error.html
+---
+Da haben wir leider nichts gefunden!
diff --git a/demo/hosts/demo/content/ajax.md b/demo/hosts/demo/content/ajax.md
new file mode 100644
index 0000000..39c4454
--- /dev/null
+++ b/demo/hosts/demo/content/ajax.md
@@ -0,0 +1,8 @@
+---
+title: Startseite
+template: ajax.html
+search:
+ index: false
+---
+
+# Demo Project
diff --git a/demo/hosts/demo/content/contact.md b/demo/hosts/demo/content/contact.md
new file mode 100644
index 0000000..5762410
--- /dev/null
+++ b/demo/hosts/demo/content/contact.md
@@ -0,0 +1,8 @@
+---
+title: Startseite
+template: contact.html
+search:
+ index: false
+---
+
+# Demo Project
diff --git a/demo/hosts/demo/content/forms/contact/success.md b/demo/hosts/demo/content/forms/contact/success.md
new file mode 100644
index 0000000..f39443c
--- /dev/null
+++ b/demo/hosts/demo/content/forms/contact/success.md
@@ -0,0 +1,8 @@
+---
+title: Form submitted
+template: form-submitted.html
+menu:
+ visible: false
+---
+
+## Your request was successfully submitted
diff --git a/demo/hosts/demo/content/forms/error.md b/demo/hosts/demo/content/forms/error.md
new file mode 100644
index 0000000..64cfe1f
--- /dev/null
+++ b/demo/hosts/demo/content/forms/error.md
@@ -0,0 +1,8 @@
+---
+title: Error sending form
+template: form-submitted.html
+menu:
+ visible: false
+---
+
+## Error submitting your request!
\ No newline at end of file
diff --git a/demo/hosts/demo/content/index.md b/demo/hosts/demo/content/index.md
new file mode 100644
index 0000000..66c4067
--- /dev/null
+++ b/demo/hosts/demo/content/index.md
@@ -0,0 +1,8 @@
+---
+title: Startseite
+template: page.html
+search:
+ index: false
+---
+
+# Demo Project
diff --git a/demo/hosts/demo/content/robots.txt b/demo/hosts/demo/content/robots.txt
new file mode 100644
index 0000000..aadfde9
--- /dev/null
+++ b/demo/hosts/demo/content/robots.txt
@@ -0,0 +1,3 @@
+User-agent: *
+Disallow: /about/impressum
+Allow: /
\ No newline at end of file
diff --git a/demo/hosts/demo/extensions/test.extension.js b/demo/hosts/demo/extensions/test.extension.js
new file mode 100644
index 0000000..bb628f6
--- /dev/null
+++ b/demo/hosts/demo/extensions/test.extension.js
@@ -0,0 +1,6 @@
+import { $hooks } from 'system/hooks.mjs';
+
+$hooks.registerAction("forms/test-form/submit", (context) => {
+ console.log("test-form submitted", context);
+ return null;
+})
\ No newline at end of file
diff --git a/demo/hosts/demo/site.yaml b/demo/hosts/demo/site.yaml
new file mode 100644
index 0000000..3325c8e
--- /dev/null
+++ b/demo/hosts/demo/site.yaml
@@ -0,0 +1,28 @@
+id: demo-site
+hostname:
+ - localhost
+baseurl: "http://localhost:1010"
+language: en
+template:
+ engine: thymeleaf
+modules:
+ active:
+ - thymeleaf-module
+ - forms-module
+media:
+ formats:
+ - name: small
+ width: 256
+ height: 256
+ format: webp
+ compression: true
+ - name: big
+ width: 512
+ height: 512
+ format: webp
+ compression: true
+ - name: test2
+ width: 72
+ height: 72
+ format: webp
+ compression: true
\ No newline at end of file
diff --git a/demo/hosts/demo/templates/ajax.html b/demo/hosts/demo/templates/ajax.html
new file mode 100644
index 0000000..2760a19
--- /dev/null
+++ b/demo/hosts/demo/templates/ajax.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/hosts/demo/templates/contact.html b/demo/hosts/demo/templates/contact.html
new file mode 100644
index 0000000..2a07bfc
--- /dev/null
+++ b/demo/hosts/demo/templates/contact.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contact form
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/hosts/demo/templates/form-submitted.html b/demo/hosts/demo/templates/form-submitted.html
new file mode 100644
index 0000000..4936a77
--- /dev/null
+++ b/demo/hosts/demo/templates/form-submitted.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/hosts/demo/templates/libs/fragments.html b/demo/hosts/demo/templates/libs/fragments.html
new file mode 100644
index 0000000..ed7ee6f
--- /dev/null
+++ b/demo/hosts/demo/templates/libs/fragments.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/hosts/demo/templates/page.html b/demo/hosts/demo/templates/page.html
new file mode 100644
index 0000000..4c89e20
--- /dev/null
+++ b/demo/hosts/demo/templates/page.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Test Formular
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c93cd47..c949d56 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.condation.cms.modules
forms-module
- 2.0.0
+ 2.1.0
jar
UTF-8
@@ -14,7 +14,7 @@
forms module
NORMAL
- 6.0.0-SNAPSHOT
+ 6.1.0
21
21
diff --git a/src/main/java/com/condation/cms/modules/forms/FormsConfig.java b/src/main/java/com/condation/cms/modules/forms/FormsConfig.java
index fc9e943..d89f450 100644
--- a/src/main/java/com/condation/cms/modules/forms/FormsConfig.java
+++ b/src/main/java/com/condation/cms/modules/forms/FormsConfig.java
@@ -24,6 +24,7 @@
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import lombok.Data;
@@ -47,10 +48,11 @@ public Optional