@modernman00/shared-js-lib 1.2.66 → 1.2.68
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/AcctMgt/changePassword.js +30 -83
- package/AcctMgt/code.js +14 -55
- package/AcctMgt/createFormHandler.js +35 -0
- package/AcctMgt/forgot.js +14 -60
- package/AcctMgt/login.js +30 -70
- package/AcctMgt/processAll.js +20 -29
- package/AcctMgt/recaptchaToken.js +19 -0
- package/AcctMgt/registerHandler.js +24 -0
- package/AcctMgt/update.js +13 -49
- package/config/version.php +1 -1
- package/package.json +1 -1
|
@@ -1,47 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
// setupPasswordChange.js
|
|
2
2
|
import { id } from '../UtilityHtml.js';
|
|
3
3
|
import { bindEvent, showPassword } from '../Utility.js';
|
|
4
4
|
import { matchInput } from '../general.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Initializes password change functionality with accessibility, validation, and submission logic.
|
|
10
|
-
*
|
|
11
|
-
* This function sets up:
|
|
12
|
-
* - ARIA attributes for accessibility
|
|
13
|
-
* - Input matching between password and confirmation fields
|
|
14
|
-
* - Max length enforcement
|
|
15
|
-
* - Event bindings for submit and password visibility toggle
|
|
16
|
-
* - Form submission via `loginSubmission`
|
|
17
|
-
*
|
|
18
|
-
* @function setupPasswordChange
|
|
19
|
-
* @param {Object} [config] - Configuration object for customizing behavior.
|
|
20
|
-
* @param {string} [config.buttonId='button'] - ID of the submit button.
|
|
21
|
-
* @param {string} [config.passwordId='password'] - ID of the password input field.
|
|
22
|
-
* @param {string} [config.confirmId='confirm_password'] - ID of the confirm password input field.
|
|
23
|
-
* @param {string} [config.showToggleId='showPassword'] - ID of the toggle button to show/hide password.
|
|
24
|
-
* @param {string} [config.errorId='confirm_password_error'] - ID of the element to display mismatch errors.
|
|
25
|
-
* @param {string} [config.helpId='password_help'] - ID of the helper text element for password guidance.
|
|
26
|
-
* @param {string} [config.route] - API endpoint for password change submission.
|
|
27
|
-
* @param {string} [config.redirect] - URL to redirect to after successful password change.
|
|
28
|
-
* @param {string} [config.theme='bulma'] - UI theme identifier passed to `loginSubmission`.
|
|
29
|
-
* @param {number} [config.maxLength=50] - Maximum allowed length for password fields.
|
|
30
|
-
* @param {Object} [config.recaptchaV3=null] - reCAPTCHA v3 configuration ({ siteKey: 'xxx', action: 'CHANGE_PASSWORD' }).
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* setupPasswordChange(); // Uses default IDs and routes
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* setupPasswordChange({
|
|
37
|
-
* buttonId: 'submitBtn',
|
|
38
|
-
* passwordId: 'new_password',
|
|
39
|
-
* confirmId: 'confirm_new_password',
|
|
40
|
-
* route: '/api/change-password',
|
|
41
|
-
* redirect: '/dashboard'
|
|
42
|
-
* });
|
|
43
|
-
*/
|
|
44
|
-
|
|
5
|
+
import { createFormHandler } from './createFormHandler.js';
|
|
45
6
|
|
|
46
7
|
export const setupPasswordChange = ({
|
|
47
8
|
formId = 'changePassword',
|
|
@@ -53,57 +14,43 @@ export const setupPasswordChange = ({
|
|
|
53
14
|
helpId = 'password_help',
|
|
54
15
|
route,
|
|
55
16
|
redirect,
|
|
17
|
+
lengthLimitArray = null, // { id: [...], max: [...] } or null
|
|
18
|
+
optionalFields = [],
|
|
56
19
|
theme = 'bulma',
|
|
57
|
-
|
|
58
|
-
recaptchaV3 = null // { siteKey: 'xxx', action: 'CHANGE_PASSWORD' }
|
|
20
|
+
recaptchaAction = 'CHANGE_PASSWORD'
|
|
59
21
|
} = {}) => {
|
|
60
|
-
// Accessibility & input attributes
|
|
61
22
|
const passwordInput = id(passwordId);
|
|
62
23
|
const showToggle = id(showToggleId);
|
|
63
24
|
const helperText = id(helpId);
|
|
64
25
|
|
|
65
|
-
passwordInput
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
helperText.textContent =
|
|
69
|
-
'Password must be at least 8 characters long, contain at least one uppercase letter, one lowercase letter, one number, and one special character.';
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Length limit object
|
|
74
|
-
const lengthLimit = {
|
|
75
|
-
maxLength: {
|
|
76
|
-
id: [passwordId, confirmId],
|
|
77
|
-
max: [maxLength, maxLength]
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// Submission handler
|
|
82
|
-
const handleSubmit = async (e) => {
|
|
83
|
-
e.preventDefault();
|
|
26
|
+
if (passwordInput) {
|
|
27
|
+
passwordInput.setAttribute('autocomplete', 'current-password');
|
|
28
|
+
}
|
|
84
29
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
{ action: recaptchaV3.action || 'CHANGE_PASSWORD' });
|
|
92
|
-
} catch (err) {
|
|
93
|
-
showError(err);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
30
|
+
if (showToggle) {
|
|
31
|
+
showToggle.setAttribute(
|
|
32
|
+
'aria-label',
|
|
33
|
+
'Warning: this will display your password on the screen.'
|
|
34
|
+
);
|
|
35
|
+
}
|
|
96
36
|
|
|
97
|
-
|
|
37
|
+
if (helperText) {
|
|
38
|
+
helperText.setAttribute('aria-live', 'polite');
|
|
39
|
+
helperText.textContent =
|
|
40
|
+
'Password must be at least 8 characters long, contain at least one uppercase letter, one lowercase letter, one number, and one special character.';
|
|
41
|
+
}
|
|
98
42
|
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// Bind events
|
|
103
|
-
bindEvent({ id: buttonId, handler: handleSubmit });
|
|
104
43
|
bindEvent({ id: showToggleId, handler: () => showPassword(passwordId) });
|
|
105
44
|
matchInput(passwordId, confirmId, errorId);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
|
|
109
45
|
|
|
46
|
+
createFormHandler({
|
|
47
|
+
formId,
|
|
48
|
+
buttonId,
|
|
49
|
+
route,
|
|
50
|
+
redirect,
|
|
51
|
+
theme,
|
|
52
|
+
lengthLimit: lengthLimitArray,
|
|
53
|
+
optionalFields,
|
|
54
|
+
recaptchaAction
|
|
55
|
+
});
|
|
56
|
+
};
|
package/AcctMgt/code.js
CHANGED
|
@@ -1,30 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { showError } from '../ShowResponse.js';
|
|
1
|
+
// createCodeSubmitHandler.js
|
|
2
|
+
import { createFormHandler } from './createFormHandler.js';
|
|
4
3
|
|
|
5
|
-
/**
|
|
6
|
-
* Creates a reusable form submission handler for code-based forms.
|
|
7
|
-
*
|
|
8
|
-
* @function createCodeSubmitHandler
|
|
9
|
-
* @param {Object} options - Configuration for the handler.
|
|
10
|
-
* @param {string} options.formId - ID of the form element.
|
|
11
|
-
* @param {string} options.inputId - ID of the input field to validate.
|
|
12
|
-
* @param {string} options.buttonId - ID of the submit button.
|
|
13
|
-
* @param {string} options.route - API endpoint for submission.
|
|
14
|
-
* @param {string} options.redirect - URL to redirect to after success.
|
|
15
|
-
* @param {string} [options.theme='bulma'] - UI theme identifier.
|
|
16
|
-
* @param {number} [options.maxLength=50] - Max input length.
|
|
17
|
-
* @param {Object} [options.recaptchaV3=null] - reCAPTCHA v3 configuration ({ siteKey: 'OUR_ENTERPRISE_SITE_KEYx', action: 'TOKEN' }).
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* createCodeSubmitHandler({
|
|
21
|
-
* formId: 'codeForm',
|
|
22
|
-
* inputId: 'code',
|
|
23
|
-
* buttonId: 'button',
|
|
24
|
-
* route: appTestRoutes.appTestCode,
|
|
25
|
-
* redirect: appTestRoutes.appTestCodeRedirect
|
|
26
|
-
* });
|
|
27
|
-
*/
|
|
28
4
|
export function createCodeSubmitHandler({
|
|
29
5
|
formId,
|
|
30
6
|
inputId = 'code',
|
|
@@ -32,34 +8,17 @@ export function createCodeSubmitHandler({
|
|
|
32
8
|
route,
|
|
33
9
|
redirect,
|
|
34
10
|
theme = 'bulma',
|
|
35
|
-
|
|
36
|
-
|
|
11
|
+
lengthLimitArray = null, // { id: [...], max: [...] } or null
|
|
12
|
+
recaptchaAction = 'SUBMIT'
|
|
37
13
|
}) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} catch (err) {
|
|
49
|
-
showError(err);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const lengthLimit = {
|
|
54
|
-
maxLength: {
|
|
55
|
-
id: [inputId],
|
|
56
|
-
max: [maxLength]
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
loginSubmission(formId, route, redirect, theme, lengthLimit);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
bindEvent({ id: buttonId, handler });
|
|
14
|
+
createFormHandler({
|
|
15
|
+
formId,
|
|
16
|
+
buttonId,
|
|
17
|
+
route,
|
|
18
|
+
redirect,
|
|
19
|
+
theme,
|
|
20
|
+
lengthLimit: lengthLimitArray,
|
|
21
|
+
optionalFields: [inputId],
|
|
22
|
+
recaptchaAction
|
|
23
|
+
});
|
|
64
24
|
}
|
|
65
|
-
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// createFormHandler.js
|
|
2
|
+
import { bindEvent } from '../Utility.js';
|
|
3
|
+
import { recaptchaToken } from './recaptchaToken.js';
|
|
4
|
+
import { loginSubmission } from './processAll.js';
|
|
5
|
+
|
|
6
|
+
export function createFormHandler({
|
|
7
|
+
formId,
|
|
8
|
+
buttonId = 'button',
|
|
9
|
+
route,
|
|
10
|
+
redirect,
|
|
11
|
+
theme = 'bulma',
|
|
12
|
+
lengthLimit = null, // { id: [...], max: [...] } or null
|
|
13
|
+
optionalFields = [], // ['remember_me', 'captcha'] etc.
|
|
14
|
+
recaptchaAction = 'SUBMIT'
|
|
15
|
+
}) {
|
|
16
|
+
const handler = async (e) => {
|
|
17
|
+
e.preventDefault();
|
|
18
|
+
|
|
19
|
+
const token = await recaptchaToken(recaptchaAction);
|
|
20
|
+
|
|
21
|
+
await loginSubmission({
|
|
22
|
+
formId,
|
|
23
|
+
loginURL: route,
|
|
24
|
+
redirect,
|
|
25
|
+
css: theme,
|
|
26
|
+
lengthLimit,
|
|
27
|
+
optionalFields,
|
|
28
|
+
recaptchaToken: token
|
|
29
|
+
? { token, action: recaptchaAction }
|
|
30
|
+
: null
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
// 🔹 This is the click binding you’re referring to
|
|
34
|
+
bindEvent({ id: buttonId, handler });
|
|
35
|
+
}
|
package/AcctMgt/forgot.js
CHANGED
|
@@ -1,36 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { showError } from '../ShowResponse.js';
|
|
1
|
+
// forgotSubmitHandler.js
|
|
2
|
+
import { createFormHandler } from './createFormHandler.js';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Creates a reusable form submission handler for email-based forms.
|
|
8
|
-
*
|
|
9
|
-
* This function:
|
|
10
|
-
* - Prevents default form submission
|
|
11
|
-
* - Applies max length validation to the email input
|
|
12
|
-
* - Submits the form using `loginSubmission` with route and redirect logic
|
|
13
|
-
*
|
|
14
|
-
* @function createEmailSubmitHandler
|
|
15
|
-
* @param {Object} options - Configuration for the handler.
|
|
16
|
-
* @param {string} options.formId - ID of the form element.
|
|
17
|
-
* @param {string} options.inputId - ID of the email input field.
|
|
18
|
-
* @param {string} options.buttonId - ID of the submit button.
|
|
19
|
-
* @param {string} options.route - API endpoint for submission.
|
|
20
|
-
* @param {string} options.redirect - URL to redirect to after success.
|
|
21
|
-
* @param {string} [options.theme='bulma'] - UI theme identifier.
|
|
22
|
-
* @param {number} [options.maxLength=50] - Max input length.
|
|
23
|
-
* @param {Object} [options.recaptchaV3=null] - reCAPTCHA v3 configuration ({ siteKey: 'OUR_ENTERPRISE_SITE_KEYx', action: 'FORGOT' }).
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* createEmailSubmitHandler({
|
|
27
|
-
* formId: 'forgotPassword',
|
|
28
|
-
* inputId: 'email',
|
|
29
|
-
* buttonId: 'button',
|
|
30
|
-
* route: appTestRoutes.appTestForgot,
|
|
31
|
-
* redirect: appTestRoutes.appTestForgotRedirect
|
|
32
|
-
* });
|
|
33
|
-
*/
|
|
34
4
|
export function forgotSubmitHandler({
|
|
35
5
|
formId,
|
|
36
6
|
inputId = 'email',
|
|
@@ -38,35 +8,19 @@ export function forgotSubmitHandler({
|
|
|
38
8
|
route,
|
|
39
9
|
redirect,
|
|
40
10
|
theme = 'bulma',
|
|
41
|
-
|
|
42
|
-
|
|
11
|
+
lengthLimitArray = null, // { id: [...], max: [...] } or null
|
|
12
|
+
recaptchaAction = 'FORGOT'
|
|
43
13
|
}) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
} catch (err) {
|
|
55
|
-
showError(err);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const lengthLimit = {
|
|
60
|
-
maxLength: {
|
|
61
|
-
id: [inputId],
|
|
62
|
-
max: [maxLength]
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
loginSubmission(formId, route, redirect, theme, lengthLimit);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
bindEvent({ id: buttonId, handler });
|
|
14
|
+
createFormHandler({
|
|
15
|
+
formId,
|
|
16
|
+
buttonId,
|
|
17
|
+
route,
|
|
18
|
+
redirect,
|
|
19
|
+
theme,
|
|
20
|
+
lengthLimit: lengthLimitArray,
|
|
21
|
+
optionalFields: [inputId],
|
|
22
|
+
recaptchaAction
|
|
23
|
+
});
|
|
70
24
|
}
|
|
71
25
|
|
|
72
26
|
|
package/AcctMgt/login.js
CHANGED
|
@@ -1,42 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import { id} from '../UtilityHtml.js';
|
|
1
|
+
// createAdminLoginHandler.js
|
|
2
|
+
import { id } from '../UtilityHtml.js';
|
|
3
3
|
import { bindEvent, showPassword } from '../Utility.js';
|
|
4
|
-
import {
|
|
4
|
+
import { createFormHandler } from './createFormHandler.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Creates a reusable admin login handler with password visibility and accessibility support.
|
|
9
|
-
*
|
|
10
|
-
* This function:
|
|
11
|
-
* - Binds form submission to `loginSubmission`
|
|
12
|
-
* - Applies max length validation to email and password fields
|
|
13
|
-
* - Enables password visibility toggle
|
|
14
|
-
* - Sets accessibility attributes for screen readers and autocomplete
|
|
15
|
-
*
|
|
16
|
-
* @function createAdminLoginHandler
|
|
17
|
-
* @param {Object} options - Configuration for the login handler.
|
|
18
|
-
* @param {string} options.formId - ID of the login form.
|
|
19
|
-
* @param {string} options.emailId - ID of the email input field.
|
|
20
|
-
* @param {string} options.passwordId - ID of the password input field.
|
|
21
|
-
* @param {string} options.buttonId - ID of the submit button.
|
|
22
|
-
* @param {string} options.showToggleId - ID of the password visibility toggle button.
|
|
23
|
-
* @param {string} options.route - API endpoint for login submission.
|
|
24
|
-
* @param {string} options.redirect - URL to redirect to after successful login.
|
|
25
|
-
* @param {string} [options.theme='bootstrap'] - UI theme identifier.
|
|
26
|
-
* @param {number[]} [options.maxLength=[30, 50]] - Max lengths for password and email respectively.
|
|
27
|
-
* @param {Object} [options.recaptchaV3=null] - reCAPTCHA v3 configuration ({ siteKey: 'OUR_ENTERPRISE_SITE_KEY', action: 'LOGIN' }).
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* createAdminLoginHandler({
|
|
31
|
-
* formId: 'managed',
|
|
32
|
-
* emailId: 'email',
|
|
33
|
-
* passwordId: 'password',
|
|
34
|
-
* buttonId: 'button',
|
|
35
|
-
* showToggleId: 'showPassword',
|
|
36
|
-
* route: appTestRoutes.appTest,
|
|
37
|
-
* redirect: appTestRoutes.redirect
|
|
38
|
-
* });
|
|
39
|
-
*/
|
|
40
6
|
export function createAdminLoginHandler({
|
|
41
7
|
formId,
|
|
42
8
|
emailId = 'email',
|
|
@@ -46,43 +12,37 @@ export function createAdminLoginHandler({
|
|
|
46
12
|
route,
|
|
47
13
|
redirect,
|
|
48
14
|
theme = 'bootstrap',
|
|
49
|
-
|
|
50
|
-
|
|
15
|
+
recaptchaAction = 'LOGIN',
|
|
16
|
+
lengthLimitArray = null,
|
|
17
|
+
optionalFields = []
|
|
51
18
|
}) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
let recaptchaToken = null;
|
|
56
|
-
// Only run v3 if configured AND grecaptcha is available
|
|
57
|
-
if (recaptchaV3?.siteKey && window.grecaptcha && window.grecaptcha.enterprise) {
|
|
58
|
-
try {
|
|
59
|
-
recaptchaToken = await grecaptcha.enterprise.execute(
|
|
60
|
-
recaptchaV3.siteKey,
|
|
61
|
-
{ action: recaptchaV3.action || 'LOGIN' } );
|
|
62
|
-
} catch (err) {
|
|
63
|
-
showError(err);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
19
|
+
// Accessibility
|
|
20
|
+
const passwordInput = id(passwordId);
|
|
21
|
+
const toggleLabel = id(showToggleId);
|
|
66
22
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
max: maxLength
|
|
71
|
-
}
|
|
72
|
-
};
|
|
23
|
+
if (passwordInput) {
|
|
24
|
+
passwordInput.setAttribute('autocomplete', 'current-password');
|
|
25
|
+
}
|
|
73
26
|
|
|
74
|
-
|
|
75
|
-
|
|
27
|
+
if (toggleLabel) {
|
|
28
|
+
toggleLabel.setAttribute(
|
|
29
|
+
'aria-label',
|
|
30
|
+
'Warning: this will display your password on the screen.'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
76
33
|
|
|
77
|
-
|
|
34
|
+
// Password visibility toggle
|
|
78
35
|
bindEvent({ id: showToggleId, handler: () => showPassword(passwordId) });
|
|
79
36
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
37
|
+
// Core handler
|
|
38
|
+
createFormHandler({
|
|
39
|
+
formId,
|
|
40
|
+
buttonId,
|
|
41
|
+
route,
|
|
42
|
+
redirect,
|
|
43
|
+
theme,
|
|
44
|
+
lengthLimit: lengthLimitArray,
|
|
45
|
+
optionalFields: [emailId, passwordId, ...optionalFields],
|
|
46
|
+
recaptchaAction
|
|
47
|
+
});
|
|
88
48
|
}
|
package/AcctMgt/processAll.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// processAll.js
|
|
1
2
|
'use strict';
|
|
2
3
|
import { postFormData } from '../Http.js';
|
|
3
4
|
import { showLoader, clearLoader } from '../Loader.js';
|
|
@@ -5,59 +6,49 @@ import { id } from '../UtilityHtml.js';
|
|
|
5
6
|
import { showError } from '../ShowResponse.js';
|
|
6
7
|
import FormHelper from '../FormHelper.js';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
// block the setLoader div
|
|
10
|
-
|
|
11
9
|
/**
|
|
12
|
-
* Handles the submission of
|
|
13
|
-
* @param {string} formId - The ID of the form to submit.
|
|
14
|
-
* @param {string} loginURL - The URL to make the POST request to.
|
|
15
|
-
* @param {string} redirect - The URL to redirect the user to after the submission is complete.
|
|
16
|
-
* @param {string} [css=null] - The CSS class to add to the notification element if the submission is successful.
|
|
17
|
-
* @returns {void} yes
|
|
18
|
-
* @throws {Error} - If there is an error with the submission
|
|
19
|
-
* @param {Object} [options.recaptchaV3=null] - reCAPTCHA v3 configuration ({ siteKey: 'OUR_ENTERPRISE_SITE_KEY', action: 'LOGIN' }).
|
|
10
|
+
* Handles the submission of a form and redirects the user.
|
|
20
11
|
*/
|
|
21
|
-
export const loginSubmission = async ({
|
|
12
|
+
export const loginSubmission = async ({
|
|
13
|
+
formId,
|
|
14
|
+
loginURL,
|
|
15
|
+
redirect,
|
|
16
|
+
css = null,
|
|
17
|
+
lengthLimit = null, // { id: [...], max: [...] } or null
|
|
18
|
+
optionalFields = [],
|
|
19
|
+
recaptchaToken = null // { token, action } or null
|
|
22
20
|
}) => {
|
|
23
|
-
|
|
24
21
|
try {
|
|
25
|
-
|
|
26
22
|
const formInput = id(formId);
|
|
27
23
|
|
|
28
24
|
if (!formInput) {
|
|
29
25
|
throw new Error(`Form ${formId} not found`);
|
|
30
|
-
return;
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
const formInputArr = Array.from(formInput.elements);
|
|
34
|
-
|
|
35
29
|
const formData = new FormHelper(formInputArr);
|
|
36
30
|
|
|
37
31
|
formData.clearError();
|
|
38
32
|
|
|
39
33
|
if (lengthLimit) {
|
|
40
|
-
formData.realTimeCheckLen(lengthLimit.
|
|
34
|
+
formData.realTimeCheckLen(lengthLimit.id, lengthLimit.max);
|
|
41
35
|
}
|
|
42
36
|
|
|
43
37
|
formData.massValidate(optionalFields, { email: 'email', password: 'password' });
|
|
44
38
|
|
|
45
|
-
if (formData.result
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
notificationId.scrollIntoView({ behavior: 'smooth' });
|
|
50
|
-
|
|
51
|
-
showLoader();
|
|
39
|
+
if (formData.result !== 1) {
|
|
40
|
+
alert('The form cannot be submitted. Please check the errors');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
52
43
|
|
|
53
|
-
|
|
44
|
+
const notificationId = id(`${formId}_notification`) || formId;
|
|
45
|
+
notificationId.scrollIntoView({ behavior: 'smooth' });
|
|
54
46
|
|
|
55
|
-
|
|
47
|
+
showLoader();
|
|
48
|
+
localStorage.setItem('redirect', redirect);
|
|
56
49
|
|
|
57
|
-
|
|
50
|
+
await postFormData(loginURL, formId, redirect, css, recaptchaToken);
|
|
58
51
|
|
|
59
|
-
alert('The form cannot be submitted. Please check the errors');
|
|
60
|
-
}
|
|
61
52
|
} catch (err) {
|
|
62
53
|
showError(err);
|
|
63
54
|
} finally {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// recaptchaToken.js
|
|
2
|
+
import { showError } from '../ShowResponse.js';
|
|
3
|
+
|
|
4
|
+
export const recaptchaToken = async (action = 'SUBMIT') => {
|
|
5
|
+
let token = null;
|
|
6
|
+
|
|
7
|
+
if (window.RECAPTCHA_SITE_KEY && window.grecaptcha && window.grecaptcha.enterprise) {
|
|
8
|
+
try {
|
|
9
|
+
token = await window.grecaptcha.enterprise.execute(
|
|
10
|
+
window.RECAPTCHA_SITE_KEY,
|
|
11
|
+
{ action }
|
|
12
|
+
);
|
|
13
|
+
} catch (err) {
|
|
14
|
+
showError(err);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return token;
|
|
19
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// registerHandler.js
|
|
2
|
+
import { createFormHandler } from './createFormHandler.js';
|
|
3
|
+
|
|
4
|
+
export function registerHandler({
|
|
5
|
+
formId,
|
|
6
|
+
buttonId = 'button',
|
|
7
|
+
route,
|
|
8
|
+
redirect,
|
|
9
|
+
theme = 'bootstrap',
|
|
10
|
+
recaptchaAction = 'SUBMIT',
|
|
11
|
+
lengthLimitArray = null,
|
|
12
|
+
optionalFields = []
|
|
13
|
+
}) {
|
|
14
|
+
createFormHandler({
|
|
15
|
+
formId,
|
|
16
|
+
buttonId,
|
|
17
|
+
route,
|
|
18
|
+
redirect,
|
|
19
|
+
theme,
|
|
20
|
+
lengthLimit: lengthLimitArray,
|
|
21
|
+
optionalFields,
|
|
22
|
+
recaptchaAction
|
|
23
|
+
});
|
|
24
|
+
}
|
package/AcctMgt/update.js
CHANGED
|
@@ -1,49 +1,22 @@
|
|
|
1
|
+
// update.js
|
|
1
2
|
import { id } from '../UtilityHtml.js';
|
|
2
3
|
import { bindEvent } from '../Utility.js';
|
|
3
4
|
import { msgException, showError } from '../ShowResponse.js';
|
|
4
5
|
import axios from 'axios';
|
|
5
6
|
import { redirectAfterDelay, parseErrorResponse } from '../general.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
* @function update
|
|
10
|
-
* @param {Object} options - Configuration for the handler.
|
|
11
|
-
* @param {string} options.formId - ID of the form element.
|
|
12
|
-
* @param {string} options.buttonId - ID of the submit button.
|
|
13
|
-
* @param {string} options.route - API endpoint for submission.
|
|
14
|
-
* @param {string} options.redirect - URL to redirect to after success.
|
|
15
|
-
* @param {Object} [options.recaptchaV3=null] - reCAPTCHA v3 configuration ({ siteKey: 'OUR_ENTERPRISE_SITE_KEY', action: 'LOGIN' }).
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* update({
|
|
20
|
-
* formId: 'updateForm',
|
|
21
|
-
* buttonId: 'updateButton',
|
|
22
|
-
* route: appTestRoutes.appTestUpdate,
|
|
23
|
-
* redirect: appTestRoutes.appTestUpdateRedirect
|
|
24
|
-
* });
|
|
25
|
-
*/
|
|
7
|
+
import { recaptchaToken } from './recaptchaToken.js';
|
|
8
|
+
|
|
26
9
|
export function update({
|
|
27
10
|
formId,
|
|
28
11
|
buttonId,
|
|
29
12
|
route,
|
|
30
13
|
redirect,
|
|
31
|
-
|
|
14
|
+
recaptchaAction = 'SUBMIT'
|
|
32
15
|
}) {
|
|
33
16
|
const handler = async (e) => {
|
|
34
17
|
e.preventDefault();
|
|
35
18
|
|
|
36
|
-
|
|
37
|
-
// Only run v3 if configured AND grecaptcha is available
|
|
38
|
-
if (recaptchaV3?.siteKey && window.grecaptcha && window.grecaptcha.enterprise) {
|
|
39
|
-
try {
|
|
40
|
-
recaptchaToken = await grecaptcha.enterprise.execute(
|
|
41
|
-
recaptchaV3.siteKey,
|
|
42
|
-
{ action: recaptchaV3.action || 'LOGIN' });
|
|
43
|
-
} catch (err) {
|
|
44
|
-
showError(err);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
19
|
+
const token = await recaptchaToken(recaptchaAction);
|
|
47
20
|
|
|
48
21
|
const form = id(formId);
|
|
49
22
|
if (!form) {
|
|
@@ -54,9 +27,8 @@ export function update({
|
|
|
54
27
|
const formData = new FormData();
|
|
55
28
|
const inputs = form.querySelectorAll('[name]');
|
|
56
29
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
formData.append('recaptchaTokenV3', recaptchaToken);
|
|
30
|
+
if (token) {
|
|
31
|
+
formData.append('recaptchaTokenV3', token);
|
|
60
32
|
}
|
|
61
33
|
|
|
62
34
|
inputs.forEach(input => {
|
|
@@ -64,7 +36,6 @@ export function update({
|
|
|
64
36
|
const original = input.getAttribute('data-original');
|
|
65
37
|
const current = input.type === 'file' ? input.files[0] : input.value;
|
|
66
38
|
|
|
67
|
-
// Only include changed fields
|
|
68
39
|
if (input.type === 'file') {
|
|
69
40
|
if (current) formData.append(name, current);
|
|
70
41
|
} else if (current !== original) {
|
|
@@ -73,32 +44,25 @@ export function update({
|
|
|
73
44
|
});
|
|
74
45
|
|
|
75
46
|
try {
|
|
76
|
-
|
|
77
47
|
const response = await axios.post(route, formData);
|
|
78
|
-
|
|
79
48
|
const message = response.data.message;
|
|
80
49
|
|
|
81
50
|
const notificationId = id(`${formId}_notification`) || formId;
|
|
82
|
-
notificationId.style.display = 'block'
|
|
83
|
-
|
|
84
|
-
notificationId.scrollIntoView({ behavior: 'smooth' });
|
|
85
|
-
|
|
51
|
+
notificationId.style.display = 'block';
|
|
86
52
|
notificationId.innerHTML = message;
|
|
87
|
-
|
|
53
|
+
notificationId.scrollIntoView({ behavior: 'smooth' });
|
|
88
54
|
|
|
89
55
|
if (redirect) {
|
|
90
56
|
redirectAfterDelay(redirect, 2000);
|
|
91
57
|
}
|
|
92
58
|
|
|
93
59
|
} catch (error) {
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
notificationId.
|
|
98
|
-
notificationId.innerHTML = `<li style="color:white; background-color:red">${ErrorMsg}</li>`;
|
|
60
|
+
const errorMsg = parseErrorResponse(error);
|
|
61
|
+
const notificationId = id(`${formId}_notification`);
|
|
62
|
+
notificationId.style.display = 'block';
|
|
63
|
+
notificationId.innerHTML = `<li style="color:white; background-color:red">${errorMsg}</li>`;
|
|
99
64
|
}
|
|
100
65
|
};
|
|
101
66
|
|
|
102
67
|
bindEvent({ id: buttonId, handler });
|
|
103
68
|
}
|
|
104
|
-
|
package/config/version.php
CHANGED
package/package.json
CHANGED