@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.
Files changed (67) hide show
  1. package/README.md +648 -12
  2. package/admin/reldens-admin-client.css +77 -141
  3. package/admin/reldens-admin-client.js +108 -133
  4. package/admin/templates/clear-all-cache-button.html +7 -7
  5. package/admin/templates/edit.html +7 -0
  6. package/admin/templates/fields/view/audio.html +7 -0
  7. package/admin/templates/fields/view/audios.html +8 -0
  8. package/admin/templates/layout.html +15 -9
  9. package/admin/templates/list-content.html +4 -2
  10. package/admin/templates/list.html +24 -8
  11. package/admin/templates/view.html +21 -0
  12. package/install/index.html +4 -0
  13. package/lib/admin-manager/admin-filters-manager.js +177 -0
  14. package/lib/admin-manager/contents-builder.js +1 -0
  15. package/lib/admin-manager/default-translations.js +38 -0
  16. package/lib/admin-manager/router-contents.js +64 -52
  17. package/lib/admin-manager/router.js +19 -0
  18. package/lib/dynamic-form-renderer.js +228 -0
  19. package/lib/dynamic-form-request-handler.js +135 -0
  20. package/lib/dynamic-form.js +310 -0
  21. package/lib/frontend/content-renderer.js +178 -0
  22. package/lib/frontend/entity-access-manager.js +63 -0
  23. package/lib/frontend/request-processor.js +128 -0
  24. package/lib/frontend/response-manager.js +54 -0
  25. package/lib/frontend/template-cache.js +102 -0
  26. package/lib/frontend/template-resolver.js +111 -0
  27. package/lib/frontend.js +122 -629
  28. package/lib/installer.js +2 -1
  29. package/lib/manager.js +25 -12
  30. package/lib/search-renderer.js +15 -7
  31. package/lib/search-request-handler.js +67 -0
  32. package/lib/search.js +13 -1
  33. package/lib/template-engine/collections-single-transformer.js +11 -5
  34. package/lib/template-engine/collections-transformer.js +47 -34
  35. package/lib/template-engine/entities-transformer.js +3 -2
  36. package/lib/template-engine/forms-transformer.js +187 -0
  37. package/lib/template-engine/partials-transformer.js +5 -6
  38. package/lib/template-engine/system-variables-provider.js +4 -1
  39. package/lib/template-engine.js +28 -5
  40. package/lib/template-reloader.js +307 -0
  41. package/lib/templates-list.js +2 -0
  42. package/migrations/default-forms.sql +22 -0
  43. package/package.json +5 -5
  44. package/templates/{browserconfig.xml → assets/favicons/default/browserconfig.xml} +1 -1
  45. package/templates/assets/favicons/default/favicon.ico +0 -0
  46. package/templates/{site.webmanifest → assets/favicons/default/site.webmanifest} +3 -3
  47. package/templates/cms_forms/field_email.html +14 -0
  48. package/templates/cms_forms/field_number.html +17 -0
  49. package/templates/cms_forms/field_select.html +15 -0
  50. package/templates/cms_forms/field_text.html +16 -0
  51. package/templates/cms_forms/field_textarea.html +13 -0
  52. package/templates/cms_forms/form.html +22 -0
  53. package/templates/css/styles.css +4 -0
  54. package/templates/js/functions.js +144 -0
  55. package/templates/js/scripts.js +5 -0
  56. package/templates/page.html +11 -5
  57. package/templates/partials/pagedCollection.html +1 -1
  58. package/lib/admin-translations.js +0 -56
  59. package/templates/favicon.ico +0 -0
  60. /package/templates/assets/favicons/{android-icon-144x144.png → default/android-icon-144x144.png} +0 -0
  61. /package/templates/assets/favicons/{android-icon-192x192.png → default/android-icon-192x192.png} +0 -0
  62. /package/templates/assets/favicons/{android-icon-512x512.png → default/android-icon-512x512.png} +0 -0
  63. /package/templates/assets/favicons/{apple-touch-icon.png → default/apple-touch-icon.png} +0 -0
  64. /package/templates/assets/favicons/{favicon-16x16.png → default/favicon-16x16.png} +0 -0
  65. /package/templates/assets/favicons/{favicon-32x32.png → default/favicon-32x32.png} +0 -0
  66. /package/templates/assets/favicons/{mstile-150x150.png → default/mstile-150x150.png} +0 -0
  67. /package/templates/assets/favicons/{safari-pinned-tab.svg → default/safari-pinned-tab.svg} +0 -0
@@ -7,18 +7,18 @@
7
7
  "background_color": "#000000",
8
8
  "icons": [
9
9
  {
10
- "src": "assets/favicons/android-icon-144x144.png",
10
+ "src": "/assets/favicons/default/android-icon-144x144.png",
11
11
  "sizes": "144x144",
12
12
  "type": "image/png",
13
13
  "purpose": "any"
14
14
  },
15
15
  {
16
- "src": "assets/favicons/android-icon-192x192.png",
16
+ "src": "/assets/favicons/default/android-icon-192x192.png",
17
17
  "sizes": "192x192",
18
18
  "type": "image/png"
19
19
  },
20
20
  {
21
- "src": "assets/favicons/android-icon-512x512.png",
21
+ "src": "/assets/favicons/default/android-icon-512x512.png",
22
22
  "sizes": "512x512",
23
23
  "type": "image/png",
24
24
  "purpose": "maskable"
@@ -0,0 +1,14 @@
1
+ <div class="form-field {{errorClass}} {{requiredClass}}">
2
+ <label for="{{fieldName}}" class="form-label">
3
+ {{fieldLabel}}{{#isRequired}} <span class="required-indicator">*</span>{{/isRequired}}
4
+ </label>
5
+ <input type="email"
6
+ name="submittedValues[{{fieldName}}]"
7
+ id="{{fieldName}}"
8
+ value="{{fieldValue}}"
9
+ class="form-control {{#hasError}}is-invalid{{/hasError}}"
10
+ {{#isRequired}}required{{/isRequired}}
11
+ {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}} />
12
+ {{#helpText}}<div class="form-text">{{helpText}}</div>{{/helpText}}
13
+ {{#hasError}}<div class="invalid-feedback">{{fieldError}}</div>{{/hasError}}
14
+ </div>
@@ -0,0 +1,17 @@
1
+ <div class="form-field {{errorClass}} {{requiredClass}}">
2
+ <label for="{{fieldName}}" class="form-label">
3
+ {{fieldLabel}}{{#isRequired}} <span class="required-indicator">*</span>{{/isRequired}}
4
+ </label>
5
+ <input type="number"
6
+ name="submittedValues[{{fieldName}}]"
7
+ id="{{fieldName}}"
8
+ value="{{fieldValue}}"
9
+ class="form-control {{#hasError}}is-invalid{{/hasError}}"
10
+ {{#isRequired}}required{{/isRequired}}
11
+ {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}
12
+ {{#min}}min="{{min}}"{{/min}}
13
+ {{#max}}max="{{max}}"{{/max}}
14
+ {{#step}}step="{{step}}"{{/step}}/>
15
+ {{#helpText}}<div class="form-text">{{helpText}}</div>{{/helpText}}
16
+ {{#hasError}}<div class="invalid-feedback">{{fieldError}}</div>{{/hasError}}
17
+ </div>
@@ -0,0 +1,15 @@
1
+ <div class="form-field {{errorClass}} {{requiredClass}}">
2
+ <label for="{{fieldName}}" class="form-label">
3
+ {{fieldLabel}}{{#isRequired}} <span class="required-indicator">*</span>{{/isRequired}}
4
+ </label>
5
+ <select name="submittedValues[{{fieldName}}]"
6
+ id="{{fieldName}}"
7
+ class="form-select {{#hasError}}is-invalid{{/hasError}}"
8
+ {{#isRequired}}required{{/isRequired}}>
9
+ {{#options}}
10
+ <option value="{{value}}" {{#selected}}selected{{/selected}}>{{label}}</option>
11
+ {{/options}}
12
+ </select>
13
+ {{#helpText}}<div class="form-text">{{helpText}}</div>{{/helpText}}
14
+ {{#hasError}}<div class="invalid-feedback">{{fieldError}}</div>{{/hasError}}
15
+ </div>
@@ -0,0 +1,16 @@
1
+ <div class="form-field {{errorClass}} {{requiredClass}}">
2
+ <label for="{{fieldName}}" class="form-label">
3
+ {{fieldLabel}}{{#isRequired}} <span class="required-indicator">*</span>{{/isRequired}}
4
+ </label>
5
+ <input type="{{fieldType}}"
6
+ name="submittedValues[{{fieldName}}]"
7
+ id="{{fieldName}}"
8
+ value="{{fieldValue}}"
9
+ class="form-control {{#hasError}}is-invalid{{/hasError}}"
10
+ {{#isRequired}}required{{/isRequired}}
11
+ {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}
12
+ {{#maxLength}}maxlength="{{maxLength}}"{{/maxLength}}
13
+ {{#pattern}}pattern="{{pattern}}"{{/pattern}} />
14
+ {{#helpText}}<div class="form-text">{{helpText}}</div>{{/helpText}}
15
+ {{#hasError}}<div class="invalid-feedback">{{fieldError}}</div>{{/hasError}}
16
+ </div>
@@ -0,0 +1,13 @@
1
+ <div class="form-field {{errorClass}} {{requiredClass}}">
2
+ <label for="{{fieldName}}" class="form-label">
3
+ {{fieldLabel}}{{#isRequired}} <span class="required-indicator">*</span>{{/isRequired}}
4
+ </label>
5
+ <textarea name="submittedValues[{{fieldName}}]"
6
+ id="{{fieldName}}"
7
+ class="form-control {{#hasError}}is-invalid{{/hasError}}"
8
+ {{#isRequired}}required{{/isRequired}}
9
+ {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}
10
+ {{#maxLength}}maxlength="{{maxLength}}"{{/maxLength}}>{{fieldValue}}</textarea>
11
+ {{#helpText}}<div class="form-text">{{helpText}}</div>{{/helpText}}
12
+ {{#hasError}}<div class="invalid-feedback">{{fieldError}}</div>{{/hasError}}
13
+ </div>
@@ -0,0 +1,22 @@
1
+ {{#showSuccessMessage}}
2
+ <div class="form-message form-success">
3
+ {{successMessage}}
4
+ </div>
5
+ {{/showSuccessMessage}}
6
+ {{#showErrorMessage}}
7
+ <div class="form-message form-error">
8
+ {{errorMessage}}
9
+ </div>
10
+ {{/showErrorMessage}}
11
+ <form method="POST" action="{{submitUrl}}" class="{{cssClass}}">
12
+ <input type="hidden" name="formKey" value="{{formKey}}" />
13
+ <input type="hidden" name="successRedirect" value="{{successRedirect}}"/>
14
+ <input type="hidden" name="errorRedirect" value="{{errorRedirect}}"/>
15
+ <div class="hidden">
16
+ <input type="text" name="{{honeypotFieldName}}" value=""/>
17
+ </div>
18
+ {{&formFields}}
19
+ <div class="form-submit">
20
+ <button type="submit" class="btn btn-primary">{{submitButtonText}}</button>
21
+ </div>
22
+ </form>
@@ -103,3 +103,7 @@ img {
103
103
  max-width: 100%;
104
104
  height: auto;
105
105
  }
106
+
107
+ .hidden {
108
+ display: none;
109
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ *
3
+ * Reldens - Functions
4
+ *
5
+ */
6
+
7
+ function getCookie(name)
8
+ {
9
+ let value = `; ${document.cookie}`;
10
+ let parts = value.split(`; ${name}=`);
11
+ if(2 === parts.length){
12
+ return parts.pop().split(';').shift()
13
+ }
14
+ }
15
+
16
+ function deleteCookie(name)
17
+ {
18
+ document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
19
+ }
20
+
21
+ function escapeHTML(str)
22
+ {
23
+ return str.replace(/&/g, "&amp;")
24
+ .replace(/</g, "&lt;")
25
+ .replace(/>/g, "&gt;")
26
+ .replace(/"/g, "&quot;")
27
+ .replace(/'/g, "&#039;");
28
+ }
29
+
30
+ function cloneElement(element)
31
+ {
32
+ if(element instanceof HTMLCanvasElement){
33
+ let clonedCanvas = document.createElement('canvas');
34
+ clonedCanvas.width = element.width;
35
+ clonedCanvas.height = element.height;
36
+ let ctx = clonedCanvas.getContext('2d');
37
+ ctx.drawImage(element, 0, 0);
38
+ return clonedCanvas
39
+ }
40
+ return element.cloneNode(true);
41
+ }
42
+
43
+ function showConfirmDialog(callback)
44
+ {
45
+ let dialog = document.querySelector('.confirm-dialog');
46
+ if(!dialog){
47
+ return callback(false);
48
+ }
49
+ dialog.showModal();
50
+ let confirmButton = dialog.querySelector('.dialog-confirm');
51
+ let cancelButton = dialog.querySelector('.dialog-cancel');
52
+ let onConfirm = () => {
53
+ dialog.close();
54
+ callback(true);
55
+ confirmButton.removeEventListener('click', onConfirm);
56
+ cancelButton.removeEventListener('click', onCancel);
57
+ };
58
+ let onCancel = () => {
59
+ dialog.close();
60
+ callback(false);
61
+ confirmButton.removeEventListener('click', onConfirm);
62
+ cancelButton.removeEventListener('click', onCancel);
63
+ };
64
+ confirmButton.addEventListener('click', onConfirm);
65
+ cancelButton.addEventListener('click', onCancel);
66
+ }
67
+
68
+ function activateExpandCollapse()
69
+ {
70
+ let expandCollapseButtons = document.querySelectorAll('[data-expand-collapse]');
71
+ if(expandCollapseButtons){
72
+ return;
73
+ }
74
+ for(let expandCollapseButton of expandCollapseButtons){
75
+ expandCollapseButton.addEventListener('click', (event) => {
76
+ let expandCollapseElement = document.querySelector(event.currentTarget.dataset.expandCollapse);
77
+ if(expandCollapseElement){
78
+ expandCollapseElement.classList.toggle('hidden');
79
+ }
80
+ });
81
+ }
82
+ }
83
+
84
+ function createModalContent(modalElement)
85
+ {
86
+ if(modalElement.hasAttribute('data-modal-zoom-image')){
87
+ let modalContent = document.createElement('img');
88
+ modalContent.src = modalElement.getAttribute('data-modal-zoom-image');
89
+ modalContent.alt = modalElement.alt || 'Modal Image';
90
+ modalContent.classList.add('modal-zoom-image');
91
+ return modalContent;
92
+ }
93
+ return cloneElement(modalElement);
94
+ }
95
+
96
+ function activateModalElements()
97
+ {
98
+ let modalElements = document.querySelectorAll('[data-toggle="modal"]');
99
+ if(!modalElements){
100
+ return;
101
+ }
102
+ for(let modalElement of modalElements){
103
+ if(!modalElement.id){
104
+ modalElement.id = 'modal-'+Math.random().toString(36).substr(2, 9);
105
+ }
106
+ modalElement.addEventListener('click', () => {
107
+ let overlayId = 'overlay-'+modalElement.id;
108
+ let existingOverlay = document.querySelector('#'+overlayId);
109
+ if(existingOverlay){
110
+ existingOverlay.style.display = 'block';
111
+ document.body.style.overflow = 'hidden';
112
+ return;
113
+ }
114
+ let overlay = document.createElement('div');
115
+ overlay.id = overlayId;
116
+ overlay.classList.add('modal-overlay');
117
+ let modal = document.createElement('div');
118
+ modal.classList.add('modal');
119
+ modal.classList.add('clickable');
120
+ let modalContent = createModalContent(modalElement);
121
+ modalContent.classList.add('clickable');
122
+ modal.appendChild(modalContent);
123
+ overlay.appendChild(modal);
124
+ document.body.appendChild(overlay);
125
+ document.body.style.overflow = 'hidden';
126
+ modalContent.addEventListener('click', () => {
127
+ document.body.style.overflow = '';
128
+ document.body.removeChild(overlay);
129
+ });
130
+ modal.addEventListener('click', (e) => {
131
+ if(modal === e.target){
132
+ document.body.style.overflow = '';
133
+ document.body.removeChild(overlay);
134
+ }
135
+ });
136
+ overlay.addEventListener('click', (e) => {
137
+ if(overlay === e.target){
138
+ document.body.style.overflow = '';
139
+ document.body.removeChild(overlay);
140
+ }
141
+ });
142
+ });
143
+ }
144
+ }
@@ -16,4 +16,9 @@ document.addEventListener('DOMContentLoaded', function() {
16
16
  if(copyRightYear){
17
17
  copyRightYear.innerHTML = String((new Date()).getFullYear());
18
18
  }
19
+
20
+ activateExpandCollapse();
21
+
22
+ activateModalElements();
23
+
19
24
  });
@@ -29,13 +29,19 @@
29
29
  {{#canonical_url}}
30
30
  <link rel="canonical" href="{{canonical_url}}"/>
31
31
  {{/canonical_url}}
32
+ <!-- favicons -->
33
+ <meta name="msapplication-config" content="[asset(/favicons/default/browserconfig.xml)]"/>
34
+ <link rel="icon" href="[asset(/favicons/default/favicon.ico)]" type="image/x-icon"/>
35
+ <link rel="shortcut icon" href="[asset(/favicons/default/favicon.ico)]" type="image/x-icon">
36
+ <link rel="manifest" href="[asset(/favicons/default/site.webmanifest)]"/>
32
37
  <!-- CSS and JS -->
33
- <link href="/css/styles.css" rel="stylesheet"/>
34
- <script src="/js/cookie-consent.js"></script>
38
+ <link rel="stylesheet" href="[url(/css/styles.css)]"/>
39
+ <script defer src="[url(/js/cookie-consent.js)]"></script>
35
40
  </head>
36
41
  <body class="{{siteHandle}}">
37
- {{&content}}
38
- {{>cookie-consent}}
39
- <script type="text/javascript" defer src="/js/scripts.js"></script>
42
+ {{&content}}
43
+ {{>cookie-consent}}
44
+ <script defer type="text/javascript" src="[url(/js/functions.js)]"></script>
45
+ <script defer type="text/javascript" src="[url(/js/scripts.js)]"></script>
40
46
  </body>
41
47
  </html>
@@ -3,7 +3,7 @@
3
3
  {{&collectionContentForCurrentPage}}
4
4
  </div>
5
5
  <div class="row pager-container">
6
- <div class="pagination col-lg-12 mt-2 mb-2">
6
+ <div class="pagination col-lg-12">
7
7
  <ul>
8
8
  {{#prevPageUrl}}
9
9
  <li class="previous previous-page"><a href="{{ prevPageUrl }}">{{&prevPageLabel }}</a></li>
@@ -1,56 +0,0 @@
1
- /**
2
- *
3
- * Reldens - AdminTranslations
4
- *
5
- */
6
-
7
- class AdminTranslations
8
- {
9
-
10
- static appendTranslations(translations)
11
- {
12
- // @TODO - BETA - Fix translations, use snippets, include new snippets under the basic config script.
13
- let adminTranslations = {
14
- messages: {
15
- loginWelcome: 'CMS - Login',
16
- reldensTitle: 'Reldens - CMS',
17
- reldensSlogan: 'You can do it',
18
- reldensDiscordTitle: 'Join our Discord server!',
19
- reldensDiscordText: 'Talk with the creators and other Reldens users',
20
- reldensGithubTitle: 'Find us on GitHub!',
21
- reldensGithubText: 'Need a new feature?'
22
- +' Would you like to contribute with code?'
23
- +' Find the source code or create an issue in GitHub',
24
- reldensLoading: 'Loading...',
25
- confirmClearCacheMessage: 'Are you sure you want to clear all cache? This action cannot be undone.',
26
- clearCacheWarning: 'This will clear all cached routes and may impact site performance temporarily.'
27
- },
28
- labels: {
29
- navigation: 'Reldens - CMS',
30
- adminVersion: 'Admin: {{version}}',
31
- loginWelcome: 'Reldens',
32
- pages: 'Server Management',
33
- management: 'Management',
34
- shuttingDown: 'Server is shutting down in:',
35
- submitShutdownLabel: 'Shutdown Server',
36
- submitCancelLabel: 'Cancel Server Shutdown',
37
- cleanCache: 'Clean Cache',
38
- clearAllCache: 'Clear All Cache',
39
- confirmClearCache: 'Confirm Clear Cache',
40
- warning: 'Warning:',
41
- cancel: 'Cancel',
42
- confirm: 'Continue',
43
- }
44
- };
45
- for(let i of Object.keys(translations)){
46
- if(!adminTranslations[i]){
47
- adminTranslations[i] = {};
48
- }
49
- Object.assign(adminTranslations[i], translations[i]);
50
- }
51
- return adminTranslations;
52
- }
53
-
54
- }
55
-
56
- module.exports.AdminTranslations = AdminTranslations;
Binary file