@reldens/cms 0.19.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 +399 -17
- package/admin/reldens-admin-client.css +156 -99
- 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 +111 -538
- package/lib/manager.js +26 -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/asset-transformer.js +41 -0
- package/lib/template-engine/collections-single-transformer.js +28 -5
- package/lib/template-engine/collections-transformer.js +66 -32
- package/lib/template-engine/date-transformer.js +53 -0
- package/lib/template-engine/entities-transformer.js +5 -2
- package/lib/template-engine/partials-transformer.js +8 -5
- package/lib/template-engine/system-variables-provider.js +108 -0
- package/lib/template-engine/translate-transformer.js +98 -0
- package/lib/template-engine/translation-service.js +104 -0
- package/lib/template-engine/url-transformer.js +41 -0
- package/lib/template-engine.js +99 -12
- 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
package/lib/manager.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { TemplatesList } = require('./templates-list');
|
|
8
|
-
const {
|
|
8
|
+
const { DefaultTranslations } = require('./admin-manager/default-translations');
|
|
9
9
|
const { AdminTemplatesLoader } = require('./admin-templates-loader');
|
|
10
10
|
const { AdminManagerValidator } = require('./admin-manager-validator');
|
|
11
11
|
const { MimeTypes } = require('./mime-types');
|
|
@@ -18,6 +18,7 @@ const { CmsPagesRouteManager } = require('./cms-pages-route-manager');
|
|
|
18
18
|
const { Installer } = require('./installer');
|
|
19
19
|
const { Frontend } = require('./frontend');
|
|
20
20
|
const { CacheManager } = require('./cache/cache-manager');
|
|
21
|
+
const { TemplateReloader } = require('./template-reloader');
|
|
21
22
|
const { EventsManagerSingleton, Logger, sc } = require('@reldens/utils');
|
|
22
23
|
const { DriversMap } = require('@reldens/storage');
|
|
23
24
|
const { AppServerFactory, FileHandler, Encryptor } = require('@reldens/server-utils');
|
|
@@ -34,6 +35,7 @@ class Manager
|
|
|
34
35
|
this.installLockPath = FileHandler.joinPaths(this.projectRoot, 'install.lock');
|
|
35
36
|
dotenv.config({path: this.envFilePath});
|
|
36
37
|
this.config = this.loadConfigFromEnv();
|
|
38
|
+
this.adminTranslations = sc.get(props, 'adminTranslations', {});
|
|
37
39
|
this.adminEntities = sc.get(props, 'adminEntities', {});
|
|
38
40
|
this.rawRegisteredEntities = sc.get(props, 'rawRegisteredEntities', {});
|
|
39
41
|
this.entitiesTranslations = sc.get(props, 'entitiesTranslations', {});
|
|
@@ -60,6 +62,7 @@ class Manager
|
|
|
60
62
|
this.siteKeyMapping = sc.get(props, 'siteKeyMapping', sc.toJson(process.env.RELDENS_SITE_KEY_MAPPING));
|
|
61
63
|
this.templateExtensions = sc.get(props, 'templateExtensions', ['.html', '.template']);
|
|
62
64
|
this.cache = sc.get(props, 'cache', false);
|
|
65
|
+
this.reloadTime = sc.get(props, 'reloadTime', 0);
|
|
63
66
|
this.app = sc.get(props, 'app', false);
|
|
64
67
|
this.appServer = sc.get(props, 'appServer', false);
|
|
65
68
|
this.dataServer = sc.get(props, 'dataServer', false);
|
|
@@ -67,14 +70,8 @@ class Manager
|
|
|
67
70
|
this.frontend = sc.get(props, 'frontend', false);
|
|
68
71
|
this.renderEngine = sc.get(props, 'renderEngine', mustache);
|
|
69
72
|
this.prismaClient = sc.get(props, 'prismaClient', false);
|
|
70
|
-
this.
|
|
71
|
-
|
|
72
|
-
'127.0.0.1',
|
|
73
|
-
'.local',
|
|
74
|
-
'.test',
|
|
75
|
-
'.dev',
|
|
76
|
-
'.staging'
|
|
77
|
-
]);
|
|
73
|
+
this.defaultDevelopmentPatterns = ['localhost', '127.0.0.1', '.local', '.test', '.dev'];
|
|
74
|
+
this.developmentPatterns = sc.get(props, 'developmentPatterns', this.defaultDevelopmentPatterns);
|
|
78
75
|
this.developmentEnvironments = sc.get(props, 'developmentEnvironments', ['development', 'dev', 'test']);
|
|
79
76
|
this.developmentPorts = sc.get(props, 'developmentPorts', [3000, 8080, 8081]);
|
|
80
77
|
this.developmentMultiplier = sc.get(props, 'developmentMultiplier', 10);
|
|
@@ -83,6 +80,14 @@ class Manager
|
|
|
83
80
|
this.appServerFactory = new AppServerFactory();
|
|
84
81
|
this.adminEntitiesGenerator = new AdminEntitiesGenerator();
|
|
85
82
|
this.cacheManager = new CacheManager({projectRoot: this.projectRoot, enabled: this.cache});
|
|
83
|
+
this.templateReloader = new TemplateReloader({
|
|
84
|
+
reloadTime: this.reloadTime,
|
|
85
|
+
events: this.events,
|
|
86
|
+
adminTemplatesLoader: AdminTemplatesLoader,
|
|
87
|
+
mappedAdminTemplates: this.mappedAdminTemplates,
|
|
88
|
+
templatesPath: FileHandler.joinPaths(this.projectRoot, 'templates'),
|
|
89
|
+
templateExtensions: this.templateExtensions
|
|
90
|
+
});
|
|
86
91
|
this.installer = new Installer({
|
|
87
92
|
projectRoot: this.projectRoot,
|
|
88
93
|
prismaClient: this.prismaClient,
|
|
@@ -411,8 +416,12 @@ class Manager
|
|
|
411
416
|
return passwordResult;
|
|
412
417
|
};
|
|
413
418
|
}
|
|
419
|
+
this.templateReloader.trackTemplateFiles(this.mappedAdminTemplates);
|
|
414
420
|
let adminFilesContents = await AdminTemplatesLoader.fetchAdminFilesContents(this.mappedAdminTemplates);
|
|
415
|
-
let translations =
|
|
421
|
+
let translations = sc.deepMergeProperties(
|
|
422
|
+
sc.deepMergeProperties({}, DefaultTranslations),
|
|
423
|
+
sc.deepMergeProperties(this.entitiesTranslations, this.adminTranslations)
|
|
424
|
+
);
|
|
416
425
|
this.events.emit('reldens.manager.initializeAdminManager', {
|
|
417
426
|
manager: this,
|
|
418
427
|
authenticationCallback,
|
|
@@ -430,7 +439,7 @@ class Manager
|
|
|
430
439
|
renderCallback: this.renderCallback.bind(this),
|
|
431
440
|
secret: this.config.adminSecret,
|
|
432
441
|
rootPath: this.config.adminPath,
|
|
433
|
-
translations
|
|
442
|
+
translations,
|
|
434
443
|
adminFilesContents,
|
|
435
444
|
mimeTypes: this.mimeTypes,
|
|
436
445
|
allowedExtensions: this.allowedExtensions,
|
|
@@ -448,6 +457,9 @@ class Manager
|
|
|
448
457
|
}
|
|
449
458
|
};
|
|
450
459
|
this.adminManager = new AdminManager(adminConfig);
|
|
460
|
+
this.adminManager.router.checkAndReloadAdminTemplates = async () => {
|
|
461
|
+
return await this.templateReloader.handleAdminTemplateReload(this.adminManager);
|
|
462
|
+
};
|
|
451
463
|
await this.adminManager.setupAdmin();
|
|
452
464
|
return true;
|
|
453
465
|
}
|
|
@@ -476,6 +488,7 @@ class Manager
|
|
|
476
488
|
this.frontend = new Frontend({
|
|
477
489
|
app: this.app,
|
|
478
490
|
dataServer: this.dataServer,
|
|
491
|
+
events: this.events,
|
|
479
492
|
renderEngine: this.renderEngine,
|
|
480
493
|
projectRoot: this.projectRoot,
|
|
481
494
|
appServerFactory: this.appServerFactory,
|
|
@@ -484,7 +497,8 @@ class Manager
|
|
|
484
497
|
siteKeyMapping: this.siteKeyMapping,
|
|
485
498
|
templateExtensions: this.templateExtensions,
|
|
486
499
|
entitiesConfig: this.entitiesConfig,
|
|
487
|
-
cacheManager: this.cacheManager
|
|
500
|
+
cacheManager: this.cacheManager,
|
|
501
|
+
handleFrontendTemplateReload: this.templateReloader.handleFrontendTemplateReload.bind(this.templateReloader)
|
|
488
502
|
});
|
|
489
503
|
return await this.frontend.initialize();
|
|
490
504
|
}
|
package/lib/search-renderer.js
CHANGED
|
@@ -35,8 +35,9 @@ class SearchRenderer
|
|
|
35
35
|
Logger.error('Search result partial template not found: ' + partialName);
|
|
36
36
|
continue;
|
|
37
37
|
}
|
|
38
|
+
let templateData = sc.get(config, 'render.templateData', {});
|
|
38
39
|
if(sc.hasOwn(entityResult, 'pagination')){
|
|
39
|
-
let entityContent = await this.renderSearchEntityResults(entityResult.results, partialTemplate, domain);
|
|
40
|
+
let entityContent = await this.renderSearchEntityResults(entityResult.results, partialTemplate, domain, templateData);
|
|
40
41
|
let totalPages = sc.get(entityResult.pagination, 'totalPages', 1);
|
|
41
42
|
if(1 < totalPages){
|
|
42
43
|
let paginationContainer = sc.get(config, 'render.paginationContainer', 'pagedCollection');
|
|
@@ -46,22 +47,30 @@ class SearchRenderer
|
|
|
46
47
|
hasResults: 0 < entityResult.results.length,
|
|
47
48
|
noResultsMessage: entityResult.noResultsMessage || 'No results found.'
|
|
48
49
|
});
|
|
49
|
-
renderedContent += this.renderEngine.render(
|
|
50
|
+
renderedContent += this.renderEngine.render(
|
|
51
|
+
paginationTemplate,
|
|
52
|
+
paginationData,
|
|
53
|
+
this.getPartialsForDomain(domain)
|
|
54
|
+
);
|
|
50
55
|
continue;
|
|
51
56
|
}
|
|
52
57
|
renderedContent += entityContent;
|
|
53
58
|
continue;
|
|
54
59
|
}
|
|
55
|
-
renderedContent += await this.renderSearchEntityResults(entityResult.results, partialTemplate, domain);
|
|
60
|
+
renderedContent += await this.renderSearchEntityResults(entityResult.results, partialTemplate, domain, templateData);
|
|
56
61
|
}
|
|
57
62
|
return renderedContent;
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
async renderSearchEntityResults(results, partialTemplate, domain)
|
|
65
|
+
async renderSearchEntityResults(results, partialTemplate, domain, templateData = {})
|
|
61
66
|
{
|
|
62
67
|
let renderedContent = '';
|
|
68
|
+
if(!sc.hasOwn(templateData, 'columnsClass') || '' === templateData.columnsClass){
|
|
69
|
+
templateData.columnsClass = 'col-lg-6';
|
|
70
|
+
}
|
|
63
71
|
for(let row of results){
|
|
64
|
-
|
|
72
|
+
let rowData = Object.assign({}, templateData, {row});
|
|
73
|
+
renderedContent += this.renderEngine.render(partialTemplate, rowData, this.getPartialsForDomain(domain));
|
|
65
74
|
}
|
|
66
75
|
return renderedContent;
|
|
67
76
|
}
|
|
@@ -85,8 +94,7 @@ class SearchRenderer
|
|
|
85
94
|
|
|
86
95
|
loadPartialTemplate(partialName, domain)
|
|
87
96
|
{
|
|
88
|
-
|
|
89
|
-
return sc.get(partials, partialName, false);
|
|
97
|
+
return sc.get(this.getPartialsForDomain(domain), partialName, false);
|
|
90
98
|
}
|
|
91
99
|
|
|
92
100
|
loadPaginationTemplate(containerName, domain)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - SearchRequestHandler
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class SearchRequestHandler
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(props)
|
|
13
|
+
{
|
|
14
|
+
this.search = sc.get(props, 'search', false);
|
|
15
|
+
this.searchRenderer = sc.get(props, 'searchRenderer', false);
|
|
16
|
+
this.contentRenderer = sc.get(props, 'contentRenderer', false);
|
|
17
|
+
this.requestProcessor = sc.get(props, 'requestProcessor', false);
|
|
18
|
+
this.cacheManager = sc.get(props, 'cacheManager', false);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async handleSearchRequest(req, res)
|
|
22
|
+
{
|
|
23
|
+
try {
|
|
24
|
+
let domain = this.requestProcessor.getDomainFromRequest(req);
|
|
25
|
+
let config = this.search.parseSearchParameters(req.query);
|
|
26
|
+
if(!config){
|
|
27
|
+
return res.redirect('/?error-message=searchInvalidParameters');
|
|
28
|
+
}
|
|
29
|
+
let cacheKey = this.requestProcessor.buildCacheKey(req.path, req);
|
|
30
|
+
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
31
|
+
let cachedContent = await this.cacheManager.get(domain, cacheKey);
|
|
32
|
+
if(cachedContent){
|
|
33
|
+
return res.send(cachedContent);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
let searchResults = await this.search.executeSearch(config);
|
|
37
|
+
if(false === searchResults){
|
|
38
|
+
return res.redirect('/?error-message=searchExecutionFailed');
|
|
39
|
+
}
|
|
40
|
+
let content = await this.contentRenderer.renderWithTemplateContent(
|
|
41
|
+
{
|
|
42
|
+
template: config.render.page,
|
|
43
|
+
layout: config.render.layout,
|
|
44
|
+
content: await this.searchRenderer.renderSearchResults(searchResults, config, domain, req)
|
|
45
|
+
},
|
|
46
|
+
Object.assign({}, {
|
|
47
|
+
search_query: sc.get(req.query, 'search', ''),
|
|
48
|
+
searchConfig: config,
|
|
49
|
+
query: req.query
|
|
50
|
+
}),
|
|
51
|
+
domain,
|
|
52
|
+
req,
|
|
53
|
+
null
|
|
54
|
+
);
|
|
55
|
+
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
56
|
+
await this.cacheManager.set(domain, cacheKey, content);
|
|
57
|
+
}
|
|
58
|
+
return res.send(content);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
Logger.error('Search request handling error: ' + error.message);
|
|
61
|
+
return res.redirect('/?error-message=searchError');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports.SearchRequestHandler = SearchRequestHandler;
|
package/lib/search.js
CHANGED
|
@@ -38,7 +38,8 @@ class Search
|
|
|
38
38
|
page: 'page',
|
|
39
39
|
layout: 'search',
|
|
40
40
|
paginationContainer: 'pagedCollection',
|
|
41
|
-
partial: 'entriesListView'
|
|
41
|
+
partial: 'entriesListView',
|
|
42
|
+
templateData: {}
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -184,6 +185,17 @@ class Search
|
|
|
184
185
|
if(partial){
|
|
185
186
|
config.render.partial = partial;
|
|
186
187
|
}
|
|
188
|
+
for(let key of Object.keys(query)){
|
|
189
|
+
if(!key.startsWith('templateData[')){
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
let templateMatch = key.match(/templateData\[([^\]]+)\]/);
|
|
193
|
+
if(!templateMatch){
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
let templateKey = templateMatch[1];
|
|
197
|
+
config.render.templateData[templateKey] = query[key];
|
|
198
|
+
}
|
|
187
199
|
return config;
|
|
188
200
|
}
|
|
189
201
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - AssetTransformer
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class AssetTransformer
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
async transform(template, domain, req, systemVariables)
|
|
13
|
+
{
|
|
14
|
+
if(!template){
|
|
15
|
+
return template;
|
|
16
|
+
}
|
|
17
|
+
let currentRequest = sc.get(systemVariables, 'currentRequest', {});
|
|
18
|
+
let assetPattern = /\[asset\(([^)]+)\)\]/g;
|
|
19
|
+
let matches = [...template.matchAll(assetPattern)];
|
|
20
|
+
for(let i = matches.length - 1; i >= 0; i--){
|
|
21
|
+
let match = matches[i];
|
|
22
|
+
let assetPath = match[1].replace(/['"]/g, '');
|
|
23
|
+
let absoluteUrl = this.buildAssetUrl(assetPath, currentRequest);
|
|
24
|
+
template = template.substring(0, match.index) +
|
|
25
|
+
absoluteUrl +
|
|
26
|
+
template.substring(match.index + match[0].length);
|
|
27
|
+
}
|
|
28
|
+
return template;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
buildAssetUrl(assetPath, currentRequest)
|
|
32
|
+
{
|
|
33
|
+
if(!assetPath || assetPath.startsWith('http')){
|
|
34
|
+
return assetPath;
|
|
35
|
+
}
|
|
36
|
+
return sc.get(currentRequest, 'baseUrl', '')+'/assets'+(assetPath.startsWith('/') ? assetPath : '/'+assetPath);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports.AssetTransformer = AssetTransformer;
|
|
@@ -10,12 +10,22 @@ const { sc } = require('@reldens/utils');
|
|
|
10
10
|
class CollectionsSingleTransformer extends CollectionsTransformerBase
|
|
11
11
|
{
|
|
12
12
|
|
|
13
|
+
constructor(props)
|
|
14
|
+
{
|
|
15
|
+
super(props);
|
|
16
|
+
this.renderEngine = sc.get(props, 'renderEngine', false);
|
|
17
|
+
this.getPartials = sc.get(props, 'getPartials', false);
|
|
18
|
+
this.findAllPartialTags = sc.get(props, 'findAllPartialTags', false);
|
|
19
|
+
this.loadPartialTemplate = sc.get(props, 'loadPartialTemplate', false);
|
|
20
|
+
this.processAllTemplateFunctions = sc.get(props, 'processAllTemplateFunctions', false);
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
getSingleFieldCollectionRegex()
|
|
14
24
|
{
|
|
15
25
|
return /<collection\s+([^>]+)\/>/g;
|
|
16
26
|
}
|
|
17
27
|
|
|
18
|
-
async transform(template, domain)
|
|
28
|
+
async transform(template, domain, req, systemVariables, enhancedData = {})
|
|
19
29
|
{
|
|
20
30
|
let processedTemplate = template;
|
|
21
31
|
for(let match of template.matchAll(this.getSingleFieldCollectionRegex())){
|
|
@@ -30,20 +40,33 @@ class CollectionsSingleTransformer extends CollectionsTransformerBase
|
|
|
30
40
|
let fieldName = this.extractAttributeValue(tagContent, 'field');
|
|
31
41
|
processedTemplate = processedTemplate.replace(
|
|
32
42
|
match[0],
|
|
33
|
-
this.extractFieldValues(
|
|
43
|
+
await this.extractFieldValues(
|
|
34
44
|
await this.fetchCollectionForTemplate(tableName, filtersJson, queryOptionsJson, relationsString),
|
|
35
|
-
fieldName
|
|
45
|
+
fieldName,
|
|
46
|
+
domain,
|
|
47
|
+
req,
|
|
48
|
+
systemVariables,
|
|
49
|
+
enhancedData
|
|
36
50
|
)
|
|
37
51
|
);
|
|
38
52
|
}
|
|
39
53
|
return processedTemplate;
|
|
40
54
|
}
|
|
41
55
|
|
|
42
|
-
extractFieldValues(collectionData, fieldName)
|
|
56
|
+
async extractFieldValues(collectionData, fieldName, domain, req, systemVariables, enhancedData)
|
|
43
57
|
{
|
|
44
58
|
let fieldValues = '';
|
|
45
59
|
for(let row of collectionData){
|
|
46
|
-
|
|
60
|
+
let fieldValue = sc.get(row, fieldName, '');
|
|
61
|
+
if(!fieldValue){
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if(!this.processAllTemplateFunctions){
|
|
65
|
+
fieldValues += fieldValue;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
fieldValue = await this.processAllTemplateFunctions(fieldValue, domain, req, systemVariables, enhancedData);
|
|
69
|
+
fieldValues += fieldValue;
|
|
47
70
|
}
|
|
48
71
|
return fieldValues;
|
|
49
72
|
}
|
|
@@ -18,6 +18,7 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
18
18
|
this.getPartials = sc.get(props, 'getPartials', false);
|
|
19
19
|
this.findAllPartialTags = sc.get(props, 'findAllPartialTags', false);
|
|
20
20
|
this.loadPartialTemplate = sc.get(props, 'loadPartialTemplate', false);
|
|
21
|
+
this.processAllTemplateFunctions = sc.get(props, 'processAllTemplateFunctions', false);
|
|
21
22
|
this.paginationHandler = new PaginationHandler();
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -31,7 +32,7 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
31
32
|
return new RegExp('<\\/collection>');
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
async transform(template, domain, req)
|
|
35
|
+
async transform(template, domain, req, systemVariables, enhancedData = {})
|
|
35
36
|
{
|
|
36
37
|
let processedTemplate = template;
|
|
37
38
|
let matches = [...template.matchAll(this.getLoopCollectionStartRegex())];
|
|
@@ -62,7 +63,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
62
63
|
prevPages,
|
|
63
64
|
nextPages,
|
|
64
65
|
domain,
|
|
65
|
-
req
|
|
66
|
+
req,
|
|
67
|
+
systemVariables,
|
|
68
|
+
enhancedData
|
|
66
69
|
);
|
|
67
70
|
if(loopResult){
|
|
68
71
|
processedTemplate = loopResult;
|
|
@@ -76,7 +79,10 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
76
79
|
filtersJson,
|
|
77
80
|
relationsString,
|
|
78
81
|
queryOptionsJson,
|
|
79
|
-
domain
|
|
82
|
+
domain,
|
|
83
|
+
req,
|
|
84
|
+
systemVariables,
|
|
85
|
+
enhancedData
|
|
80
86
|
);
|
|
81
87
|
if(loopResult){
|
|
82
88
|
processedTemplate = loopResult;
|
|
@@ -92,7 +98,10 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
92
98
|
filtersJson,
|
|
93
99
|
relationsString,
|
|
94
100
|
queryOptionsJson,
|
|
95
|
-
domain
|
|
101
|
+
domain,
|
|
102
|
+
req,
|
|
103
|
+
systemVariables,
|
|
104
|
+
enhancedData
|
|
96
105
|
){
|
|
97
106
|
return await this.processCollectionBase(
|
|
98
107
|
template,
|
|
@@ -102,7 +111,10 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
102
111
|
relationsString,
|
|
103
112
|
queryOptionsJson,
|
|
104
113
|
domain,
|
|
105
|
-
false
|
|
114
|
+
false,
|
|
115
|
+
req,
|
|
116
|
+
systemVariables,
|
|
117
|
+
enhancedData
|
|
106
118
|
);
|
|
107
119
|
}
|
|
108
120
|
|
|
@@ -118,7 +130,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
118
130
|
prevPages,
|
|
119
131
|
nextPages,
|
|
120
132
|
domain,
|
|
121
|
-
req
|
|
133
|
+
req,
|
|
134
|
+
systemVariables,
|
|
135
|
+
enhancedData
|
|
122
136
|
){
|
|
123
137
|
if(!req){
|
|
124
138
|
Logger.warning('No request provided for pagination, falling back to regular collection');
|
|
@@ -129,7 +143,10 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
129
143
|
filtersJson,
|
|
130
144
|
relationsString,
|
|
131
145
|
queryOptionsJson,
|
|
132
|
-
domain
|
|
146
|
+
domain,
|
|
147
|
+
req,
|
|
148
|
+
systemVariables,
|
|
149
|
+
enhancedData
|
|
133
150
|
);
|
|
134
151
|
}
|
|
135
152
|
return await this.processCollectionBase(
|
|
@@ -146,7 +163,10 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
146
163
|
prevPages,
|
|
147
164
|
nextPages,
|
|
148
165
|
req
|
|
149
|
-
}
|
|
166
|
+
},
|
|
167
|
+
req,
|
|
168
|
+
systemVariables,
|
|
169
|
+
enhancedData
|
|
150
170
|
);
|
|
151
171
|
}
|
|
152
172
|
|
|
@@ -158,7 +178,10 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
158
178
|
relationsString,
|
|
159
179
|
queryOptionsJson,
|
|
160
180
|
domain,
|
|
161
|
-
paginationOptions
|
|
181
|
+
paginationOptions,
|
|
182
|
+
req,
|
|
183
|
+
systemVariables,
|
|
184
|
+
enhancedData
|
|
162
185
|
){
|
|
163
186
|
let startPos = startMatch.index;
|
|
164
187
|
let startEnd = startPos + startMatch[0].length;
|
|
@@ -211,13 +234,14 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
211
234
|
this.jsonFieldsParser.getJsonFieldsForEntity(tableName)
|
|
212
235
|
);
|
|
213
236
|
}
|
|
214
|
-
let collectionContent = await this.renderCollectionLoop(loopContent, collectionData, domain);
|
|
237
|
+
let collectionContent = await this.renderCollectionLoop(loopContent, collectionData, domain, req, systemVariables, enhancedData);
|
|
215
238
|
finalContent = this.renderEngine.render(
|
|
216
239
|
1 < paginationData.totalPages
|
|
217
240
|
? this.loadPaginationTemplate(paginationOptions.containerName, domain)
|
|
218
241
|
: '{{&collectionContentForCurrentPage}}',
|
|
219
242
|
Object.assign(
|
|
220
243
|
{},
|
|
244
|
+
enhancedData,
|
|
221
245
|
paginationData,
|
|
222
246
|
{
|
|
223
247
|
collectionContentForCurrentPage: collectionContent,
|
|
@@ -235,7 +259,7 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
235
259
|
queryOptionsJson,
|
|
236
260
|
relationsString
|
|
237
261
|
);
|
|
238
|
-
finalContent = await this.renderCollectionLoop(loopContent, collectionData, domain);
|
|
262
|
+
finalContent = await this.renderCollectionLoop(loopContent, collectionData, domain, req, systemVariables, enhancedData);
|
|
239
263
|
}
|
|
240
264
|
return template.substring(0, startPos) + finalContent + template.substring(endPos + endMatch[0].length);
|
|
241
265
|
}
|
|
@@ -281,36 +305,40 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
281
305
|
return '{{&collectionContentForCurrentPage}}';
|
|
282
306
|
}
|
|
283
307
|
|
|
284
|
-
async renderCollectionLoop(loopContent, collectionData, domain)
|
|
308
|
+
async renderCollectionLoop(loopContent, collectionData, domain, req, systemVariables, enhancedData)
|
|
285
309
|
{
|
|
286
310
|
if(!collectionData || 0 === collectionData.length){
|
|
287
|
-
return this.renderNoResultsMessage(domain);
|
|
311
|
+
return this.renderNoResultsMessage(domain, enhancedData);
|
|
288
312
|
}
|
|
289
313
|
let renderedContent = '';
|
|
290
314
|
for(let row of collectionData){
|
|
291
|
-
renderedContent += await this.processPartialsInLoop(loopContent, row, domain);
|
|
315
|
+
renderedContent += await this.processPartialsInLoop(loopContent, row, domain, req, systemVariables, enhancedData);
|
|
292
316
|
}
|
|
293
317
|
return renderedContent;
|
|
294
318
|
}
|
|
295
319
|
|
|
296
|
-
renderNoResultsMessage(domain)
|
|
320
|
+
renderNoResultsMessage(domain, enhancedData)
|
|
297
321
|
{
|
|
298
322
|
let noResultsTemplate = this.loadPartialTemplate('noResults', domain);
|
|
299
323
|
if(noResultsTemplate){
|
|
300
324
|
return this.renderEngine.render(
|
|
301
325
|
noResultsTemplate,
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
326
|
+
Object.assign(
|
|
327
|
+
{},
|
|
328
|
+
enhancedData,
|
|
329
|
+
{
|
|
330
|
+
message: 'No results found.',
|
|
331
|
+
cssClass: 'no-results',
|
|
332
|
+
alertClass: 'alert-info'
|
|
333
|
+
}
|
|
334
|
+
),
|
|
307
335
|
this.getPartials(domain)
|
|
308
336
|
);
|
|
309
337
|
}
|
|
310
338
|
return '';
|
|
311
339
|
}
|
|
312
340
|
|
|
313
|
-
async processPartialsInLoop(content, rowData, domain)
|
|
341
|
+
async processPartialsInLoop(content, rowData, domain, req, systemVariables, enhancedData)
|
|
314
342
|
{
|
|
315
343
|
let processedContent = content;
|
|
316
344
|
let partialTags = this.findAllPartialTags(content);
|
|
@@ -322,20 +350,26 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
322
350
|
processedContent = processedContent.substring(0, tag.start)+''+processedContent.substring(tag.end);
|
|
323
351
|
continue;
|
|
324
352
|
}
|
|
353
|
+
if(this.processAllTemplateFunctions){
|
|
354
|
+
partialContent = await this.processAllTemplateFunctions(partialContent, domain, req, systemVariables, enhancedData);
|
|
355
|
+
}
|
|
356
|
+
let renderData = Object.assign({}, enhancedData);
|
|
325
357
|
if(sc.hasOwn(tag.attributes, 'row')){
|
|
326
|
-
|
|
327
|
-
+this.renderEngine.render(partialContent, {row: rowData}, this.getPartials(domain))
|
|
328
|
-
+processedContent.substring(tag.end);
|
|
329
|
-
continue;
|
|
358
|
+
renderData.row = rowData;
|
|
330
359
|
}
|
|
331
|
-
let
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
360
|
+
for(let key of Object.keys(tag.attributes)){
|
|
361
|
+
if('row' !== key){
|
|
362
|
+
renderData[key] = tag.attributes[key];
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
processedContent = processedContent.substring(0, tag.start)
|
|
366
|
+
+this.renderEngine.render(partialContent, renderData, this.getPartials(domain))
|
|
367
|
+
+processedContent.substring(tag.end);
|
|
368
|
+
}
|
|
369
|
+
if(this.processAllTemplateFunctions){
|
|
370
|
+
processedContent = await this.processAllTemplateFunctions(processedContent, domain, req, systemVariables, enhancedData);
|
|
337
371
|
}
|
|
338
|
-
return this.renderEngine.render(processedContent, {row: rowData}, this.getPartials(domain));
|
|
372
|
+
return this.renderEngine.render(processedContent, Object.assign({}, enhancedData, {row: rowData}), this.getPartials(domain));
|
|
339
373
|
}
|
|
340
374
|
|
|
341
375
|
getCurrentUrl(req)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - DateTransformer
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class DateTransformer
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(props)
|
|
13
|
+
{
|
|
14
|
+
this.defaultFormat = sc.get(props, 'defaultFormat', 'Y-m-d H:i:s');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async transform(template, domain, req, systemVariables)
|
|
18
|
+
{
|
|
19
|
+
if(!template){
|
|
20
|
+
return template;
|
|
21
|
+
}
|
|
22
|
+
let datePattern = /\[date\(([^)]*)\)\]/g;
|
|
23
|
+
let matches = [...template.matchAll(datePattern)];
|
|
24
|
+
for(let i = matches.length - 1; i >= 0; i--){
|
|
25
|
+
let match = matches[i];
|
|
26
|
+
let args = match[1] ? match[1].split(',').map(arg => arg.trim().replace(/['"]/g, '')) : [];
|
|
27
|
+
let dateValue = args[0] || '';
|
|
28
|
+
let formatValue = args[1] || this.defaultFormat;
|
|
29
|
+
let formattedDate = this.formatDate(dateValue, formatValue);
|
|
30
|
+
template = template.substring(0, match.index) +
|
|
31
|
+
formattedDate +
|
|
32
|
+
template.substring(match.index + match[0].length);
|
|
33
|
+
}
|
|
34
|
+
return template;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
formatDate(dateValue, format)
|
|
38
|
+
{
|
|
39
|
+
let date;
|
|
40
|
+
if(!dateValue || '' === dateValue || 'now' === dateValue.toLowerCase()){
|
|
41
|
+
date = new Date();
|
|
42
|
+
} else {
|
|
43
|
+
date = new Date(dateValue);
|
|
44
|
+
if(isNaN(date.getTime())){
|
|
45
|
+
date = new Date();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return sc.formatDate(date, format);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports.DateTransformer = DateTransformer;
|
|
@@ -21,7 +21,7 @@ class EntitiesTransformer
|
|
|
21
21
|
return /<entity\s+name="([^"]+)"(?:\s+field="([^"]+)"\s+value="([^"]+)"|\s+id="([^"]+)")?\s*\/?>/g;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
async transform(template, domain)
|
|
24
|
+
async transform(template, domain, req, systemVariables, enhancedData = {})
|
|
25
25
|
{
|
|
26
26
|
let processedTemplate = template;
|
|
27
27
|
for(let match of template.matchAll(this.getEntityRegex())){
|
|
@@ -36,7 +36,10 @@ class EntitiesTransformer
|
|
|
36
36
|
match[0],
|
|
37
37
|
await this.processAllTemplateFunctions(
|
|
38
38
|
sc.get(await this.fetchEntityForTemplate(tableName, value, field), 'content', ''),
|
|
39
|
-
domain
|
|
39
|
+
domain,
|
|
40
|
+
req,
|
|
41
|
+
systemVariables,
|
|
42
|
+
enhancedData
|
|
40
43
|
)
|
|
41
44
|
);
|
|
42
45
|
}
|