@reldens/cms 0.19.0 → 0.20.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 +168 -11
- package/admin/reldens-admin-client.css +81 -78
- package/lib/frontend.js +141 -27
- package/lib/manager.js +1 -0
- package/lib/template-engine/asset-transformer.js +41 -0
- package/lib/template-engine/collections-single-transformer.js +22 -5
- package/lib/template-engine/collections-transformer.js +35 -14
- package/lib/template-engine/date-transformer.js +53 -0
- package/lib/template-engine/entities-transformer.js +4 -2
- package/lib/template-engine/partials-transformer.js +5 -1
- package/lib/template-engine/system-variables-provider.js +105 -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 +91 -10
- package/package.json +4 -4
package/lib/frontend.js
CHANGED
|
@@ -19,6 +19,7 @@ class Frontend
|
|
|
19
19
|
this.appServerFactory = sc.get(props, 'appServerFactory', false);
|
|
20
20
|
this.dataServer = sc.get(props, 'dataServer', false);
|
|
21
21
|
this.renderEngine = sc.get(props, 'renderEngine', false);
|
|
22
|
+
this.events = sc.get(props, 'events', false);
|
|
22
23
|
this.projectRoot = sc.get(props, 'projectRoot', './');
|
|
23
24
|
this.templatesPath = FileHandler.joinPaths(this.projectRoot, 'templates');
|
|
24
25
|
this.publicPath = FileHandler.joinPaths(this.projectRoot, 'public');
|
|
@@ -79,7 +80,11 @@ class Frontend
|
|
|
79
80
|
renderEngine: this.renderEngine,
|
|
80
81
|
dataServer: this.dataServer,
|
|
81
82
|
getPartials: this.getPartialsForDomain.bind(this),
|
|
82
|
-
entitiesConfig: this.entitiesConfig
|
|
83
|
+
entitiesConfig: this.entitiesConfig,
|
|
84
|
+
events: this.events,
|
|
85
|
+
defaultDomain: this.defaultDomain,
|
|
86
|
+
projectRoot: this.projectRoot,
|
|
87
|
+
publicPath: this.publicPath
|
|
83
88
|
});
|
|
84
89
|
this.searchConfig.jsonFieldsParser = this.templateEngine.jsonFieldsParser;
|
|
85
90
|
await this.loadPartials();
|
|
@@ -345,7 +350,8 @@ class Frontend
|
|
|
345
350
|
query: req.query
|
|
346
351
|
}),
|
|
347
352
|
domain,
|
|
348
|
-
req
|
|
353
|
+
req,
|
|
354
|
+
null
|
|
349
355
|
);
|
|
350
356
|
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
351
357
|
await this.cacheManager.set(domain, cacheKey, content);
|
|
@@ -357,28 +363,73 @@ class Frontend
|
|
|
357
363
|
}
|
|
358
364
|
}
|
|
359
365
|
|
|
366
|
+
normalizePathForRouteSearch(path)
|
|
367
|
+
{
|
|
368
|
+
if(!path || '/' === path){
|
|
369
|
+
return '/';
|
|
370
|
+
}
|
|
371
|
+
return path.endsWith('/') ? path.slice(0, -1) : path;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async handleRouteRedirect(route, res)
|
|
375
|
+
{
|
|
376
|
+
let redirectUrl = sc.get(route, 'redirect_url', null);
|
|
377
|
+
if(!redirectUrl){
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
let redirectType = sc.get(route, 'redirect_type', '301');
|
|
381
|
+
let statusCode = '301' === redirectType ? 301 : 302;
|
|
382
|
+
return res.redirect(statusCode, redirectUrl);
|
|
383
|
+
}
|
|
384
|
+
|
|
360
385
|
async handleRequest(req, res)
|
|
361
386
|
{
|
|
362
387
|
try {
|
|
363
|
-
let
|
|
388
|
+
let originalPath = req.path;
|
|
364
389
|
let domain = this.getDomainFromRequest(req);
|
|
365
390
|
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
366
|
-
let cachedContent = await this.cacheManager.get(domain,
|
|
391
|
+
let cachedContent = await this.cacheManager.get(domain, originalPath);
|
|
367
392
|
if(cachedContent){
|
|
368
393
|
return res.send(cachedContent);
|
|
369
394
|
}
|
|
370
395
|
}
|
|
371
|
-
let route = await this.findRouteByPath(
|
|
396
|
+
let route = await this.findRouteByPath(originalPath, domain);
|
|
372
397
|
if(route){
|
|
373
|
-
|
|
398
|
+
let redirectResult = await this.handleRouteRedirect(route, res);
|
|
399
|
+
if(redirectResult){
|
|
400
|
+
return redirectResult;
|
|
401
|
+
}
|
|
402
|
+
let normalizedPath = this.normalizePathForRouteSearch(originalPath);
|
|
403
|
+
let routeFoundWithSlash = originalPath !== normalizedPath && route.path === normalizedPath + '/';
|
|
404
|
+
if(!originalPath.endsWith('/') && routeFoundWithSlash){
|
|
405
|
+
return res.redirect(301, originalPath + '/');
|
|
406
|
+
}
|
|
407
|
+
return await this.renderRouteWithCache(route, domain, res, originalPath, req);
|
|
408
|
+
}
|
|
409
|
+
let normalizedPath = this.normalizePathForRouteSearch(originalPath);
|
|
410
|
+
if(originalPath !== normalizedPath){
|
|
411
|
+
let alternativeRoute = await this.findRouteByPath(normalizedPath + '/', domain);
|
|
412
|
+
if(alternativeRoute){
|
|
413
|
+
let redirectResult = await this.handleRouteRedirect(alternativeRoute, res);
|
|
414
|
+
if(redirectResult){
|
|
415
|
+
return redirectResult;
|
|
416
|
+
}
|
|
417
|
+
if(!originalPath.endsWith('/')){
|
|
418
|
+
return res.redirect(301, originalPath + '/');
|
|
419
|
+
}
|
|
420
|
+
return await this.renderRouteWithCache(alternativeRoute, domain, res, originalPath, req);
|
|
421
|
+
}
|
|
374
422
|
}
|
|
375
|
-
|
|
423
|
+
if(!originalPath.endsWith('/') && '/' !== originalPath){
|
|
424
|
+
return res.redirect(301, originalPath + '/');
|
|
425
|
+
}
|
|
426
|
+
let entityResult = await this.findEntityByPath(originalPath);
|
|
376
427
|
if(entityResult){
|
|
377
|
-
return await this.renderEntityWithCache(entityResult, domain, res,
|
|
428
|
+
return await this.renderEntityWithCache(entityResult, domain, res, originalPath, req);
|
|
378
429
|
}
|
|
379
|
-
let templatePath = this.findTemplateByPath(
|
|
430
|
+
let templatePath = this.findTemplateByPath(originalPath, domain);
|
|
380
431
|
if(templatePath){
|
|
381
|
-
return await this.renderTemplateWithCache(templatePath, domain, res,
|
|
432
|
+
return await this.renderTemplateWithCache(templatePath, domain, res, originalPath, req);
|
|
382
433
|
}
|
|
383
434
|
return await this.renderNotFound(domain, res, req);
|
|
384
435
|
} catch (error) {
|
|
@@ -394,8 +445,9 @@ class Frontend
|
|
|
394
445
|
Logger.error('Routes entity not found in dataServer.');
|
|
395
446
|
return false;
|
|
396
447
|
}
|
|
448
|
+
let normalizedPath = this.normalizePathForRouteSearch(path);
|
|
397
449
|
let domainFilter = domain || null;
|
|
398
|
-
let routeFilters = {path, enabled: 1};
|
|
450
|
+
let routeFilters = {path: normalizedPath, enabled: 1};
|
|
399
451
|
let routes = await routesEntity.load(routeFilters);
|
|
400
452
|
let matchingRoute = false;
|
|
401
453
|
let nullDomain = false;
|
|
@@ -411,7 +463,25 @@ class Frontend
|
|
|
411
463
|
if(matchingRoute){
|
|
412
464
|
return matchingRoute;
|
|
413
465
|
}
|
|
414
|
-
|
|
466
|
+
if(nullDomain){
|
|
467
|
+
return nullDomain;
|
|
468
|
+
}
|
|
469
|
+
if(normalizedPath !== path){
|
|
470
|
+
let routeFiltersWithSlash = {path: path, enabled: 1};
|
|
471
|
+
let routesWithSlash = await routesEntity.load(routeFiltersWithSlash);
|
|
472
|
+
for(let route of routesWithSlash){
|
|
473
|
+
if(route.domain === domainFilter){
|
|
474
|
+
return route;
|
|
475
|
+
}
|
|
476
|
+
if(!route.domain){
|
|
477
|
+
nullDomain = route;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if(nullDomain){
|
|
481
|
+
return nullDomain;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return false;
|
|
415
485
|
}
|
|
416
486
|
|
|
417
487
|
async isEntityAccessible(entityName)
|
|
@@ -509,12 +579,12 @@ class Frontend
|
|
|
509
579
|
if(!content){
|
|
510
580
|
return false;
|
|
511
581
|
}
|
|
512
|
-
return await this.renderWithTemplateContent(content, Object.assign({}, route, content), domain, req);
|
|
582
|
+
return await this.renderWithTemplateContent(content, Object.assign({}, route, content), domain, req, route);
|
|
513
583
|
}
|
|
514
584
|
|
|
515
585
|
async generateEntityContent(entityResult, domain, req)
|
|
516
586
|
{
|
|
517
|
-
return await this.renderWithTemplateContent(entityResult.entity, entityResult.entity, domain, req);
|
|
587
|
+
return await this.renderWithTemplateContent(entityResult.entity, entityResult.entity, domain, req, null);
|
|
518
588
|
}
|
|
519
589
|
|
|
520
590
|
async generateTemplateContent(templatePath, domain, req)
|
|
@@ -524,7 +594,15 @@ class Frontend
|
|
|
524
594
|
Logger.error('Failed to read template: ' + templatePath);
|
|
525
595
|
return false;
|
|
526
596
|
}
|
|
527
|
-
return await this.templateEngine.render(
|
|
597
|
+
return await this.templateEngine.render(
|
|
598
|
+
template,
|
|
599
|
+
{},
|
|
600
|
+
this.getPartialsForDomain(domain),
|
|
601
|
+
domain,
|
|
602
|
+
req,
|
|
603
|
+
null,
|
|
604
|
+
null
|
|
605
|
+
);
|
|
528
606
|
}
|
|
529
607
|
|
|
530
608
|
async renderRoute(route, domain, res, req)
|
|
@@ -545,10 +623,10 @@ class Frontend
|
|
|
545
623
|
|
|
546
624
|
async renderWithTemplate(content, data, domain, res, req)
|
|
547
625
|
{
|
|
548
|
-
return res.send(await this.renderWithTemplateContent(content, data, domain, req));
|
|
626
|
+
return res.send(await this.renderWithTemplateContent(content, data, domain, req, null));
|
|
549
627
|
}
|
|
550
628
|
|
|
551
|
-
async renderWithTemplateContent(content, data, domain, req)
|
|
629
|
+
async renderWithTemplateContent(content, data, domain, req, route)
|
|
552
630
|
{
|
|
553
631
|
let templateName = sc.get(content, 'template', 'page');
|
|
554
632
|
if(!templateName){
|
|
@@ -558,7 +636,16 @@ class Frontend
|
|
|
558
636
|
if(!layoutName){
|
|
559
637
|
layoutName = 'default';
|
|
560
638
|
}
|
|
561
|
-
let
|
|
639
|
+
let currentEntityData = Object.assign({}, content, data);
|
|
640
|
+
let layoutContent = await this.processContentWithLayout(
|
|
641
|
+
content,
|
|
642
|
+
data,
|
|
643
|
+
layoutName,
|
|
644
|
+
domain,
|
|
645
|
+
req,
|
|
646
|
+
route,
|
|
647
|
+
currentEntityData
|
|
648
|
+
);
|
|
562
649
|
let templatePath = this.findTemplatePath(templateName, domain);
|
|
563
650
|
if(!templatePath){
|
|
564
651
|
return layoutContent;
|
|
@@ -569,10 +656,19 @@ class Frontend
|
|
|
569
656
|
}
|
|
570
657
|
return await this.templateEngine.render(
|
|
571
658
|
pageTemplate,
|
|
572
|
-
Object.assign(
|
|
659
|
+
Object.assign(
|
|
660
|
+
{},
|
|
661
|
+
this.fetchMetaFields(data),
|
|
662
|
+
{
|
|
663
|
+
content: layoutContent,
|
|
664
|
+
siteHandle: this.resolveDomainToSiteKey(domain)
|
|
665
|
+
}
|
|
666
|
+
),
|
|
573
667
|
this.getPartialsForDomain(domain),
|
|
574
668
|
domain,
|
|
575
|
-
req
|
|
669
|
+
req,
|
|
670
|
+
route,
|
|
671
|
+
currentEntityData
|
|
576
672
|
);
|
|
577
673
|
}
|
|
578
674
|
|
|
@@ -583,17 +679,25 @@ class Frontend
|
|
|
583
679
|
Logger.error('Failed to read template: ' + templatePath);
|
|
584
680
|
return false;
|
|
585
681
|
}
|
|
586
|
-
return await this.templateEngine.render(
|
|
682
|
+
return await this.templateEngine.render(
|
|
683
|
+
template,
|
|
684
|
+
data,
|
|
685
|
+
this.getPartialsForDomain(domain),
|
|
686
|
+
domain,
|
|
687
|
+
req,
|
|
688
|
+
null,
|
|
689
|
+
null
|
|
690
|
+
);
|
|
587
691
|
}
|
|
588
692
|
|
|
589
693
|
async renderWithLayout(content, data, layoutName, domain, res, req)
|
|
590
694
|
{
|
|
591
|
-
return res.send(await this.renderWithTemplateContent(content, data, domain, req));
|
|
695
|
+
return res.send(await this.renderWithTemplateContent(content, data, domain, req, null));
|
|
592
696
|
}
|
|
593
697
|
|
|
594
|
-
async processContentWithLayout(content, data, layoutName, domain, req)
|
|
698
|
+
async processContentWithLayout(content, data, layoutName, domain, req, route, currentEntityData)
|
|
595
699
|
{
|
|
596
|
-
let processedContent = await this.processContent(content, data, domain, req);
|
|
700
|
+
let processedContent = await this.processContent(content, data, domain, req, route, currentEntityData);
|
|
597
701
|
let layoutPath = this.findLayoutPath(layoutName, domain);
|
|
598
702
|
if(!layoutPath){
|
|
599
703
|
return processedContent;
|
|
@@ -607,17 +711,27 @@ class Frontend
|
|
|
607
711
|
Object.assign({}, data, {content: processedContent}),
|
|
608
712
|
this.getPartialsForDomain(domain),
|
|
609
713
|
domain,
|
|
610
|
-
req
|
|
714
|
+
req,
|
|
715
|
+
route,
|
|
716
|
+
currentEntityData
|
|
611
717
|
);
|
|
612
718
|
}
|
|
613
719
|
|
|
614
|
-
async processContent(content, data, domain, req)
|
|
720
|
+
async processContent(content, data, domain, req, route, currentEntityData)
|
|
615
721
|
{
|
|
616
722
|
let contentText = sc.get(content, 'content', '');
|
|
617
723
|
if(!contentText){
|
|
618
724
|
return '';
|
|
619
725
|
}
|
|
620
|
-
return await this.templateEngine.render(
|
|
726
|
+
return await this.templateEngine.render(
|
|
727
|
+
contentText,
|
|
728
|
+
data,
|
|
729
|
+
this.getPartialsForDomain(domain),
|
|
730
|
+
domain,
|
|
731
|
+
req,
|
|
732
|
+
route,
|
|
733
|
+
currentEntityData
|
|
734
|
+
);
|
|
621
735
|
}
|
|
622
736
|
|
|
623
737
|
async renderNotFound(domain, res, req)
|
package/lib/manager.js
CHANGED
|
@@ -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)
|
|
19
29
|
{
|
|
20
30
|
let processedTemplate = template;
|
|
21
31
|
for(let match of template.matchAll(this.getSingleFieldCollectionRegex())){
|
|
@@ -30,20 +40,27 @@ 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
|
|
36
49
|
)
|
|
37
50
|
);
|
|
38
51
|
}
|
|
39
52
|
return processedTemplate;
|
|
40
53
|
}
|
|
41
54
|
|
|
42
|
-
extractFieldValues(collectionData, fieldName)
|
|
55
|
+
async extractFieldValues(collectionData, fieldName, domain, req, systemVariables)
|
|
43
56
|
{
|
|
44
57
|
let fieldValues = '';
|
|
45
58
|
for(let row of collectionData){
|
|
46
|
-
|
|
59
|
+
let fieldValue = sc.get(row, fieldName, '');
|
|
60
|
+
if(fieldValue && this.processAllTemplateFunctions){
|
|
61
|
+
fieldValue = await this.processAllTemplateFunctions(fieldValue, domain, req, systemVariables);
|
|
62
|
+
}
|
|
63
|
+
fieldValues += fieldValue;
|
|
47
64
|
}
|
|
48
65
|
return fieldValues;
|
|
49
66
|
}
|
|
@@ -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)
|
|
35
36
|
{
|
|
36
37
|
let processedTemplate = template;
|
|
37
38
|
let matches = [...template.matchAll(this.getLoopCollectionStartRegex())];
|
|
@@ -62,7 +63,8 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
62
63
|
prevPages,
|
|
63
64
|
nextPages,
|
|
64
65
|
domain,
|
|
65
|
-
req
|
|
66
|
+
req,
|
|
67
|
+
systemVariables
|
|
66
68
|
);
|
|
67
69
|
if(loopResult){
|
|
68
70
|
processedTemplate = loopResult;
|
|
@@ -76,7 +78,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
76
78
|
filtersJson,
|
|
77
79
|
relationsString,
|
|
78
80
|
queryOptionsJson,
|
|
79
|
-
domain
|
|
81
|
+
domain,
|
|
82
|
+
req,
|
|
83
|
+
systemVariables
|
|
80
84
|
);
|
|
81
85
|
if(loopResult){
|
|
82
86
|
processedTemplate = loopResult;
|
|
@@ -92,7 +96,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
92
96
|
filtersJson,
|
|
93
97
|
relationsString,
|
|
94
98
|
queryOptionsJson,
|
|
95
|
-
domain
|
|
99
|
+
domain,
|
|
100
|
+
req,
|
|
101
|
+
systemVariables
|
|
96
102
|
){
|
|
97
103
|
return await this.processCollectionBase(
|
|
98
104
|
template,
|
|
@@ -102,7 +108,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
102
108
|
relationsString,
|
|
103
109
|
queryOptionsJson,
|
|
104
110
|
domain,
|
|
105
|
-
false
|
|
111
|
+
false,
|
|
112
|
+
req,
|
|
113
|
+
systemVariables
|
|
106
114
|
);
|
|
107
115
|
}
|
|
108
116
|
|
|
@@ -118,7 +126,8 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
118
126
|
prevPages,
|
|
119
127
|
nextPages,
|
|
120
128
|
domain,
|
|
121
|
-
req
|
|
129
|
+
req,
|
|
130
|
+
systemVariables
|
|
122
131
|
){
|
|
123
132
|
if(!req){
|
|
124
133
|
Logger.warning('No request provided for pagination, falling back to regular collection');
|
|
@@ -129,7 +138,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
129
138
|
filtersJson,
|
|
130
139
|
relationsString,
|
|
131
140
|
queryOptionsJson,
|
|
132
|
-
domain
|
|
141
|
+
domain,
|
|
142
|
+
req,
|
|
143
|
+
systemVariables
|
|
133
144
|
);
|
|
134
145
|
}
|
|
135
146
|
return await this.processCollectionBase(
|
|
@@ -146,7 +157,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
146
157
|
prevPages,
|
|
147
158
|
nextPages,
|
|
148
159
|
req
|
|
149
|
-
}
|
|
160
|
+
},
|
|
161
|
+
req,
|
|
162
|
+
systemVariables
|
|
150
163
|
);
|
|
151
164
|
}
|
|
152
165
|
|
|
@@ -158,7 +171,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
158
171
|
relationsString,
|
|
159
172
|
queryOptionsJson,
|
|
160
173
|
domain,
|
|
161
|
-
paginationOptions
|
|
174
|
+
paginationOptions,
|
|
175
|
+
req,
|
|
176
|
+
systemVariables
|
|
162
177
|
){
|
|
163
178
|
let startPos = startMatch.index;
|
|
164
179
|
let startEnd = startPos + startMatch[0].length;
|
|
@@ -211,7 +226,7 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
211
226
|
this.jsonFieldsParser.getJsonFieldsForEntity(tableName)
|
|
212
227
|
);
|
|
213
228
|
}
|
|
214
|
-
let collectionContent = await this.renderCollectionLoop(loopContent, collectionData, domain);
|
|
229
|
+
let collectionContent = await this.renderCollectionLoop(loopContent, collectionData, domain, req, systemVariables);
|
|
215
230
|
finalContent = this.renderEngine.render(
|
|
216
231
|
1 < paginationData.totalPages
|
|
217
232
|
? this.loadPaginationTemplate(paginationOptions.containerName, domain)
|
|
@@ -235,7 +250,7 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
235
250
|
queryOptionsJson,
|
|
236
251
|
relationsString
|
|
237
252
|
);
|
|
238
|
-
finalContent = await this.renderCollectionLoop(loopContent, collectionData, domain);
|
|
253
|
+
finalContent = await this.renderCollectionLoop(loopContent, collectionData, domain, req, systemVariables);
|
|
239
254
|
}
|
|
240
255
|
return template.substring(0, startPos) + finalContent + template.substring(endPos + endMatch[0].length);
|
|
241
256
|
}
|
|
@@ -281,14 +296,14 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
281
296
|
return '{{&collectionContentForCurrentPage}}';
|
|
282
297
|
}
|
|
283
298
|
|
|
284
|
-
async renderCollectionLoop(loopContent, collectionData, domain)
|
|
299
|
+
async renderCollectionLoop(loopContent, collectionData, domain, req, systemVariables)
|
|
285
300
|
{
|
|
286
301
|
if(!collectionData || 0 === collectionData.length){
|
|
287
302
|
return this.renderNoResultsMessage(domain);
|
|
288
303
|
}
|
|
289
304
|
let renderedContent = '';
|
|
290
305
|
for(let row of collectionData){
|
|
291
|
-
renderedContent += await this.processPartialsInLoop(loopContent, row, domain);
|
|
306
|
+
renderedContent += await this.processPartialsInLoop(loopContent, row, domain, req, systemVariables);
|
|
292
307
|
}
|
|
293
308
|
return renderedContent;
|
|
294
309
|
}
|
|
@@ -310,7 +325,7 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
310
325
|
return '';
|
|
311
326
|
}
|
|
312
327
|
|
|
313
|
-
async processPartialsInLoop(content, rowData, domain)
|
|
328
|
+
async processPartialsInLoop(content, rowData, domain, req, systemVariables)
|
|
314
329
|
{
|
|
315
330
|
let processedContent = content;
|
|
316
331
|
let partialTags = this.findAllPartialTags(content);
|
|
@@ -322,6 +337,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
322
337
|
processedContent = processedContent.substring(0, tag.start)+''+processedContent.substring(tag.end);
|
|
323
338
|
continue;
|
|
324
339
|
}
|
|
340
|
+
if(this.processAllTemplateFunctions){
|
|
341
|
+
partialContent = await this.processAllTemplateFunctions(partialContent, domain, req, systemVariables);
|
|
342
|
+
}
|
|
325
343
|
if(sc.hasOwn(tag.attributes, 'row')){
|
|
326
344
|
processedContent = processedContent.substring(0, tag.start)
|
|
327
345
|
+this.renderEngine.render(partialContent, {row: rowData}, this.getPartials(domain))
|
|
@@ -335,6 +353,9 @@ class CollectionsTransformer extends CollectionsTransformerBase
|
|
|
335
353
|
this.renderEngine.render(wrapperTemplate, renderData, partials) +
|
|
336
354
|
processedContent.substring(tag.end);
|
|
337
355
|
}
|
|
356
|
+
if(this.processAllTemplateFunctions){
|
|
357
|
+
processedContent = await this.processAllTemplateFunctions(processedContent, domain, req, systemVariables);
|
|
358
|
+
}
|
|
338
359
|
return this.renderEngine.render(processedContent, {row: rowData}, this.getPartials(domain));
|
|
339
360
|
}
|
|
340
361
|
|
|
@@ -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)
|
|
25
25
|
{
|
|
26
26
|
let processedTemplate = template;
|
|
27
27
|
for(let match of template.matchAll(this.getEntityRegex())){
|
|
@@ -36,7 +36,9 @@ 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
|
|
40
42
|
)
|
|
41
43
|
);
|
|
42
44
|
}
|
|
@@ -13,9 +13,10 @@ class PartialsTransformer
|
|
|
13
13
|
{
|
|
14
14
|
this.renderEngine = sc.get(props, 'renderEngine', false);
|
|
15
15
|
this.getPartials = sc.get(props, 'getPartials', false);
|
|
16
|
+
this.processAllTemplateFunctions = sc.get(props, 'processAllTemplateFunctions', false);
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
async transform(template, domain)
|
|
19
|
+
async transform(template, domain, req, systemVariables)
|
|
19
20
|
{
|
|
20
21
|
let processedTemplate = template;
|
|
21
22
|
let partialTags = this.findAllPartialTags(template);
|
|
@@ -27,6 +28,9 @@ class PartialsTransformer
|
|
|
27
28
|
processedTemplate = processedTemplate.substring(0, tag.start)+''+processedTemplate.substring(tag.end);
|
|
28
29
|
continue;
|
|
29
30
|
}
|
|
31
|
+
if(this.processAllTemplateFunctions){
|
|
32
|
+
partialContent = await this.processAllTemplateFunctions(partialContent, domain, req, systemVariables);
|
|
33
|
+
}
|
|
30
34
|
let wrapperTemplate = '{{#vars}}{{> ' + tag.name + '}}{{/vars}}';
|
|
31
35
|
let renderData = { vars: tag.attributes };
|
|
32
36
|
let partials = {[tag.name]: partialContent};
|