@webbycrown/advanced-fields 1.0.0 → 1.0.2
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/README.md +19 -6
- package/admin/jsconfig.json +10 -0
- package/admin/src/components/AdvancedCheckbox/index.jsx +377 -0
- package/admin/src/components/AdvancedInput/index.jsx +179 -0
- package/admin/src/components/AdvancedRadio/index.jsx +344 -0
- package/admin/src/components/Initializer.jsx +18 -0
- package/admin/src/components/PluginIcon.jsx +108 -0
- package/admin/src/index.js +787 -0
- package/admin/src/pages/App.jsx +13 -0
- package/admin/src/pluginId.js +3 -0
- package/admin/src/translations/en.json +86 -0
- package/admin/src/utils/getTranslation.js +5 -0
- package/index.js +158 -0
- package/package.json +6 -3
- package/strapi-server.js +186 -0
- package/strapi-server.mjs +74 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Page } from '@strapi/strapi/admin';
|
|
2
|
+
import { Routes, Route } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
const App = () => {
|
|
5
|
+
return (
|
|
6
|
+
<Routes>
|
|
7
|
+
<Route index element={<Page.Error />} />
|
|
8
|
+
<Route path="*" element={<Page.Error />} />
|
|
9
|
+
</Routes>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { App };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"advanced-fields.plugin.name": "Advanced Fields",
|
|
3
|
+
"advanced-fields.input.label": "Advanced Input",
|
|
4
|
+
"advanced-fields.input.description": "Professional-grade text input with comprehensive validation and advanced configuration options",
|
|
5
|
+
"advanced-fields.checkbox.label": "Advanced Checkbox",
|
|
6
|
+
"advanced-fields.checkbox.description": "Unified checkbox field supporting both single and multiple selections with advanced configuration",
|
|
7
|
+
"advanced-fields.selectinput.label": "Select Input",
|
|
8
|
+
"advanced-fields.selectinput.description": "Select an option",
|
|
9
|
+
|
|
10
|
+
"advanced-fields.input.settings.base.label": "Basic settings",
|
|
11
|
+
"advanced-fields.input.options.required.label": "Required field",
|
|
12
|
+
"advanced-fields.input.options.required.description": "You won't be able to create an entry if this field is empty",
|
|
13
|
+
"advanced-fields.input.options.unique.label": "Unique field",
|
|
14
|
+
"advanced-fields.input.options.unique.description": "You won't be able to create an entry if there is an existing entry with identical content",
|
|
15
|
+
"advanced-fields.input.options.maxLength.label": "Maximum length",
|
|
16
|
+
"advanced-fields.input.options.maxLength.description": "Set the maximum number of characters allowed",
|
|
17
|
+
"advanced-fields.input.options.minLength.label": "Minimum length",
|
|
18
|
+
"advanced-fields.input.options.minLength.description": "Set the minimum number of characters allowed",
|
|
19
|
+
"advanced-fields.input.options.defaultValue.label": "Default value",
|
|
20
|
+
"advanced-fields.input.options.defaultValue.description": "Set the default value for this field",
|
|
21
|
+
|
|
22
|
+
"advanced-fields.input.settings.advanced.label": "Advanced settings",
|
|
23
|
+
"advanced-fields.input.options.regex.label": "RegExp pattern",
|
|
24
|
+
"advanced-fields.input.options.regex.description": "The text of the regular expression",
|
|
25
|
+
"advanced-fields.input.options.placeholder.label": "Placeholder",
|
|
26
|
+
"advanced-fields.input.options.placeholder.description": "Display text when the field is empty",
|
|
27
|
+
"advanced-fields.input.options.private.label": "Private field",
|
|
28
|
+
"advanced-fields.input.options.private.description": "This field will not be included in API responses",
|
|
29
|
+
"advanced-fields.input.options.customErrorMessage.label": "Custom error message",
|
|
30
|
+
"advanced-fields.input.options.customErrorMessage.description": "Display a custom error message when validation fails",
|
|
31
|
+
|
|
32
|
+
"advanced-fields.checkbox.settings.base.label": "Basic settings",
|
|
33
|
+
"advanced-fields.checkbox.options.required.label": "Required field",
|
|
34
|
+
"advanced-fields.checkbox.options.required.description": "You won't be able to create an entry if this field is empty",
|
|
35
|
+
"advanced-fields.checkbox.options.checkboxType.label": "Checkbox Type",
|
|
36
|
+
"advanced-fields.checkbox.options.checkboxType.description": "Choose between single checkbox or multiple checkboxes",
|
|
37
|
+
"advanced-fields.checkbox.options.checkboxType.single": "Single Checkbox",
|
|
38
|
+
"advanced-fields.checkbox.options.checkboxType.multiple": "Multiple Checkboxes",
|
|
39
|
+
"advanced-fields.checkbox.options.defaultValue.label": "Default State",
|
|
40
|
+
"advanced-fields.checkbox.options.defaultValue.description": "Pre-checked state for single checkbox",
|
|
41
|
+
"advanced-fields.checkbox.options.defaultValue.options.true": "Checked (True)",
|
|
42
|
+
"advanced-fields.checkbox.options.defaultValue.options.false": "Unchecked (False)",
|
|
43
|
+
|
|
44
|
+
"advanced-fields.checkbox.settings.advanced.label": "Advanced settings",
|
|
45
|
+
"advanced-fields.checkbox.options.customErrorMessage.label": "Custom error message",
|
|
46
|
+
"advanced-fields.checkbox.options.customErrorMessage.description": "Display a custom error message when validation fails",
|
|
47
|
+
"advanced-fields.checkbox.options.customErrorMessage.placeholder": "Enter custom error message",
|
|
48
|
+
"advanced-fields.checkbox.options.private.label": "Private field",
|
|
49
|
+
"advanced-fields.checkbox.options.private.description": "This field will not be included in API responses",
|
|
50
|
+
"advanced-fields.checkbox.options.labelOn.label": "Checked Label",
|
|
51
|
+
"advanced-fields.checkbox.options.labelOn.description": "Custom label displayed when single checkbox is checked",
|
|
52
|
+
"advanced-fields.checkbox.options.labelOff.label": "Unchecked Label",
|
|
53
|
+
"advanced-fields.checkbox.options.labelOff.description": "Custom label displayed when single checkbox is unchecked",
|
|
54
|
+
"advanced-fields.checkbox.options.checkboxOptions.label": "Checkbox Options",
|
|
55
|
+
"advanced-fields.checkbox.options.checkboxOptions.description": "Define available options for multiple checkboxes (one per line: value|label)",
|
|
56
|
+
"advanced-fields.checkbox.options.checkboxOptions.placeholder": "option1|Option 1\noption2|Option 2\noption3|Option 3",
|
|
57
|
+
"advanced-fields.checkbox.options.defaultSelected.label": "Default Selected",
|
|
58
|
+
"advanced-fields.checkbox.options.defaultSelected.description": "Pre-selected options for multiple checkboxes (one per line)",
|
|
59
|
+
"advanced-fields.checkbox.options.defaultSelected.placeholder": "option1\noption2",
|
|
60
|
+
"advanced-fields.checkbox.options.minChoices.label": "Minimum Choices",
|
|
61
|
+
"advanced-fields.checkbox.options.minChoices.description": "Minimum number of options that must be selected (0 for no minimum)",
|
|
62
|
+
"advanced-fields.checkbox.options.maxChoices.label": "Maximum Choices",
|
|
63
|
+
"advanced-fields.checkbox.options.maxChoices.description": "Maximum number of options that can be selected (0 for no maximum)",
|
|
64
|
+
"advanced-fields.checkbox.options.layout.label": "Layout Style",
|
|
65
|
+
"advanced-fields.checkbox.options.layout.description": "Visual layout of multiple checkbox options",
|
|
66
|
+
"advanced-fields.checkbox.options.layout.vertical": "Vertical Stack",
|
|
67
|
+
"advanced-fields.checkbox.options.layout.horizontal": "Horizontal Row",
|
|
68
|
+
"advanced-fields.checkbox.options.layout.grid": "Grid Layout",
|
|
69
|
+
|
|
70
|
+
"advanced-fields.radio.label": "Multiple Type Choice",
|
|
71
|
+
"advanced-fields.radio.description": "Select one or more options (radio style)",
|
|
72
|
+
"advanced-fields.radio.settings.base.label": "Basic settings",
|
|
73
|
+
"advanced-fields.radio.options.required.label": "Multiple Type Choice",
|
|
74
|
+
"advanced-fields.radio.options.required.description": "You won't be able to create an entry if this field is empty",
|
|
75
|
+
"advanced-fields.radio.options.radioOptions.label": "Multiple Type Choice",
|
|
76
|
+
"advanced-fields.radio.options.radioOptions.description": "Enter one option per line in format: value|label (e.g., \"1|Option 1\")",
|
|
77
|
+
"advanced-fields.radio.options.radioOptions.placeholder": "1|Option 1\n2|Option 2\n3|Option 3",
|
|
78
|
+
"advanced-fields.radio.options.selectionType.label": "Selection Type",
|
|
79
|
+
"advanced-fields.radio.options.selectionType.description": "Allow selecting only one or multiple type choices",
|
|
80
|
+
"advanced-fields.radio.options.customErrorMessage.label": "Custom error message",
|
|
81
|
+
"advanced-fields.radio.options.customErrorMessage.description": "Display a custom error message when validation fails",
|
|
82
|
+
"advanced-fields.radio.options.customErrorMessage.placeholder": "Enter custom error message",
|
|
83
|
+
"advanced-fields.radio.no-options": "No options defined. Please configure this field in the content type settings.",
|
|
84
|
+
"advanced-fields.radio.options.type.single": "Single selection",
|
|
85
|
+
"advanced-fields.radio.options.type.multiple": "Multiple selection"
|
|
86
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PLUGIN_ID = 'advanced-fields';
|
|
4
|
+
|
|
5
|
+
const customFields = [
|
|
6
|
+
{
|
|
7
|
+
name: 'input',
|
|
8
|
+
type: 'string',
|
|
9
|
+
validate: (value, { required, options = {} }) => {
|
|
10
|
+
// Basic required validation
|
|
11
|
+
if (required && (!value || value.toString().trim().length === 0)) {
|
|
12
|
+
return 'This field is required';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Length validation
|
|
16
|
+
if (value && options.maxLength && value.length > options.maxLength) {
|
|
17
|
+
return `Maximum length is ${options.maxLength} characters`;
|
|
18
|
+
}
|
|
19
|
+
if (value && options.minLength && value.length < options.minLength) {
|
|
20
|
+
return `Minimum length is ${options.minLength} characters`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Regex validation
|
|
24
|
+
if (value && options.regex) {
|
|
25
|
+
try {
|
|
26
|
+
const regex = new RegExp(options.regex);
|
|
27
|
+
if (!regex.test(value)) {
|
|
28
|
+
return options.customErrorMessage || 'Value does not match required format';
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
// Invalid regex pattern - silently ignore
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Input type validation
|
|
36
|
+
if (value && options.inputType) {
|
|
37
|
+
switch (options.inputType) {
|
|
38
|
+
case 'email':
|
|
39
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
40
|
+
if (!emailRegex.test(value)) {
|
|
41
|
+
return 'Please enter a valid email address';
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case 'url':
|
|
45
|
+
try {
|
|
46
|
+
new URL(value);
|
|
47
|
+
} catch {
|
|
48
|
+
return 'Please enter a valid URL';
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
case 'number':
|
|
52
|
+
if (isNaN(parseFloat(value))) {
|
|
53
|
+
return 'Please enter a valid number';
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'checkbox',
|
|
64
|
+
type: 'json',
|
|
65
|
+
validate: (value, { required, options = {} }) => {
|
|
66
|
+
|
|
67
|
+
// Basic required validation
|
|
68
|
+
if (required) {
|
|
69
|
+
if (!value ||
|
|
70
|
+
(Array.isArray(value) && value.length === 0) ||
|
|
71
|
+
(typeof value === 'string' && value.trim() === '') ||
|
|
72
|
+
value === null ||
|
|
73
|
+
value === undefined) {
|
|
74
|
+
return options.customErrorMessage || 'This field is required';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// If no value and not required, no additional validation needed
|
|
79
|
+
if (!required && (!value || (Array.isArray(value) && value.length === 0))) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Choice validation for multiple checkboxes only
|
|
84
|
+
if (options.checkboxType === 'multiple' && Array.isArray(value)) {
|
|
85
|
+
if (options.minChoices > 0 && value.length < options.minChoices) {
|
|
86
|
+
return options.customErrorMessage || `Please select at least ${options.minChoices} option${options.minChoices > 1 ? 's' : ''}`;
|
|
87
|
+
}
|
|
88
|
+
if (options.maxChoices > 0 && value.length > options.maxChoices) {
|
|
89
|
+
return options.customErrorMessage || `Please select at most ${options.maxChoices} option${options.maxChoices > 1 ? 's' : ''}`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "radio",
|
|
98
|
+
type: "json",
|
|
99
|
+
validate: (value, { required, options = {} }) => {
|
|
100
|
+
// Basic required validation
|
|
101
|
+
if (required) {
|
|
102
|
+
if (!value ||
|
|
103
|
+
(Array.isArray(value) && value.length === 0) ||
|
|
104
|
+
(typeof value === 'string' && value.trim() === '') ||
|
|
105
|
+
value === null ||
|
|
106
|
+
value === undefined) {
|
|
107
|
+
return 'This field is required';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Choice validation
|
|
112
|
+
if (Array.isArray(value)) {
|
|
113
|
+
if (options.minChoices > 0 && value.length < options.minChoices) {
|
|
114
|
+
return `Please select at least ${options.minChoices} option${options.minChoices > 1 ? 's' : ''}`;
|
|
115
|
+
}
|
|
116
|
+
if (options.maxChoices > 0 && value.length > options.maxChoices) {
|
|
117
|
+
return `Please select at most ${options.maxChoices} option${options.maxChoices > 1 ? 's' : ''}`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
module.exports = {
|
|
127
|
+
register({ strapi }) {
|
|
128
|
+
// Ensure custom fields registry is available
|
|
129
|
+
if (!strapi.customFields) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Register custom fields with proper error handling
|
|
134
|
+
customFields.forEach((field) => {
|
|
135
|
+
try {
|
|
136
|
+
|
|
137
|
+
const fieldConfig = {
|
|
138
|
+
name: field.name,
|
|
139
|
+
pluginId: PLUGIN_ID,
|
|
140
|
+
type: field.type,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Add validation function if it exists
|
|
144
|
+
if (field.validate) {
|
|
145
|
+
fieldConfig.validate = field.validate;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
strapi.customFields.register(fieldConfig);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
// Field registration failed - silently continue
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
bootstrap({ strapi }) {
|
|
156
|
+
// Bootstrap completed
|
|
157
|
+
},
|
|
158
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webbycrown/advanced-fields",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"strapi",
|
|
6
6
|
"plugin",
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
"./strapi-server": "./strapi-server.js"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"
|
|
28
|
+
"admin",
|
|
29
|
+
"strapi-server.js",
|
|
30
|
+
"strapi-server.mjs",
|
|
31
|
+
"index.js",
|
|
29
32
|
"README.md",
|
|
30
33
|
"LICENSE"
|
|
31
34
|
],
|
|
@@ -64,7 +67,7 @@
|
|
|
64
67
|
"displayName": "Advanced Fields",
|
|
65
68
|
"description": "Professional custom fields for Strapi: Advanced Input with validation, Advanced Checkbox (single/multiple), and Advanced Radio (single/multiple) with dynamic options and comprehensive configuration"
|
|
66
69
|
},
|
|
67
|
-
"description": "
|
|
70
|
+
"description": "Professional custom fields for Strapi: Advanced Input with validation, Advanced Checkbox (single/multiple), and Advanced Radio (single/multiple) with dynamic options and comprehensive configuration",
|
|
68
71
|
"license": "MIT",
|
|
69
72
|
"author": {
|
|
70
73
|
"name": "WebbyCrown",
|
package/strapi-server.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PLUGIN_ID = 'advanced-fields';
|
|
4
|
+
|
|
5
|
+
const customFields = [
|
|
6
|
+
{
|
|
7
|
+
name: 'input',
|
|
8
|
+
type: 'string',
|
|
9
|
+
validate: (value, { required, options = {} }) => {
|
|
10
|
+
// Parse field options
|
|
11
|
+
const {
|
|
12
|
+
minLength = 0,
|
|
13
|
+
maxLength = 0,
|
|
14
|
+
regex = '',
|
|
15
|
+
customErrorMessage = ''
|
|
16
|
+
} = options;
|
|
17
|
+
|
|
18
|
+
// Check required validation
|
|
19
|
+
if (required && (!value || value.trim().length === 0)) {
|
|
20
|
+
return customErrorMessage || 'This field is required';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// If no value, no additional validation needed
|
|
24
|
+
if (!value || value.trim().length === 0) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const stringValue = value.toString().trim();
|
|
29
|
+
|
|
30
|
+
// Check min/max length validation
|
|
31
|
+
if (minLength > 0 && stringValue.length < minLength) {
|
|
32
|
+
return customErrorMessage || `Minimum length is ${minLength} characters`;
|
|
33
|
+
}
|
|
34
|
+
if (maxLength > 0 && stringValue.length > maxLength) {
|
|
35
|
+
return customErrorMessage || `Maximum length is ${maxLength} characters`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check regex validation
|
|
39
|
+
if (regex && regex.trim()) {
|
|
40
|
+
try {
|
|
41
|
+
const regexPattern = new RegExp(regex);
|
|
42
|
+
if (!regexPattern.test(stringValue)) {
|
|
43
|
+
return customErrorMessage || 'Value does not match the required pattern';
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// Invalid regex pattern, skip validation
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'checkbox',
|
|
55
|
+
type: 'json',
|
|
56
|
+
validate: (value, { required, options = {} }) => {
|
|
57
|
+
// Parse field options
|
|
58
|
+
const {
|
|
59
|
+
checkboxType = 'single',
|
|
60
|
+
minChoices = 0,
|
|
61
|
+
maxChoices = 0,
|
|
62
|
+
customErrorMessage = ''
|
|
63
|
+
} = options;
|
|
64
|
+
|
|
65
|
+
// Check required validation
|
|
66
|
+
if (required) {
|
|
67
|
+
if (!value ||
|
|
68
|
+
(Array.isArray(value) && value.length === 0) ||
|
|
69
|
+
(typeof value === 'string' && value.trim() === '') ||
|
|
70
|
+
value === null ||
|
|
71
|
+
value === undefined) {
|
|
72
|
+
return customErrorMessage || 'This field is required';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// If no value, no additional validation needed
|
|
77
|
+
if (!value || (Array.isArray(value) && value.length === 0)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const values = Array.isArray(value) ? value : [];
|
|
82
|
+
|
|
83
|
+
// Check min/max choices validation (only for multiple mode)
|
|
84
|
+
if (checkboxType === 'multiple') {
|
|
85
|
+
if (minChoices > 0 && values.length < minChoices) {
|
|
86
|
+
return customErrorMessage || `Please select at least ${minChoices} option${minChoices > 1 ? 's' : ''}`;
|
|
87
|
+
}
|
|
88
|
+
if (maxChoices > 0 && values.length > maxChoices) {
|
|
89
|
+
return customErrorMessage || `Please select at most ${maxChoices} option${maxChoices > 1 ? 's' : ''}`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "radio",
|
|
98
|
+
type: "json",
|
|
99
|
+
validate: (value, { required, options = {} }) => {
|
|
100
|
+
// Parse field options
|
|
101
|
+
const {
|
|
102
|
+
selectionType = 'single',
|
|
103
|
+
minChoices = 0,
|
|
104
|
+
maxChoices = 0,
|
|
105
|
+
customErrorMessage = ''
|
|
106
|
+
} = options;
|
|
107
|
+
|
|
108
|
+
// Check required validation
|
|
109
|
+
if (required) {
|
|
110
|
+
if (!value ||
|
|
111
|
+
(Array.isArray(value) && value.length === 0) ||
|
|
112
|
+
(typeof value === 'string' && value.trim() === '') ||
|
|
113
|
+
value === null ||
|
|
114
|
+
value === undefined) {
|
|
115
|
+
return customErrorMessage || 'This field is required';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// If no value, no additional validation needed
|
|
120
|
+
if (!value || (Array.isArray(value) && value.length === 0)) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const values = Array.isArray(value) ? value : [];
|
|
125
|
+
|
|
126
|
+
// Check min/max choices validation (only for multiple mode)
|
|
127
|
+
if (selectionType === 'multiple') {
|
|
128
|
+
if (minChoices > 0 && values.length < minChoices) {
|
|
129
|
+
return customErrorMessage || `Please select at least ${minChoices} option${minChoices > 1 ? 's' : ''}`;
|
|
130
|
+
}
|
|
131
|
+
if (maxChoices > 0 && values.length > maxChoices) {
|
|
132
|
+
return customErrorMessage || `Please select at most ${maxChoices} option${maxChoices > 1 ? 's' : ''}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
register({ strapi }) {
|
|
143
|
+
// Ensure custom fields registry is available
|
|
144
|
+
if (!strapi.customFields) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Register custom fields with proper error handling
|
|
149
|
+
customFields.forEach((field) => {
|
|
150
|
+
try {
|
|
151
|
+
const fieldConfig = {
|
|
152
|
+
name: field.name,
|
|
153
|
+
plugin: PLUGIN_ID,
|
|
154
|
+
type: field.type,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Add validation function if it exists
|
|
158
|
+
if (field.validate) {
|
|
159
|
+
fieldConfig.validate = field.validate;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
strapi.customFields.register(fieldConfig);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
// Silent error handling
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
bootstrap({ strapi }) {
|
|
170
|
+
// Wait longer for registration to complete
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
// Verify all fields are registered only if customFields.get is available
|
|
173
|
+
if (strapi.customFields && typeof strapi.customFields.get === 'function') {
|
|
174
|
+
customFields.forEach((field) => {
|
|
175
|
+
try {
|
|
176
|
+
const registeredField = strapi.customFields.get(`${PLUGIN_ID}.${field.name}`);
|
|
177
|
+
// Field verification completed silently
|
|
178
|
+
} catch (error) {
|
|
179
|
+
// Silent error handling
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}, 1000);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PLUGIN_ID = 'advanced-fields';
|
|
4
|
+
|
|
5
|
+
const customFields = [
|
|
6
|
+
{
|
|
7
|
+
name: 'input',
|
|
8
|
+
type: 'string',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'checkbox',
|
|
12
|
+
type: 'json',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "radio",
|
|
16
|
+
type: "json"
|
|
17
|
+
}
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
register({ strapi }) {
|
|
22
|
+
console.log(`[${PLUGIN_ID}] Registering custom fields...`);
|
|
23
|
+
|
|
24
|
+
// Ensure custom fields registry is available
|
|
25
|
+
if (!strapi.customFields) {
|
|
26
|
+
console.error(`[${PLUGIN_ID}] Custom fields registry not available`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Register custom fields with proper error handling
|
|
31
|
+
customFields.forEach((field) => {
|
|
32
|
+
try {
|
|
33
|
+
console.log(`[${PLUGIN_ID}] Registering field: ${field.name} (type: ${field.type})`);
|
|
34
|
+
strapi.customFields.register({
|
|
35
|
+
name: field.name,
|
|
36
|
+
plugin: PLUGIN_ID,
|
|
37
|
+
type: field.type,
|
|
38
|
+
});
|
|
39
|
+
console.log(`[${PLUGIN_ID}] Successfully registered field: ${field.name}`);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(`[${PLUGIN_ID}] Failed to register field ${field.name}:`, error.message);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
console.log(`[${PLUGIN_ID}] All custom fields registration completed`);
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
bootstrap({ strapi }) {
|
|
49
|
+
console.log(`[${PLUGIN_ID}] Bootstrap starting...`);
|
|
50
|
+
|
|
51
|
+
// Wait longer for registration to complete
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
// Verify all fields are registered only if customFields.get is available
|
|
54
|
+
if (strapi.customFields && typeof strapi.customFields.get === 'function') {
|
|
55
|
+
customFields.forEach((field) => {
|
|
56
|
+
try {
|
|
57
|
+
const registeredField = strapi.customFields.get(`${PLUGIN_ID}.${field.name}`);
|
|
58
|
+
if (registeredField) {
|
|
59
|
+
console.log(`[${PLUGIN_ID}] ✅ Field verified: ${field.name}`);
|
|
60
|
+
} else {
|
|
61
|
+
console.error(`[${PLUGIN_ID}] ❌ Field not found in registry: ${field.name}`);
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(`[${PLUGIN_ID}] Error verifying field ${field.name}:`, error.message);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
console.log(`[${PLUGIN_ID}] Skipping field verification (customFields.get not available)`);
|
|
69
|
+
}
|
|
70
|
+
}, 1000);
|
|
71
|
+
|
|
72
|
+
console.log(`[${PLUGIN_ID}] Bootstrap completed`);
|
|
73
|
+
},
|
|
74
|
+
};
|