@reldens/cms 0.20.0 → 0.21.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 +236 -11
- package/admin/reldens-admin-client.css +75 -21
- 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/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/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 +50 -45
- package/lib/admin-manager/router.js +19 -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 +89 -630
- 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/partials-transformer.js +5 -6
- package/lib/template-engine/system-variables-provider.js +4 -1
- package/lib/template-engine.js +11 -5
- package/lib/template-reloader.js +307 -0
- package/package.json +4 -4
- 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/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
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - TemplateReloader
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { FileHandler } = require('@reldens/server-utils');
|
|
8
|
+
const { sc } = require('@reldens/utils');
|
|
9
|
+
|
|
10
|
+
class TemplateReloader
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
constructor(props = {})
|
|
14
|
+
{
|
|
15
|
+
this.reloadTime = sc.get(props, 'reloadTime', 0);
|
|
16
|
+
this.events = sc.get(props, 'events', false);
|
|
17
|
+
this.fileTracking = {};
|
|
18
|
+
this.reloadInterval = false;
|
|
19
|
+
this.isActive = -1 === this.reloadTime || 0 < this.reloadTime;
|
|
20
|
+
this.adminTemplatesLoader = sc.get(props, 'adminTemplatesLoader', false);
|
|
21
|
+
this.mappedAdminTemplates = sc.get(props, 'mappedAdminTemplates', {});
|
|
22
|
+
this.templatesPath = sc.get(props, 'templatesPath', '');
|
|
23
|
+
this.templateExtensions = sc.get(props, 'templateExtensions', []);
|
|
24
|
+
this.setupReloadInterval();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
setupReloadInterval()
|
|
28
|
+
{
|
|
29
|
+
if(0 >= this.reloadTime){
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
if(this.reloadInterval){
|
|
33
|
+
clearInterval(this.reloadInterval);
|
|
34
|
+
}
|
|
35
|
+
this.reloadInterval = setInterval(() => {
|
|
36
|
+
this.checkAndReloadChangedTemplates();
|
|
37
|
+
}, this.reloadTime);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
iterateTemplateFiles(templatesPaths, callback)
|
|
41
|
+
{
|
|
42
|
+
if(!templatesPaths){
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if(sc.isString(templatesPaths)){
|
|
46
|
+
return callback(templatesPaths);
|
|
47
|
+
}
|
|
48
|
+
if(Array.isArray(templatesPaths)){
|
|
49
|
+
let result = false;
|
|
50
|
+
for(let filePath of templatesPaths){
|
|
51
|
+
if(callback(filePath)){
|
|
52
|
+
result = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
if(sc.isObject(templatesPaths)){
|
|
58
|
+
let result = false;
|
|
59
|
+
for(let key of Object.keys(templatesPaths)){
|
|
60
|
+
let templateData = templatesPaths[key];
|
|
61
|
+
if(sc.isObject(templateData)){
|
|
62
|
+
if(this.iterateTemplateFiles(templateData, callback)){
|
|
63
|
+
result = true;
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if(callback(templateData)){
|
|
68
|
+
result = true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
trackTemplateFiles(templatesPaths)
|
|
77
|
+
{
|
|
78
|
+
if(0 === this.reloadTime){
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return this.iterateTemplateFiles(templatesPaths, (filePath) => {
|
|
82
|
+
if(!FileHandler.exists(filePath)){
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
let modTime = FileHandler.getFileModificationTime(filePath);
|
|
86
|
+
if(!modTime){
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
this.fileTracking[filePath] = {
|
|
90
|
+
lastModified: modTime,
|
|
91
|
+
isChanged: false
|
|
92
|
+
};
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
checkTemplateChanges(templatesPaths)
|
|
98
|
+
{
|
|
99
|
+
if(0 === this.reloadTime){
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return this.iterateTemplateFiles(templatesPaths, (filePath) => {
|
|
103
|
+
if(!FileHandler.exists(filePath)){
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
let trackedFile = this.fileTracking[filePath];
|
|
107
|
+
if(!trackedFile){
|
|
108
|
+
this.trackTemplateFiles(filePath);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
let currentModTime = FileHandler.getFileModificationTime(filePath);
|
|
112
|
+
if(!currentModTime){
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if(currentModTime.getTime() > trackedFile.lastModified.getTime()){
|
|
116
|
+
if(-1 !== this.reloadTime){
|
|
117
|
+
trackedFile.lastModified = currentModTime;
|
|
118
|
+
}
|
|
119
|
+
trackedFile.isChanged = true;
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
hasChangedTemplates(templatesPaths)
|
|
127
|
+
{
|
|
128
|
+
return this.iterateTemplateFiles(templatesPaths, (filePath) => {
|
|
129
|
+
let trackedFile = this.fileTracking[filePath];
|
|
130
|
+
return trackedFile ? trackedFile.isChanged : false;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
markTemplatesAsReloaded(templatesPaths)
|
|
135
|
+
{
|
|
136
|
+
if(0 === this.reloadTime){
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
return this.iterateTemplateFiles(templatesPaths, (filePath) => {
|
|
140
|
+
let trackedFile = this.fileTracking[filePath];
|
|
141
|
+
if(trackedFile){
|
|
142
|
+
trackedFile.isChanged = false;
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
shouldReloadAdminTemplates(mappedAdminTemplates)
|
|
149
|
+
{
|
|
150
|
+
if(0 === this.reloadTime){
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
if(-1 === this.reloadTime){
|
|
154
|
+
return this.checkTemplateChanges(mappedAdminTemplates);
|
|
155
|
+
}
|
|
156
|
+
return this.hasChangedTemplates(mappedAdminTemplates);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
shouldReloadFrontendTemplates(templatesPath, templateExtensions)
|
|
160
|
+
{
|
|
161
|
+
if(0 === this.reloadTime){
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
let templateFiles = this.collectTemplateFiles(templatesPath, templateExtensions);
|
|
165
|
+
if(-1 === this.reloadTime){
|
|
166
|
+
return this.checkTemplateChanges(templateFiles);
|
|
167
|
+
}
|
|
168
|
+
return this.hasChangedTemplates(templateFiles);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
collectTemplateFiles(templatesPath, templateExtensions)
|
|
172
|
+
{
|
|
173
|
+
let templateFiles = [];
|
|
174
|
+
if(!FileHandler.exists(templatesPath)){
|
|
175
|
+
return templateFiles;
|
|
176
|
+
}
|
|
177
|
+
let partialsPath = FileHandler.joinPaths(templatesPath, 'partials');
|
|
178
|
+
if(FileHandler.exists(partialsPath)){
|
|
179
|
+
let partialFiles = FileHandler.getFilesInFolder(partialsPath, templateExtensions);
|
|
180
|
+
for(let file of partialFiles){
|
|
181
|
+
templateFiles.push(FileHandler.joinPaths(partialsPath, file));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
let domainsPath = FileHandler.joinPaths(templatesPath, 'domains');
|
|
185
|
+
if(FileHandler.exists(domainsPath)){
|
|
186
|
+
let domainFolders = FileHandler.fetchSubFoldersList(domainsPath);
|
|
187
|
+
for(let domain of domainFolders){
|
|
188
|
+
let domainPath = FileHandler.joinPaths(domainsPath, domain);
|
|
189
|
+
let domainPartialsPath = FileHandler.joinPaths(domainPath, 'partials');
|
|
190
|
+
if(FileHandler.exists(domainPartialsPath)){
|
|
191
|
+
let domainPartialFiles = FileHandler.getFilesInFolder(domainPartialsPath, templateExtensions);
|
|
192
|
+
for(let file of domainPartialFiles){
|
|
193
|
+
templateFiles.push(FileHandler.joinPaths(domainPartialsPath, file));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return templateFiles;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
checkAndReloadChangedTemplates()
|
|
202
|
+
{
|
|
203
|
+
if(0 === this.reloadTime){
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
let hasChanges = false;
|
|
207
|
+
for(let filePath of Object.keys(this.fileTracking)){
|
|
208
|
+
if(this.checkTemplateChanges(filePath)){
|
|
209
|
+
hasChanges = true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if(hasChanges && this.events){
|
|
213
|
+
this.events.emit('reldens.templateReloader.templatesChanged', {
|
|
214
|
+
reloader: this,
|
|
215
|
+
changedFiles: this.getChangedFiles()
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
return hasChanges;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
getChangedFiles()
|
|
222
|
+
{
|
|
223
|
+
let changedFiles = [];
|
|
224
|
+
for(let filePath of Object.keys(this.fileTracking)){
|
|
225
|
+
let trackedFile = this.fileTracking[filePath];
|
|
226
|
+
if(trackedFile && trackedFile.isChanged){
|
|
227
|
+
changedFiles.push(filePath);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return changedFiles;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
destroy()
|
|
234
|
+
{
|
|
235
|
+
if(this.reloadInterval){
|
|
236
|
+
clearInterval(this.reloadInterval);
|
|
237
|
+
this.reloadInterval = false;
|
|
238
|
+
}
|
|
239
|
+
this.fileTracking = {};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async checkAndReloadAdminTemplates()
|
|
243
|
+
{
|
|
244
|
+
if(!this.adminTemplatesLoader){
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
if(!this.shouldReloadAdminTemplates(this.mappedAdminTemplates)){
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
let newAdminFilesContents = await this.adminTemplatesLoader.fetchAdminFilesContents(this.mappedAdminTemplates);
|
|
251
|
+
if(!newAdminFilesContents){
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
this.markTemplatesAsReloaded(this.mappedAdminTemplates);
|
|
255
|
+
return newAdminFilesContents;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async checkAndReloadFrontendTemplates()
|
|
259
|
+
{
|
|
260
|
+
if(!this.shouldReloadFrontendTemplates(this.templatesPath, this.templateExtensions)){
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
let templateFiles = this.collectTemplateFiles(this.templatesPath, this.templateExtensions);
|
|
264
|
+
this.markTemplatesAsReloaded(templateFiles);
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async updateAdminContentsAfterReload(newAdminFilesContents, adminManager)
|
|
269
|
+
{
|
|
270
|
+
if(!newAdminFilesContents || !adminManager){
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
adminManager.adminFilesContents = newAdminFilesContents;
|
|
274
|
+
adminManager.contentsBuilder.adminFilesContents = newAdminFilesContents;
|
|
275
|
+
adminManager.routerContents.adminFilesContents = newAdminFilesContents;
|
|
276
|
+
adminManager.addCacheButtonSubscriber.cacheCleanButton = newAdminFilesContents.cacheCleanButton;
|
|
277
|
+
adminManager.addCacheButtonSubscriber.clearAllCacheButton = newAdminFilesContents.clearAllCacheButton;
|
|
278
|
+
await adminManager.contentsBuilder.buildAdminContents();
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async handleAdminTemplateReload(adminManager)
|
|
283
|
+
{
|
|
284
|
+
if(0 === this.reloadTime){
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
let reloadedContents = await this.checkAndReloadAdminTemplates();
|
|
288
|
+
if(reloadedContents){
|
|
289
|
+
await this.updateAdminContentsAfterReload(reloadedContents, adminManager);
|
|
290
|
+
}
|
|
291
|
+
return reloadedContents;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async handleFrontendTemplateReload(templateCache, templateResolver)
|
|
295
|
+
{
|
|
296
|
+
let reloadResult = await this.checkAndReloadFrontendTemplates();
|
|
297
|
+
if(reloadResult){
|
|
298
|
+
await templateCache.loadPartials();
|
|
299
|
+
await templateCache.setupDomainTemplates();
|
|
300
|
+
templateResolver.domainTemplatesMap = templateCache.getDomainTemplatesMap();
|
|
301
|
+
}
|
|
302
|
+
return reloadResult;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
module.exports.TemplateReloader = TemplateReloader;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reldens/cms",
|
|
3
3
|
"scope": "@reldens",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.21.0",
|
|
5
5
|
"description": "Reldens - CMS",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"url": "https://github.com/damian-pastorini/reldens-cms/issues"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@reldens/server-utils": "^0.
|
|
37
|
-
"@reldens/storage": "^0.
|
|
36
|
+
"@reldens/server-utils": "^0.23.0",
|
|
37
|
+
"@reldens/storage": "^0.62.0",
|
|
38
38
|
"@reldens/utils": "^0.50.0",
|
|
39
|
-
"dotenv": "^17.0
|
|
39
|
+
"dotenv": "^17.2.0",
|
|
40
40
|
"mustache": "^4.2.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
|
Binary file
|
|
@@ -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,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, "&")
|
|
24
|
+
.replace(/</g, "<")
|
|
25
|
+
.replace(/>/g, ">")
|
|
26
|
+
.replace(/"/g, """)
|
|
27
|
+
.replace(/'/g, "'");
|
|
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
|
+
}
|
package/templates/js/scripts.js
CHANGED
package/templates/page.html
CHANGED
|
@@ -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"
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
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;
|
package/templates/favicon.ico
DELETED
|
Binary file
|
/package/templates/assets/favicons/{android-icon-144x144.png → default/android-icon-144x144.png}
RENAMED
|
File without changes
|
/package/templates/assets/favicons/{android-icon-192x192.png → default/android-icon-192x192.png}
RENAMED
|
File without changes
|
/package/templates/assets/favicons/{android-icon-512x512.png → default/android-icon-512x512.png}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|