avalynx-form 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Juergen Schwind an the Avalynx-Form Authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # AvalynxForm
2
+
3
+ AvalynxForm is a lightweight, customizable form handling library for web applications. Based on Bootstrap >=5.3 without any framework dependencies.
4
+
5
+ ## Features
6
+
7
+ - **Form Handling**: Simplifies the process of creating and managing forms in your web applications.
8
+ - **Bootstrap Integration**: Designed for seamless integration with Bootstrap >= 5.3.
9
+ - **Easy to Use**: Simple API for creating and managing forms within your web applications.
10
+
11
+ ## Example
12
+
13
+ Here's a simple example of how to use AvalynxForm in your project:
14
+
15
+ * [Overview](https://avalynx-form.jbs-newmedia.de/examples/index.html)
16
+ * [Form](https://avalynx-form.jbs-newmedia.de/examples/form.html)
17
+
18
+ ## Installation
19
+
20
+ To use AvalynxForm in your project, you can directly include it in your HTML file. Ensure you have Bootstrap 5.3 or higher included in your project for AvalynxForm to work correctly.
21
+
22
+ First, include Bootstrap:
23
+
24
+ ```html
25
+ <!-- Bootstrap -->
26
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3/dist/css/bootstrap.min.css" rel="stylesheet">
27
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3/dist/js/bootstrap.bundle.min.js"></script>
28
+ ```
29
+
30
+ Then, include AvalynxForm:
31
+
32
+ ```html
33
+ <script src="path/to/avalynx-form.js"></script>
34
+ ```
35
+
36
+ Replace `path/to/avalynx-form.js` with the actual path to the file in your project.
37
+
38
+ ## Installation via jsDelivr ([Link](https://cdn.jsdelivr.net/npm/avalynx-form/))
39
+
40
+ AvalynxForm is also available via [jsDelivr](https://www.jsdelivr.com/). You can include it in your project like this:
41
+
42
+ ```html
43
+ <script src="https://cdn.jsdelivr.net/npm/avalynx-form@0.0.1/dist/js/avalynx-form.js"></script>
44
+ ```
45
+
46
+ Make sure to also include Bootstrap's JS/CSS in your project to ensure AvalynxForm displays correctly.
47
+
48
+ ## Installation via NPM ([Link](https://www.npmjs.com/package/avalynx-form))
49
+
50
+ AvalynxForm is also available as a npm package. You can add it to your project with the following command:
51
+
52
+ ```bash
53
+ npm install avalynx-form
54
+ ```
55
+
56
+ After installing, you can import AvalynxForm into your JavaScript file like this:
57
+
58
+ ```javascript
59
+ import { AvalynxForm } from 'avalynx-form';
60
+ ```
61
+
62
+ Make sure to also include Bootstrap's JS/CSS in your project to ensure AvalynxForm displays correctly.
63
+
64
+ ## Installation via Symfony AssetMapper
65
+
66
+ ```bash
67
+ php bin/console importmap:require avalynx-form
68
+ ```
69
+
70
+ After installing, you can import AvalynxForm into your JavaScript file like this:
71
+
72
+ ```javascript
73
+ import { AvalynxForm } from 'avalynx-form';
74
+ ```
75
+
76
+ Make sure to also include Bootstrap's JS/CSS in your project to ensure AvalynxForm displays correctly.
77
+
78
+ ## Installation via Composer ([Link](https://packagist.org/packages/avalynx/avalynx-form))
79
+
80
+ AvalynxForm is also available as a Composer package. You can add it to your project with the following command:
81
+
82
+ ```bash
83
+ composer require avalynx/avalynx-form
84
+ ```
85
+
86
+ After installing, you can import AvalynxForm into your HTML file like this:
87
+
88
+ ```html
89
+ <script src="vendor/avalynx/avalynx-form/dist/js/avalynx-form.js"></script>
90
+ ```
91
+
92
+ Make sure to also include Bootstrap's JS/CSS in your project to ensure AvalynxForm displays correctly.
93
+
94
+ ## Usage
95
+
96
+ To use AvalynxForm in your project, include the AvalynxForm JavaScript file in your project and initialize the class with the appropriate selector.
97
+
98
+ ```javascript
99
+ new AvalynxForm("#myForm", {
100
+ apiParams: {
101
+ extraData1: 'value1',
102
+ extraData2: 'value2'
103
+ },
104
+ onSuccess: function(response) {
105
+ console.log('Form submission was successful:', response);
106
+ },
107
+ onError: function(response) {
108
+ console.error('Form submission failed:', response);
109
+ }
110
+ });
111
+ ```
112
+
113
+ ## Options
114
+
115
+ AvalynxForm allows the following options for customization:
116
+
117
+ - `id`: (string) The ID of the element to attach the form to.
118
+ - `options`: An object containing the following keys:
119
+ - `apiParams`: (object) Additional parameters to be sent with the form data (default: `{}`).
120
+ - `loader`: (object) An instance of AvalynxLoader to use as the loader for the modal (default: `null`).
121
+ - `onSuccess`: (function) A callback function to be executed when the form submission is successful (default: `null`).
122
+ - `onError`: (function) A callback function to be executed when the form submission fails (default: `null`).
123
+
124
+ ## Contributing
125
+
126
+ Contributions are welcome! If you'd like to contribute, please fork the repository and submit a pull request with your changes or improvements. We're looking for contributions in the following areas:
127
+
128
+ - Bug fixes
129
+ - Feature enhancements
130
+ - Documentation improvements
131
+
132
+ Before submitting your pull request, please ensure your changes are well-documented and follow the existing coding style of the project.
133
+
134
+ ## License
135
+
136
+ AvalynxForm is open-sourced software licensed under the [MIT license](LICENSE).
137
+
138
+ ## Contact
139
+
140
+ If you have any questions, feature requests, or issues, please open an issue on our [GitHub repository](https://github.com/avalynx/avalynx-form/issues) or submit a pull request.
141
+
142
+ Thank you for considering AvalynxForm for your project!
@@ -0,0 +1,177 @@
1
+ /**
2
+ * AvalynxForm
3
+ *
4
+ * AvalynxForm is a lightweight, customizable form handling library for web applications. Based on Bootstrap >=5.3 without any framework dependencies.
5
+ *
6
+ * @version 0.0.1
7
+ * @license MIT
8
+ * @author https://github.com/avalynx/avalynx-datatable/graphs/contributors
9
+ * @website https://github.com/avalynx/
10
+ * @repository https://github.com/avalynx/avalynx-datatable.git
11
+ * @bugs https://github.com/avalynx/avalynx-datatable/issues
12
+ *
13
+ * @param {string} id - The ID of the element to attach the form to.
14
+ * @param {object} options - An object containing the following keys:
15
+ * @param {object} options.apiParams - Additional parameters to be sent with the form data (default: `{}`).
16
+ * @param {object} options.loader - An instance of AvalynxLoader to use as the loader for the modal (default: `null`).
17
+ * @param {function} options.onSuccess - A callback function to be executed when the form submission is successful (default: `null`).
18
+ * @param {function} options.onError - A callback function to be executed when the form submission fails (default: `null`).
19
+ *
20
+ */
21
+
22
+ export class AvalynxForm {
23
+ constructor(id, options = {}) {
24
+ this.form = document.getElementById(id);
25
+ if (this.form === null) {
26
+ console.error("AvalynxForm: Element with id '" + id + "' not found");
27
+ return;
28
+ }
29
+ this.id = id;
30
+ this.options = {
31
+ apiParams: {},
32
+ loader: null,
33
+ onSuccess: null,
34
+ onError: null,
35
+ ...options
36
+ };
37
+ this.init();
38
+ }
39
+
40
+ init() {
41
+ this.setupSubmitHandler();
42
+ this.setupOverlayAndLoader();
43
+ }
44
+
45
+ setupSubmitHandler() {
46
+ this.form.addEventListener('submit', (event) => {
47
+ event.preventDefault();
48
+ this.sendAjaxRequest();
49
+ });
50
+ }
51
+
52
+ async sendAjaxRequest() {
53
+ const action = this.form.action;
54
+ const method = this.form.method.toUpperCase();
55
+
56
+ const formData = new FormData(this.form);
57
+
58
+ for (const [key, value] of Object.entries(this.options.apiParams)) {
59
+ formData.append(key, value);
60
+ }
61
+
62
+ try {
63
+ if (this.options.loader === null) {
64
+ const overlay = document.getElementById(`${this.id}-overlay`);
65
+ overlay.style.display = 'flex';
66
+ } else {
67
+ this.options.loader.load = true;
68
+ }
69
+
70
+ const response = await fetch(action, {
71
+ method: method,
72
+ body: formData,
73
+ });
74
+
75
+ const result = await response.json();
76
+ this.handleResponse(result);
77
+ } catch (error) {
78
+ console.error('Error during AJAX request:', error);
79
+ } finally {
80
+ if (this.options.loader === null) {
81
+ const overlay = document.getElementById(`${this.id}-overlay`);
82
+ if (overlay) {
83
+ overlay.style.display = 'none';
84
+ }
85
+ } else {
86
+ this.options.loader.load = false;
87
+ }
88
+ }
89
+ }
90
+
91
+ handleResponse(response) {
92
+ if (response.debug_msg !== undefined) {
93
+ alert(response.debug_msg);
94
+ }
95
+ if ((response.success !== undefined) && (response.success === true)) {
96
+ if (this.options.onSuccess) {
97
+ this.options.onSuccess(response);
98
+ }
99
+
100
+ if (response.redirect !== undefined) {
101
+ window.location.href = response.redirect;
102
+ }
103
+ } else {
104
+ if (response.invalid !== undefined) {
105
+ for (const [key, value] of Object.entries(response.invalid)) {
106
+ this.showInvalidFeedback(key, value);
107
+ }
108
+ }
109
+
110
+ if (response.valid !== undefined) {
111
+ for (const [key, value] of Object.entries(response.valid)) {
112
+ this.clearInvalidFeedback(key);
113
+ }
114
+ }
115
+
116
+ if (this.options.onError) {
117
+ this.options.onError(response);
118
+ }
119
+ }
120
+ }
121
+
122
+ showInvalidFeedback(key, value) {
123
+ const elements = document.querySelectorAll(`#${key}, [name="${key}"], [name="${key}[]"], [name^="${key}["]`);
124
+ elements.forEach(element => {
125
+ const parentElement = element.closest('.form-group') || element.parentElement;
126
+ if (parentElement !== null) {
127
+ const spanElement = parentElement.querySelector('.invalid-feedback');
128
+ element.classList.add('is-invalid');
129
+ if (spanElement !== null) {
130
+ spanElement.innerHTML = value;
131
+ spanElement.style.display = 'block';
132
+ }
133
+ }
134
+ });
135
+ }
136
+
137
+ clearInvalidFeedback(key) {
138
+ const elements = document.querySelectorAll(`#${key}, [name="${key}"], [name="${key}[]"], [name^="${key}["]`);
139
+ elements.forEach(element => {
140
+ const parentElement = element.closest('.form-group') || element.parentElement;
141
+ if (parentElement !== null) {
142
+ const spanElement = parentElement.querySelector('.invalid-feedback');
143
+ element.classList.remove('is-invalid');
144
+ if (spanElement !== null) {
145
+ spanElement.innerHTML = "&nbsp;";
146
+ spanElement.style.display = 'none';
147
+ }
148
+ }
149
+ });
150
+ }
151
+
152
+ setupOverlayAndLoader() {
153
+ if (this.options.loader === null) {
154
+ this.form.style.position = 'relative';
155
+ const overlay = document.createElement('div');
156
+ overlay.id = `${this.id}-overlay`;
157
+ overlay.style.position = 'absolute';
158
+ overlay.style.top = 0;
159
+ overlay.style.left = 0;
160
+ overlay.style.width = '100%';
161
+ overlay.style.height = '100%';
162
+ overlay.style.display = 'none';
163
+ overlay.style.alignItems = 'center';
164
+ overlay.style.justifyContent = 'center';
165
+ overlay.style.backgroundColor = 'rgba(var(--bs-body-bg-rgb, 0, 0, 0), 0.7)';
166
+ overlay.style.zIndex = '1000';
167
+
168
+ const spinner = document.createElement('div');
169
+ spinner.className = 'spinner-border text-primary';
170
+ spinner.role = 'status';
171
+ spinner.innerHTML = '<span class="visually-hidden">Loading...</span>';
172
+
173
+ overlay.appendChild(spinner);
174
+ this.form.appendChild(overlay);
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * AvalynxForm
3
+ *
4
+ * AvalynxForm is a lightweight, customizable form handling library for web applications. Based on Bootstrap >=5.3 without any framework dependencies.
5
+ *
6
+ * @version 0.0.1
7
+ * @license MIT
8
+ * @author https://github.com/avalynx/avalynx-datatable/graphs/contributors
9
+ * @website https://github.com/avalynx/
10
+ * @repository https://github.com/avalynx/avalynx-datatable.git
11
+ * @bugs https://github.com/avalynx/avalynx-datatable/issues
12
+ *
13
+ * @param {string} id - The ID of the element to attach the form to.
14
+ * @param {object} options - An object containing the following keys:
15
+ * @param {object} options.apiParams - Additional parameters to be sent with the form data (default: `{}`).
16
+ * @param {object} options.loader - An instance of AvalynxLoader to use as the loader for the modal (default: `null`).
17
+ * @param {function} options.onSuccess - A callback function to be executed when the form submission is successful (default: `null`).
18
+ * @param {function} options.onError - A callback function to be executed when the form submission fails (default: `null`).
19
+ *
20
+ */
21
+
22
+ class AvalynxForm {
23
+ constructor(id, options = {}) {
24
+ this.form = document.getElementById(id);
25
+ if (this.form === null) {
26
+ console.error("AvalynxForm: Element with id '" + id + "' not found");
27
+ return;
28
+ }
29
+ this.id = id;
30
+ this.options = {
31
+ apiParams: {},
32
+ loader: null,
33
+ onSuccess: null,
34
+ onError: null,
35
+ ...options
36
+ };
37
+ this.init();
38
+ }
39
+
40
+ init() {
41
+ this.setupSubmitHandler();
42
+ this.setupOverlayAndLoader();
43
+ }
44
+
45
+ setupSubmitHandler() {
46
+ this.form.addEventListener('submit', (event) => {
47
+ event.preventDefault();
48
+ this.sendAjaxRequest();
49
+ });
50
+ }
51
+
52
+ async sendAjaxRequest() {
53
+ const action = this.form.action;
54
+ const method = this.form.method.toUpperCase();
55
+
56
+ const formData = new FormData(this.form);
57
+
58
+ for (const [key, value] of Object.entries(this.options.apiParams)) {
59
+ formData.append(key, value);
60
+ }
61
+
62
+ try {
63
+ if (this.options.loader === null) {
64
+ const overlay = document.getElementById(`${this.id}-overlay`);
65
+ overlay.style.display = 'flex';
66
+ } else {
67
+ this.options.loader.load = true;
68
+ }
69
+
70
+ const response = await fetch(action, {
71
+ method: method,
72
+ body: formData,
73
+ });
74
+
75
+ const result = await response.json();
76
+ this.handleResponse(result);
77
+ } catch (error) {
78
+ console.error('Error during AJAX request:', error);
79
+ } finally {
80
+ if (this.options.loader === null) {
81
+ const overlay = document.getElementById(`${this.id}-overlay`);
82
+ if (overlay) {
83
+ overlay.style.display = 'none';
84
+ }
85
+ } else {
86
+ this.options.loader.load = false;
87
+ }
88
+ }
89
+ }
90
+
91
+ handleResponse(response) {
92
+ if (response.debug_msg !== undefined) {
93
+ alert(response.debug_msg);
94
+ }
95
+ if ((response.success !== undefined) && (response.success === true)) {
96
+ if (this.options.onSuccess) {
97
+ this.options.onSuccess(response);
98
+ }
99
+
100
+ if (response.redirect !== undefined) {
101
+ window.location.href = response.redirect;
102
+ }
103
+ } else {
104
+ if (response.invalid !== undefined) {
105
+ for (const [key, value] of Object.entries(response.invalid)) {
106
+ this.showInvalidFeedback(key, value);
107
+ }
108
+ }
109
+
110
+ if (response.valid !== undefined) {
111
+ for (const [key, value] of Object.entries(response.valid)) {
112
+ this.clearInvalidFeedback(key);
113
+ }
114
+ }
115
+
116
+ if (this.options.onError) {
117
+ this.options.onError(response);
118
+ }
119
+ }
120
+ }
121
+
122
+ showInvalidFeedback(key, value) {
123
+ const elements = document.querySelectorAll(`#${key}, [name="${key}"], [name="${key}[]"], [name^="${key}["]`);
124
+ elements.forEach(element => {
125
+ const parentElement = element.closest('.form-group') || element.parentElement;
126
+ if (parentElement !== null) {
127
+ const spanElement = parentElement.querySelector('.invalid-feedback');
128
+ element.classList.add('is-invalid');
129
+ if (spanElement !== null) {
130
+ spanElement.innerHTML = value;
131
+ spanElement.style.display = 'block';
132
+ }
133
+ }
134
+ });
135
+ }
136
+
137
+ clearInvalidFeedback(key) {
138
+ const elements = document.querySelectorAll(`#${key}, [name="${key}"], [name="${key}[]"], [name^="${key}["]`);
139
+ elements.forEach(element => {
140
+ const parentElement = element.closest('.form-group') || element.parentElement;
141
+ if (parentElement !== null) {
142
+ const spanElement = parentElement.querySelector('.invalid-feedback');
143
+ element.classList.remove('is-invalid');
144
+ if (spanElement !== null) {
145
+ spanElement.innerHTML = "&nbsp;";
146
+ spanElement.style.display = 'none';
147
+ }
148
+ }
149
+ });
150
+ }
151
+
152
+ setupOverlayAndLoader() {
153
+ if (this.options.loader === null) {
154
+ this.form.style.position = 'relative';
155
+ const overlay = document.createElement('div');
156
+ overlay.id = `${this.id}-overlay`;
157
+ overlay.style.position = 'absolute';
158
+ overlay.style.top = 0;
159
+ overlay.style.left = 0;
160
+ overlay.style.width = '100%';
161
+ overlay.style.height = '100%';
162
+ overlay.style.display = 'none';
163
+ overlay.style.alignItems = 'center';
164
+ overlay.style.justifyContent = 'center';
165
+ overlay.style.backgroundColor = 'rgba(var(--bs-body-bg-rgb, 0, 0, 0), 0.7)';
166
+ overlay.style.zIndex = '1000';
167
+
168
+ const spinner = document.createElement('div');
169
+ spinner.className = 'spinner-border text-primary';
170
+ spinner.role = 'status';
171
+ spinner.innerHTML = '<span class="visually-hidden">Loading...</span>';
172
+
173
+ overlay.appendChild(spinner);
174
+ this.form.appendChild(overlay);
175
+ }
176
+ }
177
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "avalynx-form",
3
+ "title": "AvalynxForm",
4
+ "description": "AvalynxForm is a lightweight, customizable form handling library for web applications. Based on Bootstrap >=5.3 without any framework dependencies.",
5
+ "version": "0.0.1",
6
+ "license": "MIT",
7
+ "main": "dist/js/avalynx-form.js",
8
+ "module": "dist/js/avalynx-form.esm.js",
9
+ "files": [
10
+ "dist/js/avalynx-form.js",
11
+ "dist/js/avalynx-form.esm.js"
12
+ ],
13
+ "keywords": [
14
+ "avalynx",
15
+ "form",
16
+ "validation",
17
+ "input",
18
+ "bootstrap",
19
+ "bootstrap5",
20
+ "component"
21
+ ],
22
+ "ignore": [
23
+ "package.json"
24
+ ],
25
+ "author": {
26
+ "name": "Juergen Schwind an the Avalynx-Form Team",
27
+ "url": "https://github.com/avalynx/avalynx-form/graphs/contributors"
28
+ },
29
+ "homepage": "https://github.com/avalynx/",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/avalynx/avalynx-form.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/avalynx/avalynx-form/issues"
36
+ },
37
+ "scripts": {
38
+ "test": "jest",
39
+ "build": "shx rm -rf dist; shx mkdir -p dist/js/; shx cp src/js/avalynx-form.js dist/js/avalynx-form.js; shx cp src/js/avalynx-form.js dist/js/avalynx-form.esm.js; node build.js dist/js/avalynx-form.esm.js"
40
+ },
41
+ "dependencies": {
42
+ "bootstrap": ">=5.3"
43
+ },
44
+ "devDependencies": {
45
+ "@babel/core": "^7",
46
+ "@babel/preset-env": "^7",
47
+ "babel-jest": "^29",
48
+ "jest": "^29",
49
+ "jest-environment-jsdom": "^29",
50
+ "shelljs": "^0",
51
+ "shx": "^0"
52
+ }
53
+ }