@reldens/cms 0.47.0 → 0.49.0
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/.claude/advanced-usage-guide.md +98 -0
- package/.claude/api-reference.md +146 -0
- package/.claude/configuration-guide.md +126 -0
- package/.claude/database-schema.md +32 -0
- package/.claude/forms-system-guide.md +193 -0
- package/.claude/installation-guide.md +223 -0
- package/.claude/multi-domain-i18n-guide.md +178 -0
- package/.claude/password-management-guide.md +426 -0
- package/.claude/search-guide.md +66 -0
- package/.claude/templating-system-guide.md +349 -0
- package/CLAUDE.md +92 -3
- package/README.md +71 -1447
- package/bin/reldens-cms-update-password.js +246 -0
- package/lib/admin-manager/router-contents.js +14 -2
- package/lib/admin-manager/router.js +1 -0
- package/lib/manager.js +70 -8
- package/lib/password-encryption-handler.js +94 -0
- package/lib/template-engine.js +8 -2
- package/package.json +5 -4
- package/templates/.env.dist +1 -1
- package/templates/page.html +15 -11
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Advanced Usage Guide
|
|
2
|
+
|
|
3
|
+
## Template Reloading for Development
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
7
|
+
|
|
8
|
+
const cms = new Manager({
|
|
9
|
+
reloadTime: isDevelopment ? -1 : 0,
|
|
10
|
+
cache: !isDevelopment,
|
|
11
|
+
entityAccess: {
|
|
12
|
+
articles: { public: true, operations: ['read'] },
|
|
13
|
+
cmsPages: { public: true, operations: ['read'] }
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Development Workflow with Template Reloading:**
|
|
19
|
+
|
|
20
|
+
1. Set `reloadTime: -1` for instant template updates
|
|
21
|
+
2. Edit admin templates in `admin/templates/` - changes appear immediately
|
|
22
|
+
3. Edit frontend templates in `templates/` - changes appear on next page load
|
|
23
|
+
4. No server restart needed for template changes
|
|
24
|
+
5. Switch to `reloadTime: 0` in production for optimal performance
|
|
25
|
+
|
|
26
|
+
## Event System
|
|
27
|
+
|
|
28
|
+
The CMS provides hooks for customization through event listeners:
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
cms.events.on('reldens.afterVariablesCreated', (eventData) => {
|
|
32
|
+
eventData.variables.customData = {
|
|
33
|
+
timestamp: Date.now(),
|
|
34
|
+
version: '1.0.0'
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
cms.events.on('reldens.beforeContentProcess', (eventData) => {
|
|
39
|
+
eventData.content = eventData.content.replace(/\[custom\]/g, 'Custom Value');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
cms.events.on('reldens.afterContentProcess', (eventData) => {
|
|
43
|
+
eventData.processedContent += '\n<!-- Processed at '+new Date()+' -->';
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
cms.events.on('reldens.templateReloader.templatesChanged', (eventData) => {
|
|
47
|
+
console.log('Templates changed:', eventData.changedFiles);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
cms.events.on('reldens.dynamicForm.afterSave', (eventData) => {
|
|
51
|
+
console.log('Form submission received:', eventData.result.id);
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Custom Authentication
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const customAuth = async (email, password, roleId) => {
|
|
59
|
+
let user = await yourAuthService.authenticate(email, password);
|
|
60
|
+
return user && user.role_id === roleId ? user : false;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const cms = new Manager({
|
|
64
|
+
authenticationMethod: 'custom',
|
|
65
|
+
authenticationCallback: customAuth
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## File Upload Configuration
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const uploadConfig = {
|
|
73
|
+
mimeTypes: {
|
|
74
|
+
image: ['image/jpeg', 'image/png', 'image/webp'],
|
|
75
|
+
document: ['application/pdf', 'text/plain']
|
|
76
|
+
},
|
|
77
|
+
allowedExtensions: {
|
|
78
|
+
image: ['.jpg', '.jpeg', '.png', '.webp'],
|
|
79
|
+
document: ['.pdf', '.txt']
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const cms = new Manager(uploadConfig);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Event Hooks
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
cms.events.on('reldens.setupAdminRoutes', ({adminManager}) => {
|
|
90
|
+
adminManager.adminRouter.get('/custom', (req, res) => {
|
|
91
|
+
res.send('Custom admin page');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
cms.events.on('adminEntityExtraData', ({entitySerializedData, entity}) => {
|
|
96
|
+
entitySerializedData.customField = 'Custom Value';
|
|
97
|
+
});
|
|
98
|
+
```
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## Manager Class
|
|
4
|
+
|
|
5
|
+
- `start()` - Initialize and start the CMS
|
|
6
|
+
- `isInstalled()` - Check if CMS is installed
|
|
7
|
+
- `initializeServices()` - Initialize all services
|
|
8
|
+
- `validateProvidedServer()` - Validate provided server instance
|
|
9
|
+
- `validateProvidedDataServer()` - Validate provided data server
|
|
10
|
+
- `validateProvidedAdminManager()` - Validate provided admin manager
|
|
11
|
+
- `validateProvidedFrontend()` - Validate provided frontend
|
|
12
|
+
- `buildAppServerConfiguration()` - Build server configuration
|
|
13
|
+
- `initializeCmsAfterInstall(props)` - Post-installation callback
|
|
14
|
+
|
|
15
|
+
## Installer Class
|
|
16
|
+
|
|
17
|
+
- `isInstalled()` - Check installation status
|
|
18
|
+
- `configureAppServerRoutes(app, appServer, appServerFactory, renderEngine)` - Setup installer routes
|
|
19
|
+
- `executeInstallProcess(req, res)` - Complete installation process
|
|
20
|
+
- `runSubprocessInstallation(dbConfig, templateVariables)` - Handle subprocess operations
|
|
21
|
+
- `checkAndInstallPackages(requiredPackages)` - Check and install dependencies
|
|
22
|
+
- `generateEntities(server, isOverride, isInstallationMode, isDryPrisma, dbConfig)` - Generate entities
|
|
23
|
+
- `createEnvFile(templateVariables)` - Create environment configuration
|
|
24
|
+
- `copyAdminDirectory()` - Copy admin assets and templates
|
|
25
|
+
|
|
26
|
+
## Frontend Architecture Classes
|
|
27
|
+
|
|
28
|
+
### Frontend Class (Orchestrator)
|
|
29
|
+
|
|
30
|
+
- `initialize()` - Set up frontend routes and templates
|
|
31
|
+
- `handleRequest(req, res)` - Main request handler
|
|
32
|
+
- `renderRoute(route, domain, res, req)` - Route-based rendering
|
|
33
|
+
- `setupStaticAssets()` - Configure static asset serving
|
|
34
|
+
|
|
35
|
+
### TemplateResolver Class
|
|
36
|
+
|
|
37
|
+
- `findTemplatePath(templateName, domain)` - Template discovery with domain fallback
|
|
38
|
+
- `findLayoutPath(layoutName, domain)` - Layout path resolution
|
|
39
|
+
- `findTemplateByPath(path, domain)` - Template lookup by URL path
|
|
40
|
+
- `resolveDomainToFolder(domain)` - Domain to folder mapping
|
|
41
|
+
- `resolveDomainToSiteKey(domain)` - Domain to site key mapping
|
|
42
|
+
|
|
43
|
+
### TemplateCache Class
|
|
44
|
+
|
|
45
|
+
- `loadPartials()` - Load and cache template partials
|
|
46
|
+
- `setupDomainTemplates()` - Initialize domain-specific templates
|
|
47
|
+
- `getPartialsForDomain(domain)` - Get domain-specific partials with fallback
|
|
48
|
+
|
|
49
|
+
### TemplateReloader Class
|
|
50
|
+
|
|
51
|
+
- `checkAndReloadAdminTemplates()` - Check and reload admin templates when changed
|
|
52
|
+
- `checkAndReloadFrontendTemplates()` - Check and reload frontend templates when changed
|
|
53
|
+
- `trackTemplateFiles(templatesPaths)` - Start tracking template files for changes
|
|
54
|
+
- `shouldReloadAdminTemplates(mappedAdminTemplates)` - Check if admin templates need reloading
|
|
55
|
+
- `shouldReloadFrontendTemplates(templatesPath, templateExtensions)` - Check if frontend templates need reloading
|
|
56
|
+
- `handleAdminTemplateReload(adminManager)` - Complete admin template reload process
|
|
57
|
+
- `handleFrontendTemplateReload(templateCache, templateResolver)` - Complete frontend template reload process
|
|
58
|
+
|
|
59
|
+
### RequestProcessor Class
|
|
60
|
+
|
|
61
|
+
- `findRouteByPath(path, domain)` - Database route lookup
|
|
62
|
+
- `handleRouteRedirect(route, res)` - Handle route redirects
|
|
63
|
+
- `getDomainFromRequest(req)` - Extract domain from request
|
|
64
|
+
- `buildCacheKey(path, req)` - Generate cache keys
|
|
65
|
+
|
|
66
|
+
### ContentRenderer Class
|
|
67
|
+
|
|
68
|
+
- `renderWithTemplateContent(content, data, domain, req, route)` - Main content rendering
|
|
69
|
+
- `generateRouteContent(route, domain, req)` - Route-based content generation
|
|
70
|
+
- `generateTemplateContent(templatePath, domain, req, data)` - Template-based content generation
|
|
71
|
+
- `fetchMetaFields(data)` - Process meta fields for templates
|
|
72
|
+
|
|
73
|
+
### EntityAccessManager Class
|
|
74
|
+
|
|
75
|
+
- `loadEntityAccessRules()` - Load entity access configuration
|
|
76
|
+
- `isEntityAccessible(entityName)` - Check entity accessibility
|
|
77
|
+
- `findEntityByPath(path)` - Entity lookup by URL path
|
|
78
|
+
|
|
79
|
+
### ResponseManager Class
|
|
80
|
+
|
|
81
|
+
- `renderWithCacheHandler(contentGenerator, errorHandler, responseHandler, domain, res, path, req)` - Generic cached response handler
|
|
82
|
+
- `renderNotFound(domain, res, req)` - 404 error handling
|
|
83
|
+
|
|
84
|
+
### SearchRequestHandler Class
|
|
85
|
+
|
|
86
|
+
- `handleSearchRequest(req, res)` - Process search requests with template data support
|
|
87
|
+
|
|
88
|
+
## TemplateEngine Class
|
|
89
|
+
|
|
90
|
+
- `render(template, data, partials, domain, req, route, currentEntityData)` - Main template rendering with enhanced context
|
|
91
|
+
- `processAllTemplateFunctions(template, domain, req, systemVariables)` - Process all template functions
|
|
92
|
+
- `buildEnhancedRenderData(data, systemVariables, currentEntityData)` - Build template context with system variables
|
|
93
|
+
|
|
94
|
+
## SystemVariablesProvider Class
|
|
95
|
+
|
|
96
|
+
- `buildSystemVariables(req, route, domain)` - Create system variables for templates
|
|
97
|
+
- `buildCurrentRequestData(req, domain)` - Build request context
|
|
98
|
+
- `buildCurrentRouteData(route)` - Build route context
|
|
99
|
+
- `buildCurrentDomainData(domain)` - Build domain context
|
|
100
|
+
|
|
101
|
+
## Search Classes
|
|
102
|
+
|
|
103
|
+
- `Search.parseSearchParameters(query)` - Parse search query parameters including templateData
|
|
104
|
+
- `Search.executeSearch(config)` - Execute search with configuration
|
|
105
|
+
- `SearchRenderer.renderSearchResults(searchResults, config, domain, req)` - Render search results with template data
|
|
106
|
+
|
|
107
|
+
## Forms System Classes
|
|
108
|
+
|
|
109
|
+
### DynamicForm Class
|
|
110
|
+
|
|
111
|
+
- `validateFormSubmission(formKey, submittedValues, req)` - Validate form submission
|
|
112
|
+
- `getFormConfig(formKey)` - Load form configuration from database
|
|
113
|
+
- `validateHoneypot(submittedValues)` - Check honeypot field for bots
|
|
114
|
+
- `validateFields(fieldsSchema, submittedValues)` - Schema-based field validation
|
|
115
|
+
- `prepareSubmittedValues(submittedValues, fieldsSchema)` - Process and normalize values
|
|
116
|
+
- `saveFormSubmission(formConfig, preparedValues)` - Save to database
|
|
117
|
+
|
|
118
|
+
### DynamicFormRenderer Class
|
|
119
|
+
|
|
120
|
+
- `renderForm(formConfig, fieldsToRender, domain, req, attributes)` - Render complete form
|
|
121
|
+
- `renderFormFields(fieldsToRender, domain, req)` - Render field set
|
|
122
|
+
- `renderFormField(field, domain, submittedValues, errors)` - Render individual field
|
|
123
|
+
- `loadFormTemplate(templateName, domain)` - Load form template with domain fallback
|
|
124
|
+
- `findFormTemplate(templateName, domain)` - Template discovery for forms
|
|
125
|
+
|
|
126
|
+
### DynamicFormRequestHandler Class
|
|
127
|
+
|
|
128
|
+
- `handleFormSubmission(req, res)` - Process POST form submissions
|
|
129
|
+
- `handleBadRequest(res, message)` - Handle validation errors
|
|
130
|
+
- `handleSuccessResponse(req, res, formKey, result)` - Handle successful submissions
|
|
131
|
+
- `buildErrorRedirectPath(req, error, formKey)` - Build error redirect URLs
|
|
132
|
+
- `buildSuccessRedirectPath(successRedirect, formKey)` - Build success redirect URLs
|
|
133
|
+
|
|
134
|
+
### FormsTransformer Class
|
|
135
|
+
|
|
136
|
+
- `transform(template, domain, req, systemVariables, enhancedData)` - Process cmsForm tags
|
|
137
|
+
- `findAllFormTags(template)` - Find cmsForm tags in template
|
|
138
|
+
- `parseFormAttributes(fullTag)` - Parse tag attributes
|
|
139
|
+
- `parseFieldsFilter(attributes, formConfig)` - Filter fields based on attributes
|
|
140
|
+
|
|
141
|
+
## AdminManager Class
|
|
142
|
+
|
|
143
|
+
- `setupAdmin()` - Initialize admin panel
|
|
144
|
+
- `generateListRouteContent()` - Entity list pages
|
|
145
|
+
- `generateEditRouteContent()` - Entity edit forms
|
|
146
|
+
- `processSaveEntity()` - Handle form submissions
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Configuration Guide
|
|
2
|
+
|
|
3
|
+
## Environment Variables
|
|
4
|
+
|
|
5
|
+
```env
|
|
6
|
+
RELDENS_APP_HOST=http://localhost
|
|
7
|
+
RELDENS_APP_PORT=8080
|
|
8
|
+
RELDENS_ADMIN_ROUTE_PATH=/admin
|
|
9
|
+
RELDENS_ADMIN_SECRET=your-secret-key
|
|
10
|
+
|
|
11
|
+
RELDENS_DB_CLIENT=mysql
|
|
12
|
+
RELDENS_DB_HOST=localhost
|
|
13
|
+
RELDENS_DB_PORT=3306
|
|
14
|
+
RELDENS_DB_NAME=cms_db
|
|
15
|
+
RELDENS_DB_USER=username
|
|
16
|
+
RELDENS_DB_PASSWORD=password
|
|
17
|
+
RELDENS_STORAGE_DRIVER=prisma
|
|
18
|
+
|
|
19
|
+
RELDENS_DEFAULT_DOMAIN=example.com
|
|
20
|
+
RELDENS_DOMAIN_MAPPING={"dev.example.com":"development"}
|
|
21
|
+
RELDENS_SITE_KEY_MAPPING={"example.com":"main"}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Template Reloading Configuration
|
|
25
|
+
|
|
26
|
+
Configure template reloading for development environments:
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
const cms = new Manager({
|
|
30
|
+
// Development: reload templates on every request when changes detected
|
|
31
|
+
reloadTime: -1,
|
|
32
|
+
|
|
33
|
+
// Production: disable template reloading (default)
|
|
34
|
+
reloadTime: 0,
|
|
35
|
+
|
|
36
|
+
// Interval-based: reload every 5 seconds when changes detected
|
|
37
|
+
reloadTime: 5000
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Template Reloading Options:**
|
|
42
|
+
|
|
43
|
+
- `reloadTime: 0` (default) - Template reloading disabled. Templates load once at startup.
|
|
44
|
+
- `reloadTime: -1` - Reload templates on every request when file changes are detected. Best for active development.
|
|
45
|
+
- `reloadTime: > 0` - Check for template changes at specified interval (milliseconds) and reload when needed. Good for development with lower overhead.
|
|
46
|
+
|
|
47
|
+
**How it works:**
|
|
48
|
+
|
|
49
|
+
- Tracks file modification times for admin and frontend templates
|
|
50
|
+
- Only reloads templates that have actually changed
|
|
51
|
+
- Automatically updates admin contents and frontend template cache
|
|
52
|
+
- Works with both admin panel templates and frontend templates/partials
|
|
53
|
+
- Zero performance impact when disabled (`reloadTime: 0`)
|
|
54
|
+
|
|
55
|
+
## Custom Entity Configuration
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const entityConfig = {
|
|
59
|
+
articles: {
|
|
60
|
+
listProperties: ['title', 'status', 'created_at'],
|
|
61
|
+
showProperties: ['title', 'content', 'author', 'status'],
|
|
62
|
+
editProperties: ['title', 'content', 'author_id', 'status'],
|
|
63
|
+
filterProperties: ['status', 'author_id'],
|
|
64
|
+
titleProperty: 'title',
|
|
65
|
+
parentItemLabel: 'Content',
|
|
66
|
+
properties: {
|
|
67
|
+
title: { type: 'string', isRequired: true },
|
|
68
|
+
content: { type: 'text' },
|
|
69
|
+
author_id: { type: 'reference', reference: 'users' },
|
|
70
|
+
featured_image: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
isUpload: true,
|
|
73
|
+
allowedTypes: 'image',
|
|
74
|
+
bucket: 'uploads'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const cms = new Manager({
|
|
81
|
+
entitiesConfig: entityConfig
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Manager Configuration Options
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
const cms = new Manager({
|
|
89
|
+
projectRoot: process.cwd(),
|
|
90
|
+
|
|
91
|
+
// Entity Access Control
|
|
92
|
+
entityAccess: {
|
|
93
|
+
cmsPages: { public: true, operations: ['read'] },
|
|
94
|
+
articles: { public: true, operations: ['read'] },
|
|
95
|
+
users: { public: false }
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
// Authentication
|
|
99
|
+
authenticationMethod: 'db-users',
|
|
100
|
+
adminRoleId: 99,
|
|
101
|
+
authenticationCallback: async (email, password, roleId) => {
|
|
102
|
+
return await yourAuthService.validate(email, password, roleId);
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
// Performance
|
|
106
|
+
cache: true,
|
|
107
|
+
reloadTime: 0,
|
|
108
|
+
|
|
109
|
+
// Multi-Domain
|
|
110
|
+
defaultDomain: 'example.com',
|
|
111
|
+
domainMapping: {'dev.example.com': 'development'},
|
|
112
|
+
siteKeyMapping: {'example.com': 'main'},
|
|
113
|
+
|
|
114
|
+
// Custom Entities
|
|
115
|
+
entitiesConfig: entityConfig,
|
|
116
|
+
entitiesTranslations: {},
|
|
117
|
+
adminTranslations: {},
|
|
118
|
+
|
|
119
|
+
// Optional Custom Services
|
|
120
|
+
app: customExpressApp,
|
|
121
|
+
appServer: customAppServer,
|
|
122
|
+
dataServer: customDataServer,
|
|
123
|
+
adminManager: customAdmin,
|
|
124
|
+
frontend: customFrontend
|
|
125
|
+
});
|
|
126
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Database Schema
|
|
2
|
+
|
|
3
|
+
## Core Tables
|
|
4
|
+
|
|
5
|
+
- `routes` - URL routing and SEO metadata
|
|
6
|
+
- `cms_pages` - Page content with layout assignments
|
|
7
|
+
- `cms_blocks` - Reusable content blocks
|
|
8
|
+
- `entities_access` - Entity access control rules
|
|
9
|
+
- `entities_meta` - Generic metadata storage
|
|
10
|
+
- `cms_pages_meta` - Page-specific metadata
|
|
11
|
+
|
|
12
|
+
## Forms Tables
|
|
13
|
+
|
|
14
|
+
- `cms_forms` - Form configurations with JSON schema
|
|
15
|
+
- `cms_forms_submitted` - Form submissions with JSON data
|
|
16
|
+
|
|
17
|
+
## User Management Tables (Optional)
|
|
18
|
+
|
|
19
|
+
- `users` - User authentication with encrypted passwords
|
|
20
|
+
- `roles` - Role definitions
|
|
21
|
+
|
|
22
|
+
## Installation Options
|
|
23
|
+
|
|
24
|
+
The installer provides checkboxes for:
|
|
25
|
+
|
|
26
|
+
- CMS core tables
|
|
27
|
+
- User authentication system
|
|
28
|
+
- Default admin user
|
|
29
|
+
- Default homepage
|
|
30
|
+
- Default content blocks
|
|
31
|
+
- Entity access control rules
|
|
32
|
+
- Dynamic forms system
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Dynamic Forms System Guide
|
|
2
|
+
|
|
3
|
+
## Basic Form Usage
|
|
4
|
+
|
|
5
|
+
Create forms in your templates using the `<cmsForm>` tag:
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<cmsForm key="contactForm"/>
|
|
9
|
+
<cmsForm key="contactForm" fields="name,email,subject,message"/>
|
|
10
|
+
<cmsForm key="newsletterSignup"
|
|
11
|
+
fields="email,name"
|
|
12
|
+
submitButtonText="Subscribe Now"
|
|
13
|
+
cssClass="newsletter-form"
|
|
14
|
+
successRedirect="/thank-you"
|
|
15
|
+
errorRedirect="/contact-error"/>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Form Configuration
|
|
19
|
+
|
|
20
|
+
Forms are configured in the `cms_forms` table via the admin panel.
|
|
21
|
+
|
|
22
|
+
### Supported Field Types
|
|
23
|
+
|
|
24
|
+
- **text** - Basic text input with maxLength, pattern validation
|
|
25
|
+
- **email** - Email input with built-in email validation
|
|
26
|
+
- **number** - Numeric input with min/max validation
|
|
27
|
+
- **textarea** - Multi-line text with maxLength
|
|
28
|
+
- **select** - Dropdown with options array
|
|
29
|
+
- **password** - Password input (masked)
|
|
30
|
+
- **tel** - Phone number input
|
|
31
|
+
- **url** - URL input with validation
|
|
32
|
+
- **date** - Date picker input
|
|
33
|
+
|
|
34
|
+
### Field Schema Properties
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"name": "fieldName",
|
|
39
|
+
"type": "text",
|
|
40
|
+
"label": "Field Label",
|
|
41
|
+
"required": true,
|
|
42
|
+
"placeholder": "Enter text...",
|
|
43
|
+
"helpText": "Additional help",
|
|
44
|
+
"maxLength": 100,
|
|
45
|
+
"minLength": 3,
|
|
46
|
+
"pattern": "^[A-Za-z]+$",
|
|
47
|
+
"min": 0,
|
|
48
|
+
"max": 100,
|
|
49
|
+
"step": 1,
|
|
50
|
+
"defaultValue": "default",
|
|
51
|
+
"options": [
|
|
52
|
+
{"value": "val1", "label": "Option 1"},
|
|
53
|
+
{"value": "val2", "label": "Option 2"}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Security Features
|
|
59
|
+
|
|
60
|
+
### Honeypot Protection
|
|
61
|
+
|
|
62
|
+
Automatic bot detection using invisible fields.
|
|
63
|
+
|
|
64
|
+
### Server-Side Validation
|
|
65
|
+
|
|
66
|
+
- SchemaValidator integration
|
|
67
|
+
- Required field validation
|
|
68
|
+
- Type validation
|
|
69
|
+
- Length limits
|
|
70
|
+
- Custom validation
|
|
71
|
+
|
|
72
|
+
### Data Sanitization
|
|
73
|
+
|
|
74
|
+
- XSS protection
|
|
75
|
+
- Input normalization
|
|
76
|
+
- Length truncation
|
|
77
|
+
|
|
78
|
+
### Rate Limiting
|
|
79
|
+
|
|
80
|
+
Uses AppServerFactory integration from server-utils.
|
|
81
|
+
|
|
82
|
+
## Template Customization
|
|
83
|
+
|
|
84
|
+
Forms use a domain-aware template fallback system:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
templates/
|
|
88
|
+
├── domains/
|
|
89
|
+
│ └── example.com/
|
|
90
|
+
│ └── cms_forms/
|
|
91
|
+
│ ├── form.html
|
|
92
|
+
│ ├── field_text.html
|
|
93
|
+
│ └── field_email.html
|
|
94
|
+
└── cms_forms/
|
|
95
|
+
├── form.html
|
|
96
|
+
├── field_text.html
|
|
97
|
+
├── field_email.html
|
|
98
|
+
├── field_textarea.html
|
|
99
|
+
├── field_select.html
|
|
100
|
+
└── field_number.html
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Event System Integration
|
|
104
|
+
|
|
105
|
+
### Available Form Events
|
|
106
|
+
|
|
107
|
+
- `reldens.formsTransformer.beforeRender` - Before form rendering
|
|
108
|
+
- `reldens.formsTransformer.afterRender` - After form rendering
|
|
109
|
+
- `reldens.dynamicForm.beforeValidation` - Before form validation
|
|
110
|
+
- `reldens.dynamicForm.afterValidation` - After form validation
|
|
111
|
+
- `reldens.dynamicForm.beforeSave` - Before saving to database
|
|
112
|
+
- `reldens.dynamicForm.afterSave` - After successful save
|
|
113
|
+
- `reldens.dynamicFormRenderer.beforeFieldsRender` - Before rendering fields
|
|
114
|
+
- `reldens.dynamicFormRenderer.afterFieldsRender` - After rendering fields
|
|
115
|
+
- `reldens.dynamicFormRequestHandler.beforeValidation` - Before request validation
|
|
116
|
+
- `reldens.dynamicFormRequestHandler.beforeSave` - Before save process
|
|
117
|
+
- `reldens.dynamicFormRequestHandler.afterSave` - After successful save
|
|
118
|
+
|
|
119
|
+
### Example Event Usage
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
cms.events.on('reldens.formsTransformer.beforeRender', (eventData) => {
|
|
123
|
+
eventData.formAttributes.cssClass += ' custom-form';
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
cms.events.on('reldens.dynamicForm.afterSave', (eventData) => {
|
|
127
|
+
console.log('Form saved:', eventData.result.id);
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Database Tables
|
|
132
|
+
|
|
133
|
+
### cms_forms Table
|
|
134
|
+
|
|
135
|
+
```sql
|
|
136
|
+
CREATE TABLE `cms_forms` (
|
|
137
|
+
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
138
|
+
`form_key` VARCHAR(255) NOT NULL UNIQUE,
|
|
139
|
+
`fields_schema` JSON NOT NULL,
|
|
140
|
+
`enabled` TINYINT UNSIGNED NOT NULL DEFAULT '0',
|
|
141
|
+
`created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
|
|
142
|
+
`updated_at` TIMESTAMP NOT NULL DEFAULT (NOW()) ON UPDATE CURRENT_TIMESTAMP,
|
|
143
|
+
PRIMARY KEY (`id`)
|
|
144
|
+
);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### cms_forms_submitted Table
|
|
148
|
+
|
|
149
|
+
```sql
|
|
150
|
+
CREATE TABLE `cms_forms_submitted` (
|
|
151
|
+
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
152
|
+
`form_id` INT UNSIGNED NOT NULL,
|
|
153
|
+
`submitted_values` JSON NOT NULL,
|
|
154
|
+
`created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
|
|
155
|
+
PRIMARY KEY (`id`),
|
|
156
|
+
FOREIGN KEY (`form_id`) REFERENCES `cms_forms`(`id`)
|
|
157
|
+
);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Form Processing Flow
|
|
161
|
+
|
|
162
|
+
1. Template Processing - FormsTransformer finds cmsForm tags
|
|
163
|
+
2. Form Loading - Loads form configuration from database
|
|
164
|
+
3. Field Filtering - Applies field filter if specified
|
|
165
|
+
4. Template Rendering - Renders form using domain-aware templates
|
|
166
|
+
5. Form Submission - POST request to /dynamic-form endpoint
|
|
167
|
+
6. Validation - Honeypot, required fields, and schema validation
|
|
168
|
+
7. Data Processing - Input sanitization and normalization
|
|
169
|
+
8. Database Storage - Save to cms_forms_submitted table
|
|
170
|
+
9. Response - Redirect with success/error parameters
|
|
171
|
+
|
|
172
|
+
## Advanced Usage
|
|
173
|
+
|
|
174
|
+
### AJAX Form Submissions
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const cms = new Manager({
|
|
178
|
+
enableJsonResponse: true
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
document.querySelector('.dynamic-form').addEventListener('submit', async function(e) {
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
let response = await fetch('/dynamic-form', {method: 'POST', body: new FormData(this)});
|
|
186
|
+
let result = await response.json();
|
|
187
|
+
if(result.success){
|
|
188
|
+
alert('Form submitted successfully!');
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
alert('Error: '+result.error);
|
|
192
|
+
});
|
|
193
|
+
```
|