@reldens/cms 0.20.0 → 0.23.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/README.md +648 -12
- package/admin/reldens-admin-client.css +77 -141
- package/admin/reldens-admin-client.js +108 -133
- package/admin/templates/clear-all-cache-button.html +7 -7
- package/admin/templates/edit.html +7 -0
- package/admin/templates/fields/view/audio.html +7 -0
- package/admin/templates/fields/view/audios.html +8 -0
- package/admin/templates/layout.html +15 -9
- package/admin/templates/list-content.html +4 -2
- package/admin/templates/list.html +24 -8
- package/admin/templates/view.html +21 -0
- package/install/index.html +4 -0
- package/lib/admin-manager/admin-filters-manager.js +177 -0
- package/lib/admin-manager/contents-builder.js +1 -0
- package/lib/admin-manager/default-translations.js +38 -0
- package/lib/admin-manager/router-contents.js +64 -52
- package/lib/admin-manager/router.js +19 -0
- package/lib/dynamic-form-renderer.js +228 -0
- package/lib/dynamic-form-request-handler.js +135 -0
- package/lib/dynamic-form.js +310 -0
- package/lib/frontend/content-renderer.js +178 -0
- package/lib/frontend/entity-access-manager.js +63 -0
- package/lib/frontend/request-processor.js +128 -0
- package/lib/frontend/response-manager.js +54 -0
- package/lib/frontend/template-cache.js +102 -0
- package/lib/frontend/template-resolver.js +111 -0
- package/lib/frontend.js +122 -629
- package/lib/installer.js +2 -1
- package/lib/manager.js +25 -12
- package/lib/search-renderer.js +15 -7
- package/lib/search-request-handler.js +67 -0
- package/lib/search.js +13 -1
- package/lib/template-engine/collections-single-transformer.js +11 -5
- package/lib/template-engine/collections-transformer.js +47 -34
- package/lib/template-engine/entities-transformer.js +3 -2
- package/lib/template-engine/forms-transformer.js +187 -0
- package/lib/template-engine/partials-transformer.js +5 -6
- package/lib/template-engine/system-variables-provider.js +4 -1
- package/lib/template-engine.js +28 -5
- package/lib/template-reloader.js +307 -0
- package/lib/templates-list.js +2 -0
- package/migrations/default-forms.sql +22 -0
- package/package.json +5 -5
- package/templates/{browserconfig.xml → assets/favicons/default/browserconfig.xml} +1 -1
- package/templates/assets/favicons/default/favicon.ico +0 -0
- package/templates/{site.webmanifest → assets/favicons/default/site.webmanifest} +3 -3
- package/templates/cms_forms/field_email.html +14 -0
- package/templates/cms_forms/field_number.html +17 -0
- package/templates/cms_forms/field_select.html +15 -0
- package/templates/cms_forms/field_text.html +16 -0
- package/templates/cms_forms/field_textarea.html +13 -0
- package/templates/cms_forms/form.html +22 -0
- package/templates/css/styles.css +4 -0
- package/templates/js/functions.js +144 -0
- package/templates/js/scripts.js +5 -0
- package/templates/page.html +11 -5
- package/templates/partials/pagedCollection.html +1 -1
- package/lib/admin-translations.js +0 -56
- package/templates/favicon.ico +0 -0
- /package/templates/assets/favicons/{android-icon-144x144.png → default/android-icon-144x144.png} +0 -0
- /package/templates/assets/favicons/{android-icon-192x192.png → default/android-icon-192x192.png} +0 -0
- /package/templates/assets/favicons/{android-icon-512x512.png → default/android-icon-512x512.png} +0 -0
- /package/templates/assets/favicons/{apple-touch-icon.png → default/apple-touch-icon.png} +0 -0
- /package/templates/assets/favicons/{favicon-16x16.png → default/favicon-16x16.png} +0 -0
- /package/templates/assets/favicons/{favicon-32x32.png → default/favicon-32x32.png} +0 -0
- /package/templates/assets/favicons/{mstile-150x150.png → default/mstile-150x150.png} +0 -0
- /package/templates/assets/favicons/{safari-pinned-tab.svg → default/safari-pinned-tab.svg} +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Reldens CMS
|
|
4
4
|
|
|
5
|
-
A powerful, flexible Content Management System built with Node.js, featuring an admin panel, multi-domain frontend support, enhanced templating with reusable content blocks, system variables, internationalization, and automated installation.
|
|
5
|
+
A powerful, flexible Content Management System built with Node.js, featuring an admin panel, multi-domain frontend support, enhanced templating with reusable content blocks, system variables, internationalization, template reloading, dynamic forms, and automated installation.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
@@ -29,6 +29,9 @@ A powerful, flexible Content Management System built with Node.js, featuring an
|
|
|
29
29
|
- **Template functions** for URLs, assets, dates, and translations
|
|
30
30
|
- **Event-driven rendering** with hooks for customization
|
|
31
31
|
- **Custom 404 handling**
|
|
32
|
+
- **Advanced search functionality** with template data support
|
|
33
|
+
- **Dynamic forms system** with template transformers and security features
|
|
34
|
+
- **Template reloading** for development with configurable reload strategies
|
|
32
35
|
|
|
33
36
|
### - Admin Panel
|
|
34
37
|
- **Full CRUD operations** for all entities including content blocks
|
|
@@ -47,15 +50,56 @@ A powerful, flexible Content Management System built with Node.js, featuring an
|
|
|
47
50
|
- **Translation support** for entity labels and properties
|
|
48
51
|
- **Content blocks management** via cms_blocks table
|
|
49
52
|
- **Entity access control** via entities_access table
|
|
53
|
+
- **Dynamic forms storage** via cms_forms and cms_forms_submitted tables
|
|
50
54
|
|
|
51
55
|
### - Configuration & Architecture
|
|
52
56
|
- **Environment-based configuration** (.env file)
|
|
53
|
-
- **Modular service architecture**
|
|
57
|
+
- **Modular service architecture** with specialized classes for better maintainability
|
|
54
58
|
- **Event-driven system** with hooks for customization
|
|
55
59
|
- **Extensible authentication** (database users or custom callbacks)
|
|
56
60
|
- **File security** with path validation and dangerous key filtering
|
|
57
61
|
- **Internationalization support** with translation files
|
|
58
62
|
|
|
63
|
+
## Architecture
|
|
64
|
+
|
|
65
|
+
### Core Classes
|
|
66
|
+
The CMS uses a modular architecture with specialized classes:
|
|
67
|
+
|
|
68
|
+
**Frontend Orchestrator:**
|
|
69
|
+
- `Frontend` - Main orchestrator class that coordinates all frontend operations
|
|
70
|
+
|
|
71
|
+
**Template Management:**
|
|
72
|
+
- `TemplateResolver` - Template discovery and domain resolution
|
|
73
|
+
- `TemplateCache` - Template and partial caching management
|
|
74
|
+
- `TemplateReloader` - Template reloading with file change detection
|
|
75
|
+
|
|
76
|
+
**Request Processing:**
|
|
77
|
+
- `RequestProcessor` - HTTP request routing and path handling
|
|
78
|
+
- `SearchRequestHandler` - Dedicated search request processing
|
|
79
|
+
- `DynamicFormRequestHandler` - Form submission processing
|
|
80
|
+
|
|
81
|
+
**Content Management:**
|
|
82
|
+
- `ContentRenderer` - Content generation and template processing
|
|
83
|
+
- `EntityAccessManager` - Entity access control and loading
|
|
84
|
+
|
|
85
|
+
**Response Handling:**
|
|
86
|
+
- `ResponseManager` - HTTP response handling and caching logic
|
|
87
|
+
|
|
88
|
+
**Template Processing:**
|
|
89
|
+
- `TemplateEngine` - Core template rendering with enhanced context
|
|
90
|
+
- `SystemVariablesProvider` - System variables for templates
|
|
91
|
+
- `FormsTransformer` - Dynamic forms template transformer
|
|
92
|
+
|
|
93
|
+
**Forms System:**
|
|
94
|
+
- `DynamicForm` - Form validation and data processing
|
|
95
|
+
- `DynamicFormRenderer` - Template-based form rendering
|
|
96
|
+
|
|
97
|
+
This architecture follows SOLID principles, providing better:
|
|
98
|
+
- **Testability** - Individual components can be tested in isolation
|
|
99
|
+
- **Maintainability** - Changes to one area don't affect others
|
|
100
|
+
- **Reusability** - Components can be reused in different contexts
|
|
101
|
+
- **Readability** - Smaller, focused classes are easier to understand
|
|
102
|
+
|
|
59
103
|
## Installation
|
|
60
104
|
|
|
61
105
|
### Method 1: Automated Web Installer
|
|
@@ -102,6 +146,34 @@ RELDENS_DOMAIN_MAPPING={"dev.example.com":"development"}
|
|
|
102
146
|
RELDENS_SITE_KEY_MAPPING={"example.com":"main"}
|
|
103
147
|
```
|
|
104
148
|
|
|
149
|
+
### Template Reloading Configuration
|
|
150
|
+
Configure template reloading for development environments:
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
const cms = new Manager({
|
|
154
|
+
// Development: reload templates on every request when changes detected
|
|
155
|
+
reloadTime: -1,
|
|
156
|
+
|
|
157
|
+
// Production: disable template reloading (default)
|
|
158
|
+
reloadTime: 0,
|
|
159
|
+
|
|
160
|
+
// Interval-based: reload every 5 seconds when changes detected
|
|
161
|
+
reloadTime: 5000
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Template Reloading Options:**
|
|
166
|
+
- **`reloadTime: 0`** (default) - Template reloading disabled. Templates load once at startup.
|
|
167
|
+
- **`reloadTime: -1`** - Reload templates on every request when file changes are detected. Best for active development.
|
|
168
|
+
- **`reloadTime: > 0`** - Check for template changes at specified interval (milliseconds) and reload when needed. Good for development with lower overhead.
|
|
169
|
+
|
|
170
|
+
**How it works:**
|
|
171
|
+
- Tracks file modification times for admin and frontend templates
|
|
172
|
+
- Only reloads templates that have actually changed
|
|
173
|
+
- Automatically updates admin contents and frontend template cache
|
|
174
|
+
- Works with both admin panel templates and frontend templates/partials
|
|
175
|
+
- Zero performance impact when disabled (`reloadTime: 0`)
|
|
176
|
+
|
|
105
177
|
### Custom Entity Configuration
|
|
106
178
|
```javascript
|
|
107
179
|
const entityConfig = {
|
|
@@ -131,6 +203,413 @@ const cms = new Manager({
|
|
|
131
203
|
});
|
|
132
204
|
```
|
|
133
205
|
|
|
206
|
+
## Dynamic Forms System
|
|
207
|
+
|
|
208
|
+
### Basic Form Usage
|
|
209
|
+
Create forms in your templates using the `<cmsForm>` tag:
|
|
210
|
+
|
|
211
|
+
```html
|
|
212
|
+
<!-- Render all form fields -->
|
|
213
|
+
<cmsForm key="contactForm"/>
|
|
214
|
+
|
|
215
|
+
<!-- Render specific fields only -->
|
|
216
|
+
<cmsForm key="contactForm" fields="name,email,subject,message"/>
|
|
217
|
+
|
|
218
|
+
<!-- Custom form attributes -->
|
|
219
|
+
<cmsForm key="newsletterSignup"
|
|
220
|
+
fields="email,name"
|
|
221
|
+
submitButtonText="Subscribe Now"
|
|
222
|
+
cssClass="newsletter-form"
|
|
223
|
+
successRedirect="/thank-you"
|
|
224
|
+
errorRedirect="/contact-error"/>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Form Configuration in Database
|
|
228
|
+
Forms are configured in the `cms_forms` table via the admin panel:
|
|
229
|
+
|
|
230
|
+
```sql
|
|
231
|
+
-- Example form configuration
|
|
232
|
+
INSERT INTO cms_forms (form_key, fields_schema, enabled) VALUES
|
|
233
|
+
('contactForm', '[
|
|
234
|
+
{
|
|
235
|
+
"name": "name",
|
|
236
|
+
"type": "text",
|
|
237
|
+
"label": "Full Name",
|
|
238
|
+
"required": true,
|
|
239
|
+
"maxLength": 100,
|
|
240
|
+
"placeholder": "Enter your full name"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"name": "email",
|
|
244
|
+
"type": "email",
|
|
245
|
+
"label": "Email Address",
|
|
246
|
+
"required": true,
|
|
247
|
+
"placeholder": "your@email.com"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"name": "subject",
|
|
251
|
+
"type": "select",
|
|
252
|
+
"label": "Subject",
|
|
253
|
+
"required": true,
|
|
254
|
+
"options": [
|
|
255
|
+
{"value": "general", "label": "General Inquiry"},
|
|
256
|
+
{"value": "support", "label": "Technical Support"},
|
|
257
|
+
{"value": "sales", "label": "Sales Question"}
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"name": "message",
|
|
262
|
+
"type": "textarea",
|
|
263
|
+
"label": "Message",
|
|
264
|
+
"required": true,
|
|
265
|
+
"maxLength": 1000,
|
|
266
|
+
"placeholder": "Enter your message here..."
|
|
267
|
+
}
|
|
268
|
+
]', 1);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Supported Field Types
|
|
272
|
+
The forms system supports various field types with validation:
|
|
273
|
+
|
|
274
|
+
- **text** - Basic text input with maxLength, pattern validation
|
|
275
|
+
- **email** - Email input with built-in email validation
|
|
276
|
+
- **number** - Numeric input with min/max validation
|
|
277
|
+
- **textarea** - Multi-line text with maxLength
|
|
278
|
+
- **select** - Dropdown with options array
|
|
279
|
+
- **password** - Password input (masked)
|
|
280
|
+
- **tel** - Phone number input
|
|
281
|
+
- **url** - URL input with validation
|
|
282
|
+
- **date** - Date picker input
|
|
283
|
+
|
|
284
|
+
### Field Schema Properties
|
|
285
|
+
Each field in the `fields_schema` JSON supports:
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"name": "fieldName", // Required: Field identifier
|
|
290
|
+
"type": "text", // Required: Field type
|
|
291
|
+
"label": "Field Label", // Display label
|
|
292
|
+
"required": true, // Validation: required field
|
|
293
|
+
"placeholder": "Enter text...", // Input placeholder
|
|
294
|
+
"helpText": "Additional help", // Help text below field
|
|
295
|
+
"maxLength": 100, // String length limit
|
|
296
|
+
"minLength": 3, // Minimum string length
|
|
297
|
+
"pattern": "^[A-Za-z]+$", // Regex validation pattern
|
|
298
|
+
"min": 0, // Number minimum value
|
|
299
|
+
"max": 100, // Number maximum value
|
|
300
|
+
"step": 1, // Number step increment
|
|
301
|
+
"defaultValue": "default", // Default field value
|
|
302
|
+
"options": [ // Select/radio options
|
|
303
|
+
{"value": "val1", "label": "Option 1"},
|
|
304
|
+
{"value": "val2", "label": "Option 2"}
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Security Features
|
|
310
|
+
The form system includes comprehensive security measures:
|
|
311
|
+
|
|
312
|
+
#### 1. Honeypot Protection
|
|
313
|
+
Automatic bot detection using invisible fields:
|
|
314
|
+
```html
|
|
315
|
+
<!-- Automatically added to all forms -->
|
|
316
|
+
<div class="hidden">
|
|
317
|
+
<input type="text" name="website_url" value="" />
|
|
318
|
+
</div>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
#### 2. Server-Side Validation
|
|
322
|
+
- **SchemaValidator integration** - Uses `@reldens/utils` SchemaValidator
|
|
323
|
+
- **Required field validation** - Ensures all required fields are provided
|
|
324
|
+
- **Type validation** - Email, number, string validation with patterns
|
|
325
|
+
- **Length limits** - Configurable per field via schema
|
|
326
|
+
- **Custom validation** - Extensible validation rules
|
|
327
|
+
|
|
328
|
+
#### 3. Data Sanitization
|
|
329
|
+
- **XSS protection** - Handled by `@reldens/server-utils` SecurityConfigurer
|
|
330
|
+
- **Input normalization** - Type-specific data processing
|
|
331
|
+
- **Length truncation** - Based on field schema maxLength
|
|
332
|
+
|
|
333
|
+
#### 4. Rate Limiting
|
|
334
|
+
- **AppServerFactory integration** - Uses existing rate limiting from server-utils
|
|
335
|
+
- **No duplicate implementation** - Leverages proven security measures
|
|
336
|
+
|
|
337
|
+
### Template Customization
|
|
338
|
+
Forms use a domain-aware template fallback system:
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
templates/
|
|
342
|
+
├── domains/
|
|
343
|
+
│ └── example.com/
|
|
344
|
+
│ └── cms_forms/
|
|
345
|
+
│ ├── form.html # Domain-specific form wrapper
|
|
346
|
+
│ ├── field_text.html # Domain-specific text field
|
|
347
|
+
│ └── field_email.html # Domain-specific email field
|
|
348
|
+
└── cms_forms/ # Default templates
|
|
349
|
+
├── form.html # Main form wrapper
|
|
350
|
+
├── field_text.html # Text input template
|
|
351
|
+
├── field_email.html # Email input template
|
|
352
|
+
├── field_textarea.html # Textarea template
|
|
353
|
+
├── field_select.html # Select dropdown template
|
|
354
|
+
└── field_number.html # Number input template
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Custom Field Templates
|
|
358
|
+
Create custom field templates for specific types:
|
|
359
|
+
|
|
360
|
+
**templates/cms_forms/field_text.html:**
|
|
361
|
+
```html
|
|
362
|
+
<div class="form-field {{errorClass}} {{requiredClass}}">
|
|
363
|
+
<label for="{{fieldName}}" class="form-label">
|
|
364
|
+
{{fieldLabel}}{{#isRequired}} <span class="required-indicator">*</span>{{/isRequired}}
|
|
365
|
+
</label>
|
|
366
|
+
<input type="{{fieldType}}"
|
|
367
|
+
name="submittedValues[{{fieldName}}]"
|
|
368
|
+
id="{{fieldName}}"
|
|
369
|
+
value="{{fieldValue}}"
|
|
370
|
+
class="form-control {{#hasError}}is-invalid{{/hasError}}"
|
|
371
|
+
{{#isRequired}}required{{/isRequired}}
|
|
372
|
+
{{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}
|
|
373
|
+
{{#maxLength}}maxlength="{{maxLength}}"{{/maxLength}}
|
|
374
|
+
{{#pattern}}pattern="{{pattern}}"{{/pattern}} />
|
|
375
|
+
{{#helpText}}<div class="form-text">{{helpText}}</div>{{/helpText}}
|
|
376
|
+
{{#hasError}}<div class="invalid-feedback">{{fieldError}}</div>{{/hasError}}
|
|
377
|
+
</div>
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**templates/cms_forms/form.html:**
|
|
381
|
+
```html
|
|
382
|
+
<form method="POST" action="{{submitUrl}}" class="{{cssClass}}">
|
|
383
|
+
<input type="hidden" name="formKey" value="{{formKey}}" />
|
|
384
|
+
<input type="hidden" name="successRedirect" value="{{successRedirect}}" />
|
|
385
|
+
<input type="hidden" name="errorRedirect" value="{{errorRedirect}}" />
|
|
386
|
+
<div class="hidden">
|
|
387
|
+
<input type="text" name="{{honeypotFieldName}}" value="" />
|
|
388
|
+
</div>
|
|
389
|
+
{{&formFields}}
|
|
390
|
+
<div class="form-submit">
|
|
391
|
+
<button type="submit" class="btn btn-primary">{{submitButtonText}}</button>
|
|
392
|
+
</div>
|
|
393
|
+
</form>
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Forms with System Variables
|
|
397
|
+
Forms can access system variables and enhanced data in templates:
|
|
398
|
+
|
|
399
|
+
```html
|
|
400
|
+
<!-- Form with the current user context -->
|
|
401
|
+
<cmsForm key="userProfile" fields="name,email,bio"/>
|
|
402
|
+
|
|
403
|
+
<!-- In the form template, access system variables: -->
|
|
404
|
+
<form method="POST" action="{{submitUrl}}" class="{{cssClass}}">
|
|
405
|
+
<h2>Update Profile for {{currentRequest.host}}</h2>
|
|
406
|
+
<p>Current time: {{systemInfo.timestamp}}</p>
|
|
407
|
+
{{&formFields}}
|
|
408
|
+
<button type="submit">Update Profile</button>
|
|
409
|
+
</form>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Event System Integration
|
|
413
|
+
The forms system provides comprehensive event hooks:
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
// Listen for form events
|
|
417
|
+
cms.events.on('reldens.formsTransformer.beforeRender', (eventData) => {
|
|
418
|
+
console.log('Rendering form:', eventData.formKey);
|
|
419
|
+
// Modify form attributes or fields before rendering
|
|
420
|
+
eventData.formAttributes.cssClass += ' custom-form';
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
cms.events.on('reldens.dynamicForm.beforeValidation', (eventData) => {
|
|
424
|
+
console.log('Validating form:', eventData.formKey);
|
|
425
|
+
// Add custom validation logic
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
cms.events.on('reldens.dynamicForm.afterSave', (eventData) => {
|
|
429
|
+
console.log('Form saved:', eventData.result.id);
|
|
430
|
+
// Send notifications, trigger workflows, etc.
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
cms.events.on('reldens.dynamicFormRequestHandler.beforeSave', (eventData) => {
|
|
434
|
+
// Modify prepared values before saving
|
|
435
|
+
eventData.preparedValues.submissionDate = new Date().toISOString();
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Available Form Events
|
|
440
|
+
- `reldens.formsTransformer.beforeRender` - Before form rendering
|
|
441
|
+
- `reldens.formsTransformer.afterRender` - After form rendering
|
|
442
|
+
- `reldens.dynamicForm.beforeValidation` - Before form validation
|
|
443
|
+
- `reldens.dynamicForm.afterValidation` - After form validation
|
|
444
|
+
- `reldens.dynamicForm.beforeSave` - Before saving to the database
|
|
445
|
+
- `reldens.dynamicForm.afterSave` - After successful save
|
|
446
|
+
- `reldens.dynamicFormRenderer.beforeFieldsRender` - Before rendering fields
|
|
447
|
+
- `reldens.dynamicFormRenderer.afterFieldsRender` - After rendering fields
|
|
448
|
+
- `reldens.dynamicFormRequestHandler.beforeValidation` - Before request validation
|
|
449
|
+
- `reldens.dynamicFormRequestHandler.beforeSave` - Before save process
|
|
450
|
+
- `reldens.dynamicFormRequestHandler.afterSave` - After successful save
|
|
451
|
+
|
|
452
|
+
### Database Tables
|
|
453
|
+
The forms system uses two main tables:
|
|
454
|
+
|
|
455
|
+
#### cms_forms Table
|
|
456
|
+
Store form configurations:
|
|
457
|
+
```sql
|
|
458
|
+
CREATE TABLE `cms_forms` (
|
|
459
|
+
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
460
|
+
`form_key` VARCHAR(255) NOT NULL UNIQUE,
|
|
461
|
+
`fields_schema` JSON NOT NULL,
|
|
462
|
+
`enabled` TINYINT UNSIGNED NOT NULL DEFAULT '0',
|
|
463
|
+
`created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
|
|
464
|
+
`updated_at` TIMESTAMP NOT NULL DEFAULT (NOW()) ON UPDATE CURRENT_TIMESTAMP,
|
|
465
|
+
PRIMARY KEY (`id`)
|
|
466
|
+
);
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### cms_forms_submitted Table
|
|
470
|
+
Store form submissions:
|
|
471
|
+
```sql
|
|
472
|
+
CREATE TABLE `cms_forms_submitted` (
|
|
473
|
+
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
474
|
+
`form_id` INT UNSIGNED NOT NULL,
|
|
475
|
+
`submitted_values` JSON NOT NULL,
|
|
476
|
+
`created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
|
|
477
|
+
PRIMARY KEY (`id`),
|
|
478
|
+
FOREIGN KEY (`form_id`) REFERENCES `cms_forms`(`id`)
|
|
479
|
+
);
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Form Processing Flow
|
|
483
|
+
1. **Template Processing** - `FormsTransformer` finds `<cmsForm>` tags
|
|
484
|
+
2. **Form Loading** - Loads form configuration from database
|
|
485
|
+
3. **Field Filtering** - Applies field filter if specified
|
|
486
|
+
4. **Template Rendering** - Renders form using domain-aware templates
|
|
487
|
+
5. **Form Submission** - POST request to `/dynamic-form` endpoint
|
|
488
|
+
6. **Validation** - Honeypot, required fields, and schema validation
|
|
489
|
+
7. **Data Processing** - Input sanitization and normalization
|
|
490
|
+
8. **Database Storage** - Save to `cms_forms_submitted` table
|
|
491
|
+
9. **Response** - Redirect with success/error parameters
|
|
492
|
+
|
|
493
|
+
### Advanced Form Usage
|
|
494
|
+
|
|
495
|
+
#### Multi-Step Forms
|
|
496
|
+
```html
|
|
497
|
+
<!-- Step 1: Basic info -->
|
|
498
|
+
<cmsForm key="applicationForm" fields="name,email,phone"/>
|
|
499
|
+
|
|
500
|
+
<!-- Step 2: Details (separate form) -->
|
|
501
|
+
<cmsForm key="applicationDetails" fields="experience,portfolio"/>
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
#### Conditional Field Display
|
|
505
|
+
Use JavaScript to show/hide fields based on selections:
|
|
506
|
+
```html
|
|
507
|
+
<cmsForm key="surveyForm" fields="age,experience,expertise"/>
|
|
508
|
+
|
|
509
|
+
<script>
|
|
510
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
511
|
+
const ageField = document.getElementById('age');
|
|
512
|
+
const experienceField = document.getElementById('experience');
|
|
513
|
+
|
|
514
|
+
ageField.addEventListener('change', function() {
|
|
515
|
+
if(parseInt(this.value) >= 18) {
|
|
516
|
+
experienceField.parentElement.style.display = 'block';
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
experienceField.parentElement.style.display = 'none';
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
</script>
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
#### AJAX Form Submissions
|
|
526
|
+
Enable JSON responses for AJAX handling:
|
|
527
|
+
```javascript
|
|
528
|
+
const cms = new Manager({
|
|
529
|
+
enableJsonResponse: true // Enable JSON responses for forms
|
|
530
|
+
});
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
```javascript
|
|
534
|
+
// Frontend AJAX handling
|
|
535
|
+
document.querySelector('.dynamic-form').addEventListener('submit', async function(e) {
|
|
536
|
+
e.preventDefault();
|
|
537
|
+
|
|
538
|
+
const response = await fetch('/dynamic-form', {method: 'POST', body: new FormData(this)});
|
|
539
|
+
|
|
540
|
+
const result = await response.json();
|
|
541
|
+
if(result.success) {
|
|
542
|
+
alert('Form submitted successfully!');
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
alert('Error: ' + result.error);
|
|
546
|
+
});
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Search Functionality
|
|
550
|
+
|
|
551
|
+
### Basic Search
|
|
552
|
+
```bash
|
|
553
|
+
# Simple search
|
|
554
|
+
/search?search=technology
|
|
555
|
+
|
|
556
|
+
# Entity-specific search with custom limit
|
|
557
|
+
/search?search=javascript&limit=20
|
|
558
|
+
|
|
559
|
+
# Custom template rendering
|
|
560
|
+
/search?search=news&renderPartial=newsListView&renderLayout=minimal
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Advanced Search with Template Data
|
|
564
|
+
```bash
|
|
565
|
+
# Pass custom template variables
|
|
566
|
+
/search?search=articles&templateData[columnsClass]=col-md-4&templateData[showExcerpt]=true
|
|
567
|
+
|
|
568
|
+
# Multiple template variables
|
|
569
|
+
/search?search=technology&templateData[columnsClass]=col-lg-6&templateData[cardClass]=shadow-sm&templateData[showAuthor]=false
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Search Template Variables
|
|
573
|
+
Templates receive dynamic data through URL parameters:
|
|
574
|
+
|
|
575
|
+
**URL:** `/search?search=tech&templateData[columnsClass]=col-md-6&templateData[showDate]=true`
|
|
576
|
+
|
|
577
|
+
**Template (entriesListView.html):**
|
|
578
|
+
```html
|
|
579
|
+
<div class="{{columnsClass}}">
|
|
580
|
+
<div class="card">
|
|
581
|
+
<h3>{{row.title}}</h3>
|
|
582
|
+
<p>{{row.content}}</p>
|
|
583
|
+
{{#showDate}}
|
|
584
|
+
<span class="date">{{row.created_at}}</span>
|
|
585
|
+
{{/showDate}}
|
|
586
|
+
</div>
|
|
587
|
+
</div>
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
**Default Values:**
|
|
591
|
+
- `columnsClass` defaults to `col-lg-6` if not provided or empty
|
|
592
|
+
- Custom variables can be added via `templateData[variableName]=value`
|
|
593
|
+
|
|
594
|
+
### Search Configuration
|
|
595
|
+
```javascript
|
|
596
|
+
// Custom search sets in Manager configuration
|
|
597
|
+
const searchSets = {
|
|
598
|
+
articlesSearch: {
|
|
599
|
+
entities: [{
|
|
600
|
+
name: 'articles',
|
|
601
|
+
fields: ['title', 'content', 'summary'],
|
|
602
|
+
relations: 'authors'
|
|
603
|
+
}],
|
|
604
|
+
pagination: {active: true, limit: 15, sortBy: 'created_at', sortDirection: 'desc'}
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
const cms = new Manager({
|
|
609
|
+
searchSets: searchSets
|
|
610
|
+
});
|
|
611
|
+
```
|
|
612
|
+
|
|
134
613
|
## Enhanced Templating System
|
|
135
614
|
|
|
136
615
|
### System Variables
|
|
@@ -171,10 +650,10 @@ Templates support dynamic functions for common operations:
|
|
|
171
650
|
<!-- URL generation with current domain -->
|
|
172
651
|
[url(/articles)] <!-- https://example.com/articles -->
|
|
173
652
|
[url(/contact#form)] <!-- https://example.com/contact#form -->
|
|
653
|
+
[url(/css/styles.css)] <!-- https://example.com/css/styles.css -->
|
|
174
654
|
|
|
175
655
|
<!-- Asset URLs with domain -->
|
|
176
|
-
[asset(/
|
|
177
|
-
[asset(/images/logo.png)] <!-- https://example.com/images/logo.png -->
|
|
656
|
+
[asset(/assets/images/logo.png)] <!-- https://example.com/images/logo.png -->
|
|
178
657
|
|
|
179
658
|
<!-- Date formatting -->
|
|
180
659
|
[date()] <!-- Current date with default format -->
|
|
@@ -303,10 +782,10 @@ Pagination state is managed via URL query parameters:
|
|
|
303
782
|
Create `templates/partials/pagedCollection.html`:
|
|
304
783
|
```html
|
|
305
784
|
<div class="row paginated-contents">
|
|
306
|
-
<div class="collection-content col-lg-12
|
|
785
|
+
<div class="collection-content col-lg-12">
|
|
307
786
|
{{&collectionContentForCurrentPage}}
|
|
308
787
|
</div>
|
|
309
|
-
<div class="pagination col-lg-12
|
|
788
|
+
<div class="pagination col-lg-12">
|
|
310
789
|
<ul class="pagination-list">
|
|
311
790
|
{{#prevPageUrl}}
|
|
312
791
|
<li><a href="{{prevPageUrl}}" class="page-link">{{&prevPageLabel}}</a></li>
|
|
@@ -497,11 +976,11 @@ The CMS uses a two-tier layout system:
|
|
|
497
976
|
<head>
|
|
498
977
|
<title>{{title}}</title>
|
|
499
978
|
<meta name="description" content="{{description}}"/>
|
|
500
|
-
<link href="[
|
|
979
|
+
<link href="[url(/css/styles.css)]" rel="stylesheet"/>
|
|
501
980
|
</head>
|
|
502
981
|
<body class="{{siteHandle}}">
|
|
503
982
|
{{&content}}
|
|
504
|
-
<script src="[
|
|
983
|
+
<script src="[url(/js/scripts.js)]"></script>
|
|
505
984
|
</body>
|
|
506
985
|
</html>
|
|
507
986
|
```
|
|
@@ -528,7 +1007,7 @@ The CMS uses a two-tier layout system:
|
|
|
528
1007
|
|
|
529
1008
|
Pages can use different layouts by setting the `layout` field in `cms_pages`:
|
|
530
1009
|
- `default` - Header, sidebar, main content, footer
|
|
531
|
-
- `full-width` - Full width without sidebars
|
|
1010
|
+
- `full-width` - Full width without sidebars
|
|
532
1011
|
- `minimal` - Basic layout with minimal styling
|
|
533
1012
|
|
|
534
1013
|
### Content Blocks
|
|
@@ -567,6 +1046,9 @@ templates/
|
|
|
567
1046
|
│ │ ├── partials/
|
|
568
1047
|
│ │ │ ├── header.html
|
|
569
1048
|
│ │ │ └── footer.html
|
|
1049
|
+
│ │ ├── cms_forms/ # Domain-specific form templates
|
|
1050
|
+
│ │ │ ├── form.html
|
|
1051
|
+
│ │ │ └── field_text.html
|
|
570
1052
|
│ │ ├── page.html # Domain-specific page wrapper
|
|
571
1053
|
│ │ └── index.html
|
|
572
1054
|
│ └── dev.example.com/
|
|
@@ -574,6 +1056,10 @@ templates/
|
|
|
574
1056
|
├── partials/
|
|
575
1057
|
│ ├── header.html (default)
|
|
576
1058
|
│ └── footer.html (default)
|
|
1059
|
+
├── cms_forms/ # Default form templates
|
|
1060
|
+
│ ├── form.html
|
|
1061
|
+
│ ├── field_text.html
|
|
1062
|
+
│ └── field_email.html
|
|
577
1063
|
├── translations/
|
|
578
1064
|
│ ├── en.json
|
|
579
1065
|
│ ├── es.json
|
|
@@ -584,6 +1070,32 @@ templates/
|
|
|
584
1070
|
|
|
585
1071
|
## Advanced Usage
|
|
586
1072
|
|
|
1073
|
+
### Template Reloading for Development
|
|
1074
|
+
```javascript
|
|
1075
|
+
// Different configurations for development vs production
|
|
1076
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
1077
|
+
|
|
1078
|
+
const cms = new Manager({
|
|
1079
|
+
// Enable aggressive template reloading in development
|
|
1080
|
+
reloadTime: isDevelopment ? -1 : 0,
|
|
1081
|
+
|
|
1082
|
+
// Other development-friendly settings
|
|
1083
|
+
cache: !isDevelopment,
|
|
1084
|
+
|
|
1085
|
+
entityAccess: {
|
|
1086
|
+
articles: { public: true, operations: ['read'] },
|
|
1087
|
+
cmsPages: { public: true, operations: ['read'] }
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
**Development Workflow with Template Reloading:**
|
|
1093
|
+
1. Set `reloadTime: -1` for instant template updates
|
|
1094
|
+
2. Edit admin templates in `admin/templates/` - changes appear immediately
|
|
1095
|
+
3. Edit frontend templates in `templates/` - changes appear on next page load
|
|
1096
|
+
4. No server restart needed for template changes
|
|
1097
|
+
5. Switch to `reloadTime: 0` in production for optimal performance
|
|
1098
|
+
|
|
587
1099
|
### Event System
|
|
588
1100
|
The CMS provides hooks for customization through event listeners:
|
|
589
1101
|
|
|
@@ -607,6 +1119,17 @@ cms.events.on('reldens.afterContentProcess', (eventData) => {
|
|
|
607
1119
|
// Modify processed content
|
|
608
1120
|
eventData.processedContent += '\n<!-- Processed at ' + new Date() + ' -->';
|
|
609
1121
|
});
|
|
1122
|
+
|
|
1123
|
+
// Listen for template reloading events
|
|
1124
|
+
cms.events.on('reldens.templateReloader.templatesChanged', (eventData) => {
|
|
1125
|
+
console.log('Templates changed:', eventData.changedFiles);
|
|
1126
|
+
});
|
|
1127
|
+
|
|
1128
|
+
// Listen for form events
|
|
1129
|
+
cms.events.on('reldens.dynamicForm.afterSave', (eventData) => {
|
|
1130
|
+
// Send email notifications, trigger workflows, etc.
|
|
1131
|
+
console.log('Form submission received:', eventData.result.id);
|
|
1132
|
+
});
|
|
610
1133
|
```
|
|
611
1134
|
|
|
612
1135
|
### Custom Authentication
|
|
@@ -663,6 +1186,10 @@ cms.events.on('adminEntityExtraData', ({entitySerializedData, entity}) => {
|
|
|
663
1186
|
- `entities_meta` - Generic metadata storage
|
|
664
1187
|
- `cms_pages_meta` - Page-specific metadata
|
|
665
1188
|
|
|
1189
|
+
### Forms Tables
|
|
1190
|
+
- `cms_forms` - Form configurations with JSON schema
|
|
1191
|
+
- `cms_forms_submitted` - Form submissions with JSON data
|
|
1192
|
+
|
|
666
1193
|
### Installation Options
|
|
667
1194
|
The installer provides checkboxes for:
|
|
668
1195
|
- CMS core tables
|
|
@@ -671,6 +1198,7 @@ The installer provides checkboxes for:
|
|
|
671
1198
|
- Default homepage
|
|
672
1199
|
- Default content blocks
|
|
673
1200
|
- Entity access control rules
|
|
1201
|
+
- Dynamic forms system
|
|
674
1202
|
|
|
675
1203
|
## API Reference
|
|
676
1204
|
|
|
@@ -679,11 +1207,58 @@ The installer provides checkboxes for:
|
|
|
679
1207
|
- `isInstalled()` - Check if CMS is installed
|
|
680
1208
|
- `initializeServices()` - Initialize all services
|
|
681
1209
|
|
|
682
|
-
### Frontend
|
|
1210
|
+
### Frontend Architecture Classes
|
|
1211
|
+
|
|
1212
|
+
#### Frontend Class (Orchestrator)
|
|
683
1213
|
- `initialize()` - Set up frontend routes and templates
|
|
684
1214
|
- `handleRequest(req, res)` - Main request handler
|
|
685
|
-
- `
|
|
686
|
-
- `
|
|
1215
|
+
- `renderRoute(route, domain, res, req)` - Route-based rendering
|
|
1216
|
+
- `setupStaticAssets()` - Configure static asset serving
|
|
1217
|
+
|
|
1218
|
+
#### TemplateResolver Class
|
|
1219
|
+
- `findTemplatePath(templateName, domain)` - Template discovery with domain fallback
|
|
1220
|
+
- `findLayoutPath(layoutName, domain)` - Layout path resolution
|
|
1221
|
+
- `findTemplateByPath(path, domain)` - Template lookup by URL path
|
|
1222
|
+
- `resolveDomainToFolder(domain)` - Domain to folder mapping
|
|
1223
|
+
- `resolveDomainToSiteKey(domain)` - Domain to site key mapping
|
|
1224
|
+
|
|
1225
|
+
#### TemplateCache Class
|
|
1226
|
+
- `loadPartials()` - Load and cache template partials
|
|
1227
|
+
- `setupDomainTemplates()` - Initialize domain-specific templates
|
|
1228
|
+
- `getPartialsForDomain(domain)` - Get domain-specific partials with fallback
|
|
1229
|
+
|
|
1230
|
+
#### TemplateReloader Class
|
|
1231
|
+
- `checkAndReloadAdminTemplates()` - Check and reload admin templates when changed
|
|
1232
|
+
- `checkAndReloadFrontendTemplates()` - Check and reload frontend templates when changed
|
|
1233
|
+
- `trackTemplateFiles(templatesPaths)` - Start tracking template files for changes
|
|
1234
|
+
- `shouldReloadAdminTemplates(mappedAdminTemplates)` - Check if admin templates need reloading
|
|
1235
|
+
- `shouldReloadFrontendTemplates(templatesPath, templateExtensions)` - Check if frontend templates need reloading
|
|
1236
|
+
- `handleAdminTemplateReload(adminManager)` - Complete admin template reload process
|
|
1237
|
+
- `handleFrontendTemplateReload(templateCache, templateResolver)` - Complete frontend template reload process
|
|
1238
|
+
|
|
1239
|
+
#### RequestProcessor Class
|
|
1240
|
+
- `findRouteByPath(path, domain)` - Database route lookup
|
|
1241
|
+
- `handleRouteRedirect(route, res)` - Handle route redirects
|
|
1242
|
+
- `getDomainFromRequest(req)` - Extract domain from request
|
|
1243
|
+
- `buildCacheKey(path, req)` - Generate cache keys
|
|
1244
|
+
|
|
1245
|
+
#### ContentRenderer Class
|
|
1246
|
+
- `renderWithTemplateContent(content, data, domain, req, route)` - Main content rendering
|
|
1247
|
+
- `generateRouteContent(route, domain, req)` - Route-based content generation
|
|
1248
|
+
- `generateTemplateContent(templatePath, domain, req, data)` - Template-based content generation
|
|
1249
|
+
- `fetchMetaFields(data)` - Process meta fields for templates
|
|
1250
|
+
|
|
1251
|
+
#### EntityAccessManager Class
|
|
1252
|
+
- `loadEntityAccessRules()` - Load entity access configuration
|
|
1253
|
+
- `isEntityAccessible(entityName)` - Check entity accessibility
|
|
1254
|
+
- `findEntityByPath(path)` - Entity lookup by URL path
|
|
1255
|
+
|
|
1256
|
+
#### ResponseManager Class
|
|
1257
|
+
- `renderWithCacheHandler(contentGenerator, errorHandler, responseHandler, domain, res, path, req)` - Generic cached response handler
|
|
1258
|
+
- `renderNotFound(domain, res, req)` - 404 error handling
|
|
1259
|
+
|
|
1260
|
+
#### SearchRequestHandler Class
|
|
1261
|
+
- `handleSearchRequest(req, res)` - Process search requests with template data support
|
|
687
1262
|
|
|
688
1263
|
### TemplateEngine Class
|
|
689
1264
|
- `render(template, data, partials, domain, req, route, currentEntityData)` - Main template rendering with enhanced context
|
|
@@ -696,6 +1271,41 @@ The installer provides checkboxes for:
|
|
|
696
1271
|
- `buildCurrentRouteData(route)` - Build route context
|
|
697
1272
|
- `buildCurrentDomainData(domain)` - Build domain context
|
|
698
1273
|
|
|
1274
|
+
### Search Classes
|
|
1275
|
+
- `Search.parseSearchParameters(query)` - Parse search query parameters including templateData
|
|
1276
|
+
- `Search.executeSearch(config)` - Execute search with configuration
|
|
1277
|
+
- `SearchRenderer.renderSearchResults(searchResults, config, domain, req)` - Render search results with template data
|
|
1278
|
+
|
|
1279
|
+
### Forms System Classes
|
|
1280
|
+
|
|
1281
|
+
#### DynamicForm Class
|
|
1282
|
+
- `validateFormSubmission(formKey, submittedValues, req)` - Validate form submission
|
|
1283
|
+
- `getFormConfig(formKey)` - Load form configuration from database
|
|
1284
|
+
- `validateHoneypot(submittedValues)` - Check honeypot field for bots
|
|
1285
|
+
- `validateFields(fieldsSchema, submittedValues)` - Schema-based field validation
|
|
1286
|
+
- `prepareSubmittedValues(submittedValues, fieldsSchema)` - Process and normalize values
|
|
1287
|
+
- `saveFormSubmission(formConfig, preparedValues)` - Save to database
|
|
1288
|
+
|
|
1289
|
+
#### DynamicFormRenderer Class
|
|
1290
|
+
- `renderForm(formConfig, fieldsToRender, domain, req, attributes)` - Render complete form
|
|
1291
|
+
- `renderFormFields(fieldsToRender, domain, req)` - Render field set
|
|
1292
|
+
- `renderFormField(field, domain, submittedValues, errors)` - Render individual field
|
|
1293
|
+
- `loadFormTemplate(templateName, domain)` - Load form template with domain fallback
|
|
1294
|
+
- `findFormTemplate(templateName, domain)` - Template discovery for forms
|
|
1295
|
+
|
|
1296
|
+
#### DynamicFormRequestHandler Class
|
|
1297
|
+
- `handleFormSubmission(req, res)` - Process POST form submissions
|
|
1298
|
+
- `handleBadRequest(res, message)` - Handle validation errors
|
|
1299
|
+
- `handleSuccessResponse(req, res, formKey, result)` - Handle successful submissions
|
|
1300
|
+
- `buildErrorRedirectPath(req, error, formKey)` - Build error redirect URLs
|
|
1301
|
+
- `buildSuccessRedirectPath(successRedirect, formKey)` - Build success redirect URLs
|
|
1302
|
+
|
|
1303
|
+
#### FormsTransformer Class
|
|
1304
|
+
- `transform(template, domain, req, systemVariables, enhancedData)` - Process cmsForm tags
|
|
1305
|
+
- `findAllFormTags(template)` - Find cmsForm tags in template
|
|
1306
|
+
- `parseFormAttributes(fullTag)` - Parse tag attributes
|
|
1307
|
+
- `parseFieldsFilter(attributes, formConfig)` - Filter fields based on attributes
|
|
1308
|
+
|
|
699
1309
|
### AdminManager Class
|
|
700
1310
|
- `setupAdmin()` - Initialize admin panel
|
|
701
1311
|
- `generateListRouteContent()` - Entity list pages
|
|
@@ -713,10 +1323,36 @@ The installer provides checkboxes for:
|
|
|
713
1323
|
project/
|
|
714
1324
|
├── admin/
|
|
715
1325
|
│ └── templates/ # Admin panel templates
|
|
1326
|
+
├── lib/
|
|
1327
|
+
│ ├── frontend/ # Frontend specialized classes
|
|
1328
|
+
│ │ ├── template-resolver.js
|
|
1329
|
+
│ │ ├── template-cache.js
|
|
1330
|
+
│ │ ├── request-processor.js
|
|
1331
|
+
│ │ ├── entity-access-manager.js
|
|
1332
|
+
│ │ ├── content-renderer.js
|
|
1333
|
+
│ │ └── response-manager.js
|
|
1334
|
+
│ ├── template-engine/ # Template processing classes
|
|
1335
|
+
│ │ └── forms-transformer.js
|
|
1336
|
+
│ ├── frontend.js # Main Frontend orchestrator
|
|
1337
|
+
│ ├── template-reloader.js # Template reloading functionality
|
|
1338
|
+
│ ├── search-request-handler.js
|
|
1339
|
+
│ ├── search.js # Search functionality
|
|
1340
|
+
│ ├── search-renderer.js # Search result rendering
|
|
1341
|
+
│ ├── dynamic-form.js # Forms validation and processing
|
|
1342
|
+
│ ├── dynamic-form-renderer.js # Forms template rendering
|
|
1343
|
+
│ ├── dynamic-form-request-handler.js # Forms request handling
|
|
1344
|
+
│ └── template-engine.js # Core template processing
|
|
716
1345
|
├── templates/
|
|
717
1346
|
│ ├── layouts/ # Body content layouts
|
|
718
1347
|
│ ├── domains/ # Domain-specific templates
|
|
1348
|
+
│ │ └── example.com/
|
|
1349
|
+
│ │ └── cms_forms/ # Domain-specific form templates
|
|
719
1350
|
│ ├── partials/ # Shared template partials
|
|
1351
|
+
│ ├── cms_forms/ # Default form templates
|
|
1352
|
+
│ │ ├── form.html # Main form wrapper
|
|
1353
|
+
│ │ ├── field_text.html # Text field template
|
|
1354
|
+
│ │ ├── field_email.html # Email field template
|
|
1355
|
+
│ │ └── field_select.html # Select field template
|
|
720
1356
|
│ ├── page.html # Base HTML wrapper
|
|
721
1357
|
│ └── 404.html # Error page
|
|
722
1358
|
├── translations/
|