@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
@@ -387,7 +387,7 @@
387
387
  .button {
388
388
  margin-bottom: 1rem;
389
389
 
390
- &.list-delete-selection {
390
+ &.list-select {
391
391
  margin-bottom: 0;
392
392
  }
393
393
  }
@@ -532,8 +532,7 @@
532
532
  flex-direction: row;
533
533
  vertical-align: middle;
534
534
  align-items: center;
535
- width: 100%;
536
- margin: 0 0 1rem 0;
535
+ margin: 0 1rem 1rem 0;
537
536
  font-size: 14px;
538
537
  color: var(--darkGrey);
539
538
 
@@ -587,130 +586,58 @@
587
586
  }
588
587
  }
589
588
 
590
- .maps-wizard {
591
- .main-action-container.maps-selection {
592
- width: 100%;
593
-
594
- .wizard-options-container {
595
- display: flex;
596
- justify-content: space-between;
597
- flex-wrap: wrap;
598
- width: 100%;
599
-
600
- /* 3 or more items => 4 columns */
601
- .wizard-map-option-container {
602
- flex: 0 0 22%;
603
- padding: 1rem 1% 0;
604
- margin: 1.5rem 0 0;
605
- border: 1px solid #ccc;
606
- }
607
-
608
- /* 1 child => 1 columns */
609
- .wizard-map-option-container:only-child {
610
- flex: 0 0 100%;
611
- padding: 1rem 0 0;
612
- border: none;
613
- }
614
-
615
- /* 2 children => 2 columns */
616
- .wizard-map-option-container:first-child:nth-last-child(2),
617
- .wizard-map-option-container:last-child:nth-child(2) {
618
- flex: 0 0 47%;
619
- }
620
-
621
- & input.map-wizard-option {
622
- top: 2px;
623
- margin-right: 0;
624
- }
625
- }
626
- }
627
-
628
- .checkbox-container {
629
- display: flex;
630
- flex-direction: row;
631
- font-weight: var(--bold);
632
- }
633
-
634
- .wizard-options-container {
635
- padding: 0;
636
- margin-bottom: 1rem;
637
-
638
- & input.map-wizard-option {
639
- position: relative;
640
- top: -2px;
641
- margin-right: 6px;
642
- }
643
-
644
- .wizard-map-option-container {
645
- display: flex;
646
- flex-direction: column;
647
- list-style: none;
648
- padding-top: 1rem;
649
- margin-top: 1.5rem;
650
- border-top: 1px solid #ccc;
651
-
652
- & label {
653
- cursor: pointer;
654
- }
655
-
656
- & canvas {
657
- width: 100%;
658
- margin-top: 1rem;
659
- }
660
- }
661
-
662
- .wizard-option-container {
663
- list-style: none;
664
- margin-bottom: 1rem;
665
-
666
- .main-option {
667
- display: inline-block;
668
- cursor: pointer;
669
- }
670
-
671
- .maps-wizard-option-content {
672
- display: none;
673
- padding-left: 1.6rem;
674
- }
675
-
676
- &.active {
677
- .maps-wizard-option-content {
678
- display: block;
679
- }
680
- }
681
- }
682
- }
683
-
684
- .maps-wizard-form {
685
- align-items: flex-start;
686
- flex-direction: column;
687
- justify-content: flex-start;
589
+ .filters-header {
590
+ display: flex;
591
+ justify-content: space-between;
592
+ align-items: center;
593
+ width: 100%;
594
+ margin-bottom: 1rem;
595
+ flex-wrap: wrap;
596
+ gap: 1rem;
597
+ }
688
598
 
689
- .submit-container {
690
- display: flex;
691
- }
692
- }
599
+ .filters-toggle {
600
+ cursor: pointer;
601
+ margin: 0;
602
+ padding: 0.5rem 0;
603
+ flex-shrink: 0;
604
+ }
693
605
 
694
- .sub-map-option-description {
695
- display: flex;
696
- align-items: center;
606
+ .filters-toggle img {
607
+ width: 34px;
608
+ height: auto;
609
+ margin-right: 0.5rem;
610
+ opacity: 0.7;
611
+ }
697
612
 
698
- & img.icon-sm {
699
- margin-right: 1rem;
700
- }
701
- }
613
+ .search-controls {
614
+ display: flex;
615
+ align-items: center;
616
+ gap: 0.5rem;
617
+ flex-wrap: wrap;
618
+ flex: 1;
619
+ justify-content: flex-end;
620
+ }
702
621
 
703
- .sub-maps-container {
704
- display: block;
622
+ .search-input-group input[type="text"] {
623
+ width: calc(100% - 1rem);
624
+ padding: 0.5rem;
625
+ border: 1px solid #ccc;
626
+ border-radius: 4px;
627
+ font-size: 1rem;
628
+ }
705
629
 
706
- &.hidden {
707
- display: none;
708
- }
630
+ .search-input-group input[type="text"]:focus {
631
+ outline: none;
632
+ border-color: var(--lightBlue);
633
+ box-shadow: 0 0 0 0.2rem rgba(52, 152, 219, 0.25);
634
+ }
709
635
 
710
- & p {
711
- margin: 1.5rem 0 0;
712
- }
713
- }
636
+ .filter-actions {
637
+ display: flex;
638
+ gap: 0.5rem;
639
+ flex-wrap: wrap;
640
+ flex-shrink: 0;
714
641
  }
715
642
 
716
643
  .loading {
@@ -768,8 +695,15 @@
768
695
  }
769
696
  }
770
697
 
771
- .view-field .field-value img {
772
- max-width: 200px;
698
+ .view-field {
699
+ .field-value img {
700
+ max-width: 200px;
701
+ }
702
+
703
+ .admin-audio-player {
704
+ width: 100%;
705
+ max-width: 400px;
706
+ }
773
707
  }
774
708
 
775
709
  .edit-field {
@@ -787,12 +721,12 @@
787
721
  margin: 0;
788
722
  padding: 0.5rem;
789
723
  border: none;
790
- background: transparent;
724
+ background-color: transparent;
791
725
 
792
726
  &:not([disabled]) {
793
727
  margin: 0;
794
728
  border: 1px solid #7f8c8d;
795
- background: var(--white);
729
+ background-color: var(--white);
796
730
 
797
731
  &[type="checkbox"] {
798
732
  max-width: max-content;
@@ -806,7 +740,7 @@
806
740
  }
807
741
 
808
742
  .actions {
809
- margin-top: 2rem;
743
+ margin: 2rem 0;
810
744
  text-align: center;
811
745
 
812
746
  & form {
@@ -851,7 +785,7 @@
851
785
  overflow: auto;
852
786
  }
853
787
 
854
- .cache-confirm-dialog {
788
+ .confirm-dialog {
855
789
  border: none;
856
790
  border-radius: 8px;
857
791
  padding: 0;
@@ -860,38 +794,40 @@
860
794
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
861
795
  }
862
796
 
863
- .cache-confirm-dialog::backdrop {
797
+ .confirm-dialog::backdrop {
864
798
  background-color: rgba(0, 0, 0, 0.5);
865
799
  }
866
800
 
867
- .cache-dialog-content {
801
+ .dialog-content {
868
802
  padding: 1rem;
869
803
  }
870
804
 
871
- .cache-dialog-content h5 {
805
+ .dialog-content h5 {
872
806
  margin: 0 0 1rem 0;
873
807
  font-size: 18px;
874
808
  color: var(--darkGrey);
875
809
  }
876
810
 
877
- .cache-dialog-content p {
811
+ .dialog-content p {
878
812
  margin: 0 0 1rem 0;
879
813
  color: var(--darkGrey);
880
814
  }
881
815
 
882
- .cache-warning {
883
- padding: 1rem;
884
- background-color: #fff3cd;
885
- border: 1px solid #ffeaa7;
886
- border-radius: 4px;
887
- color: #856404;
888
- margin-bottom: 1rem;
889
- }
890
-
891
- .cache-dialog-actions {
816
+ .dialog-actions {
892
817
  display: flex;
893
818
  justify-content: flex-end;
894
819
  gap: 1rem;
895
820
  }
896
821
 
897
822
  }
823
+
824
+ @media (max-width: 768px) {
825
+ .reldens-admin-panel .filter-actions {
826
+ flex-direction: column;
827
+ }
828
+
829
+ .reldens-admin-panel .filter-actions .button {
830
+ width: 100%;
831
+ text-align: center;
832
+ }
833
+ }
@@ -12,42 +12,6 @@ window.addEventListener('DOMContentLoaded', () => {
12
12
  let queryString = location.search;
13
13
  let urlParams = new URLSearchParams(queryString);
14
14
 
15
- function getCookie(name)
16
- {
17
- let value = `; ${document.cookie}`;
18
- let parts = value.split(`; ${name}=`);
19
- if(2 === parts.length){
20
- return parts.pop().split(';').shift()
21
- }
22
- }
23
-
24
- function deleteCookie(name)
25
- {
26
- document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
27
- }
28
-
29
- function escapeHTML(str)
30
- {
31
- return str.replace(/&/g, "&")
32
- .replace(/</g, "&lt;")
33
- .replace(/>/g, "&gt;")
34
- .replace(/"/g, "&quot;")
35
- .replace(/'/g, "&#039;");
36
- }
37
-
38
- function cloneElement(element)
39
- {
40
- if(element instanceof HTMLCanvasElement){
41
- let clonedCanvas = document.createElement('canvas');
42
- clonedCanvas.width = element.width;
43
- clonedCanvas.height = element.height;
44
- let ctx = clonedCanvas.getContext('2d');
45
- ctx.drawImage(element, 0, 0);
46
- return clonedCanvas
47
- }
48
- return element.cloneNode(true);
49
- }
50
-
51
15
  // error codes messages map:
52
16
  let errorMessages = {
53
17
  saveBadPatchData: 'Bad patch data on update.',
@@ -59,56 +23,9 @@ window.addEventListener('DOMContentLoaded', () => {
59
23
  errorId: 'Missing entity ID on POST.'
60
24
  };
61
25
 
62
- // copyright year:
63
- let copyRightYear = document.querySelector('.copyright-year');
64
- if(copyRightYear){
65
- copyRightYear.innerHTML = String((new Date()).getFullYear());
66
- }
67
-
68
- // activate expand/collapse elements
69
- let expandCollapseButtons = document.querySelectorAll('[data-expand-collapse]');
70
- if(expandCollapseButtons){
71
- for(let expandCollapseButton of expandCollapseButtons){
72
- expandCollapseButton.addEventListener('click', (event) => {
73
- let expandCollapseElement = document.querySelector(event.currentTarget.dataset.expandCollapse);
74
- if(expandCollapseElement){
75
- expandCollapseElement.classList.toggle('hidden');
76
- }
77
- });
78
- }
79
- }
26
+ activateExpandCollapse();
80
27
 
81
- // activate modals on click
82
- let modalElements = document.querySelectorAll('[data-toggle="modal"]');
83
- if(modalElements){
84
- for(let modalElement of modalElements){
85
- modalElement.addEventListener('click', () => {
86
- let overlay = document.createElement('div');
87
- overlay.classList.add('modal-overlay');
88
- let modal = document.createElement('div');
89
- modal.classList.add('modal');
90
- modal.classList.add('clickable');
91
- let clonedElement = cloneElement(modalElement);
92
- clonedElement.classList.add('clickable');
93
- modal.appendChild(clonedElement);
94
- overlay.appendChild(modal);
95
- document.body.appendChild(overlay);
96
- clonedElement.addEventListener('click', () => {
97
- document.body.removeChild(overlay);
98
- });
99
- modal.addEventListener('click', (e) => {
100
- if(e.target === modal){
101
- document.body.removeChild(modal.parentNode);
102
- }
103
- });
104
- overlay.addEventListener('click', (e) => {
105
- if(e.target === overlay) {
106
- document.body.removeChild(overlay);
107
- }
108
- });
109
- });
110
- }
111
- }
28
+ activateModalElements();
112
29
 
113
30
  // login errors:
114
31
  if('true' === urlParams.get('login-error')){
@@ -118,23 +35,64 @@ window.addEventListener('DOMContentLoaded', () => {
118
35
  }
119
36
  }
120
37
 
38
+ // entity search functionality:
39
+ let entityFilterTerm = document.querySelector('#entityFilterTerm');
40
+ let filterForm = document.querySelector('#filter-form');
41
+ let allFilters = document.querySelectorAll('.filters-toggle-content .filter input');
42
+ if(entityFilterTerm && filterForm){
43
+ entityFilterTerm.addEventListener('input', () => {
44
+ if(entityFilterTerm.value){
45
+ for(let filterInput of allFilters){
46
+ filterInput.value = '';
47
+ }
48
+ }
49
+ });
50
+ entityFilterTerm.addEventListener('keypress', (event) => {
51
+ if(13 === event.keyCode){
52
+ event.preventDefault();
53
+ filterForm.submit();
54
+ }
55
+ });
56
+ for(let filterInput of allFilters){
57
+ filterInput.addEventListener('input', () => {
58
+ if(filterInput.value){
59
+ entityFilterTerm.value = '';
60
+ }
61
+ });
62
+ }
63
+ filterForm.addEventListener('submit', () => {
64
+ if(entityFilterTerm.value && allFilters.some(input => input.value)){
65
+ for(let filterInput of allFilters){
66
+ filterInput.value = '';
67
+ }
68
+ }
69
+ });
70
+ }
71
+
121
72
  // forms behavior:
122
73
  let forms = document.querySelectorAll('form');
123
74
  if(forms){
124
75
  for(let form of forms){
125
76
  form.addEventListener('submit', (event) => {
126
- let submitButton = document.querySelector('input[type="submit"]');
77
+ let submitButton = form.querySelector('input[type="submit"], button[type="submit"]');
127
78
  submitButton.disabled = true;
128
79
  let loadingImage = document.querySelector('.submit-container .loading');
129
80
  if(loadingImage){
130
81
  loadingImage.classList.remove('hidden');
131
82
  }
132
83
  if(form.classList.contains('form-delete') || form.classList.contains('confirmation-required')){
133
- if(!confirm('Are you sure?')){
134
- event.preventDefault();
135
- submitButton.disabled = false;
136
- loadingImage.classList.add('hidden');
137
- }
84
+ event.preventDefault();
85
+ showConfirmDialog((confirmed) => {
86
+ if(confirmed){
87
+ form.submit();
88
+ }
89
+ if(!confirmed){
90
+ submitButton.disabled = false;
91
+ if(loadingImage){
92
+ loadingImage.classList.add('hidden');
93
+ }
94
+ }
95
+ });
138
96
  }
139
97
  });
140
98
  }
@@ -180,21 +138,33 @@ window.addEventListener('DOMContentLoaded', () => {
180
138
  filtersToggleContent.classList.toggle('hidden');
181
139
  });
182
140
  let allFilters = document.querySelectorAll('.filters-toggle-content .filter input');
141
+ let entitySearchInput = document.querySelector('#entityFilterTerm');
142
+ let hasEntitySearch = entitySearchInput && '' !== entitySearchInput.value;
183
143
  let activeFilters = Array.from(allFilters).filter(input => '' !== input.value);
184
- if(0 < activeFilters.length){
144
+ if(0 < activeFilters.length || hasEntitySearch){
185
145
  filtersToggleContent.classList.remove('hidden');
186
- let paginationLinks = document.querySelectorAll('.pagination a');
187
- let filtersForm = document.querySelector('#filter-form');
188
- if(paginationLinks && filtersForm){
189
- for(let link of paginationLinks){
190
- link.addEventListener('click', (event) => {
191
- event.stopPropagation();
192
- event.preventDefault();
193
- filtersForm.action = link.href;
194
- filtersForm.submit();
195
- return false;
196
- })
197
- }
146
+ }
147
+ let paginationLinks = document.querySelectorAll('.pagination a');
148
+ if(paginationLinks && filterForm){
149
+ for(let link of paginationLinks){
150
+ link.addEventListener('click', (event) => {
151
+ event.stopPropagation();
152
+ event.preventDefault();
153
+ let url = new URL(link.href);
154
+ let params = new URLSearchParams(url.search);
155
+ if(entitySearchInput && entitySearchInput.value){
156
+ params.set('entityFilterTerm', entitySearchInput.value);
157
+ }
158
+ for(let filterInput of allFilters){
159
+ if(filterInput.value){
160
+ let filterName = filterInput.name;
161
+ params.set(filterName, filterInput.value);
162
+ }
163
+ }
164
+ let newUrl = url.pathname + '?' + params;
165
+ window.location.href = newUrl;
166
+ return false;
167
+ })
198
168
  }
199
169
  }
200
170
  }
@@ -216,19 +186,31 @@ window.addEventListener('DOMContentLoaded', () => {
216
186
  let deleteSelectionForm = document.getElementById('delete-selection-form');
217
187
  let hiddenInput = document.querySelector('.hidden-ids-input');
218
188
  if(listDeleteSelection && deleteSelectionForm && hiddenInput){
219
- listDeleteSelection.addEventListener('click', () => {
220
- if(!confirm('Are you sure?')){
221
- return;
222
- }
223
- let checkboxes = document.querySelectorAll('.ids-checkbox');
224
- let ids = [];
225
- for(let checkbox of checkboxes){
226
- if(checkbox.checked){
227
- ids.push(checkbox.value);
189
+ listDeleteSelection.addEventListener('click', (event) => {
190
+ event.preventDefault();
191
+ showConfirmDialog((confirmed) => {
192
+ if(confirmed){
193
+ let checkboxes = document.querySelectorAll('.ids-checkbox');
194
+ let ids = [];
195
+ for(let checkbox of checkboxes){
196
+ if(checkbox.checked){
197
+ ids.push(parseInt(checkbox.value));
198
+ }
199
+ }
200
+ if(0 === ids.length){
201
+ return;
202
+ }
203
+ deleteSelectionForm.innerHTML = '';
204
+ for(let id of ids){
205
+ let input = document.createElement('input');
206
+ input.type = 'hidden';
207
+ input.name = 'ids[]';
208
+ input.value = id;
209
+ deleteSelectionForm.appendChild(input);
210
+ }
211
+ deleteSelectionForm.submit();
228
212
  }
229
- }
230
- hiddenInput.value = ids.join(',');
231
- deleteSelectionForm.submit();
213
+ });
232
214
  });
233
215
  }
234
216
 
@@ -278,25 +260,18 @@ window.addEventListener('DOMContentLoaded', () => {
278
260
 
279
261
  // cache clear all functionality:
280
262
  let cacheClearAllButton = document.querySelector('.cache-clear-all-button');
281
- let cacheConfirmDialog = document.querySelector('.cache-confirm-dialog');
282
- let cacheDialogCancel = document.querySelector('.cache-dialog-cancel');
283
263
  let cacheClearForm = document.querySelector('.cache-clear-form');
284
- if(cacheClearAllButton && cacheConfirmDialog){
264
+ if(cacheClearAllButton){
285
265
  cacheClearAllButton.addEventListener('click', () => {
286
- cacheConfirmDialog.showModal();
287
- });
288
- }
289
- if(cacheDialogCancel && cacheConfirmDialog){
290
- cacheDialogCancel.addEventListener('click', () => {
291
- cacheConfirmDialog.close();
292
- });
293
- }
294
- if(cacheClearForm){
295
- cacheClearForm.addEventListener('submit', (event) => {
296
- let submitButton = cacheClearForm.querySelector('button[type="submit"]');
297
- if(submitButton){
298
- submitButton.disabled = true;
299
- }
266
+ showConfirmDialog((confirmed) => {
267
+ if(confirmed && cacheClearForm){
268
+ let submitButton = cacheClearForm.querySelector('button[type="submit"]');
269
+ if(submitButton){
270
+ submitButton.disabled = true;
271
+ }
272
+ cacheClearForm.submit();
273
+ }
274
+ });
300
275
  });
301
276
  }
302
277
 
@@ -1,17 +1,17 @@
1
1
  <button type="button" class="button button-warning cache-clear-all-button">
2
2
  {{buttonText}}
3
3
  </button>
4
- <dialog class="cache-confirm-dialog">
5
- <div class="cache-dialog-content">
6
- <h5>{{confirmTitle}}</h5>
7
- <p>{{confirmMessage}}</p>
4
+ <dialog class="confirm-dialog">
5
+ <div class="dialog-content">
6
+ <h5 class="dialog-title">{{confirmTitle}}</h5>
7
+ <p class="dialog-message">{{confirmMessage}}</p>
8
8
  <div class="alert cache-warning">
9
9
  <strong>{{warningText}}</strong> {{warningMessage}}
10
10
  </div>
11
- <div class="cache-dialog-actions">
12
- <button type="button" class="button button-secondary cache-dialog-cancel">{{cancelText}}</button>
11
+ <div class="dialog-actions">
12
+ <button type="button" class="button button-secondary dialog-cancel">{{cancelText}}</button>
13
13
  <form method="post" action="{{clearAllCacheRoute}}" class="cache-clear-form">
14
- <button type="submit" class="button button-danger">{{confirmText}}</button>
14
+ <button type="submit" class="button button-danger dialog-confirm">{{confirmText}}</button>
15
15
  </form>
16
16
  </div>
17
17
  </div>
@@ -1,5 +1,11 @@
1
1
  <div class="entity-edit {{&entityName}}-edit">
2
2
  <h2>{{&templateTitle}}</h2>
3
+ <div class="actions">
4
+ <button class="button button-primary button-submit" type="submit" form="edit-form" name="saveAction" value="save">Save</button>
5
+ <button class="button button-primary button-submit" type="submit" form="edit-form" name="saveAction" value="saveAndContinue">Save and continue...</button>
6
+ <button class="button button-primary button-submit" type="submit" form="edit-form" name="saveAction" value="saveAndGoBack">Save and go back</button>
7
+ <a class="button button-secondary button-back" href="{{&entityViewRoute}}">Cancel</a>
8
+ </div>
3
9
  <form name="edit-form" id="edit-form" action="{{&entitySaveRoute}}" method="post"{{&multipartFormData}}>
4
10
  <input type="hidden" name="{{&idProperty}}" value="{{&idValue}}"/>
5
11
  <div class="edit-field">
@@ -18,6 +24,7 @@
18
24
  <div class="actions">
19
25
  <button class="button button-primary button-submit" type="submit" name="saveAction" value="save">Save</button>
20
26
  <button class="button button-primary button-submit" type="submit" name="saveAction" value="saveAndContinue">Save and continue...</button>
27
+ <button class="button button-primary button-submit" type="submit" name="saveAction" value="saveAndGoBack">Save and go back</button>
21
28
  <a class="button button-secondary button-back" href="{{&entityViewRoute}}">Cancel</a>
22
29
  </div>
23
30
  </form>
@@ -0,0 +1,7 @@
1
+ {{#fieldValue}}
2
+ <audio controls class="admin-audio-player">
3
+ <source src="{{&fieldValue}}">
4
+ Your browser does not support the audio element.
5
+ </audio>
6
+ <p><a href="{{&fieldValue}}"{{&target}}>{{&fieldValue}}</a></p>
7
+ {{/fieldValue}}
@@ -0,0 +1,8 @@
1
+ {{#fieldValue}}
2
+ <audio controls class="admin-audio-player multiple-files">
3
+ <source src="{{&fieldValuePart}}">
4
+ Your browser does not support the audio element.
5
+ </audio>
6
+ <p><a href="{{&fieldValuePart}}"{{&target}}>{{&fieldOriginalValuePart}}</a></p>
7
+ <br/>
8
+ {{/fieldValue}}