[MERGE] Branch 'master' of github_atticmedia:cjel/typo3-templates_aide

This commit is contained in:
Philipp Dieter 2021-11-15 22:40:26 +01:00
commit 4a4b809d13
12 changed files with 561 additions and 126 deletions

View File

@ -12,6 +12,8 @@ namespace Cjel\TemplatesAide\Controller;
* *
***/ ***/
use Cjel\TemplatesAide\Traits\ValidationTrait;
use Cjel\TemplatesAide\Traits\FormatResultTrait;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\CacheManager;
@ -21,10 +23,10 @@ use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Frontend\Plugin\AbstractPlugin;
use TYPO3\CMS\Frontend\Utility\EidUtility;
use TYPO3\CMS\Extbase\Reflection\ClassSchema; use TYPO3\CMS\Extbase\Reflection\ClassSchema;
use TYPO3\CMS\Extbase\Reflection\ReflectionService; use TYPO3\CMS\Extbase\Reflection\ReflectionService;
use TYPO3\CMS\Frontend\Plugin\AbstractPlugin;
use TYPO3\CMS\Frontend\Utility\EidUtility;
/** /**
* AbstractEIDController * AbstractEIDController
@ -32,6 +34,18 @@ use TYPO3\CMS\Extbase\Reflection\ReflectionService;
class AbstractEIDController class AbstractEIDController
{ {
/**
* ValidationTrait
*/
use ValidationTrait {
validateAgainstSchema as traitValidateAgainstSchema;
}
/**
* FormatResultTrait
*/
use FormatResultTrait;
/** /**
* @var BackendConfigurationManager * @var BackendConfigurationManager
*/ */
@ -99,11 +113,13 @@ class AbstractEIDController
$this->apiUtility = $this->objectManager->get( $this->apiUtility = $this->objectManager->get(
\Cjel\TemplatesAide\Utility\ApiUtility::class \Cjel\TemplatesAide\Utility\ApiUtility::class
); );
$this->configurationManager->setConfiguration(array());
$frameworkConfiguration = $this->configurationManager->getConfiguration( $frameworkConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
$this->getExtensionKey() $this->getExtensionKey()
); );
$this->configurationManager->setConfiguration(
$frameworkConfiguration
);
$this->settings = $frameworkConfiguration; $this->settings = $frameworkConfiguration;
$this->storagePids = explode( $this->storagePids = explode(
',', ',',
@ -241,4 +257,35 @@ class AbstractEIDController
} }
} }
/**
* return function
*
* @param array $result
* @return void
*/
protected function returnFunction(
$result = []
) {
$result = $this->formatResult($result, 'asd');
unset($result['cid']);
unset($result['componentMode']);
unset($result['isValid']);
if ($result) {
if (!empty($this->errors)) {
return $result;
} else {
return [
'metadata' => [
'total' => count($result),
'count' => count($result),
],
'result' => $result,
];
}
} else {
return [];
}
//return $result;
}
} }

View File

@ -3,7 +3,7 @@ namespace Cjel\TemplatesAide\Controller;
/*** /***
* *
* This file is part of the "Templates Aide" Extension for TYPO3 CMS. / This file is part of the "Templates Aide" Extension for TYPO3 CMS.
* *
* For the full copyright and license information, please read the * For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code. * LICENSE.txt file that was distributed with this source code.
@ -24,6 +24,7 @@ use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use TYPO3\CMS\Extbase\Property\PropertyMapper; use TYPO3\CMS\Extbase\Property\PropertyMapper;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationBuilder; use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationBuilder;
use TYPO3\CMS\Extbase\Service\EnvironmentService;
use TYPO3\CMS\Extbase\Service\ExtensionService; use TYPO3\CMS\Extbase\Service\ExtensionService;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility; use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
@ -148,6 +149,22 @@ class ActionController extends BaseController
$this->extensionService = $extensionService; $this->extensionService = $extensionService;
} }
/**
* environmentService
*
* @var EnvironmentService
*/
protected $environmentService;
/**
* @param
*/
public function injectEnvironmentService(
EnvironmentService $environmentService
) {
$this->environmentService = $environmentService;
}
/** /**
* propertyMapper * propertyMapper
* *
@ -204,9 +221,11 @@ class ActionController extends BaseController
*/ */
public function initializeAction() public function initializeAction()
{ {
if ($GLOBALS['TSFE']->config['config']) {
$this->config = GeneralUtility::removeDotsFromTS( $this->config = GeneralUtility::removeDotsFromTS(
$GLOBALS['TSFE']->config['config'] $GLOBALS['TSFE']->config['config']
); );
}
$this->pageType = GeneralUtility::_GP('type'); $this->pageType = GeneralUtility::_GP('type');
if (!is_numeric($this->pageType)) { if (!is_numeric($this->pageType)) {
$this->pageType = 0; $this->pageType = 0;
@ -251,7 +270,7 @@ class ActionController extends BaseController
} }
/** /**
* returns an instance of uribuilder *
*/ */
public function persistAll() public function persistAll()
{ {
@ -396,31 +415,6 @@ class ActionController extends BaseController
return false; return false;
} }
/**
* shortcut to get translation
*
* @return void
*/
protected function getTranslation($key, $arguments = null)
{
$translation = LocalizationUtility::translate(
$key,
$this->getExtensionKey(),
$arguments
);
if ($translation) {
return $translation;
}
$translation = LocalizationUtility::translate(
$key,
'site_templates',
$arguments
);
if ($translation) {
return $translation;
}
return null;
}
/** /**
* *
@ -435,41 +429,6 @@ class ActionController extends BaseController
strtolower($reflection->getShortName()); strtolower($reflection->getShortName());
} }
/**
* gets error label based on field and keyword, uses predefined extensionkey
*/
protected function getErrorLabel($field, $keyword) {
$path = 'error.' . $field . '.' . $keyword;
$errorLabel = $this->getTranslation($path);
if ($errorLabel == null) {
return $path;
}
return $errorLabel;
}
/**
* function to add validation error manually in the controller
*/
protected function addValidationError(
$field, $keyword, $overwrite = false
) {
$this->isValid = false;
$this->responseStatus = [400 => 'validationError'];
if (!array_key_exists($field, $this->errors)
|| $overwrite == true
) {
$this->errors[$field] = [
'keyword' => $keyword,
];
$this->errorLabels[$field] = $this->getErrorLabel(
$field,
$keyword
);
}
}
/** /**
* legacy function to prevent beaking old code * legacy function to prevent beaking old code
* *
@ -594,7 +553,10 @@ class ActionController extends BaseController
->setCreateAbsoluteUri(true) ->setCreateAbsoluteUri(true)
->setAddQueryString(true) ->setAddQueryString(true)
->setTargetPageType($this->ajaxPageType) ->setTargetPageType($this->ajaxPageType)
->setArguments(['cid' => $this->contentObjectUid]) ->setArguments([
'cid' => $this->contentObjectUid,
'type' => $this->ajaxPageType,
])
->uriFor($this->request->getControllerActionName()); ->uriFor($this->request->getControllerActionName());
$this->ajaxEnv = [ $this->ajaxEnv = [
'uri' => $uri, 'uri' => $uri,
@ -742,8 +704,12 @@ class ActionController extends BaseController
$this->response->setStatus($this->responseStatus); $this->response->setStatus($this->responseStatus);
} }
if ($this->pageType == $this->ajaxPageType) { if ($this->pageType == $this->ajaxPageType) {
if ($this->environmentService->isEnvironmentInBackendMode()) {
header('Content-Type: application/json');
} else {
$GLOBALS['TSFE']->setContentType('application/json'); $GLOBALS['TSFE']->setContentType('application/json');
} }
}
unset($result['data']); unset($result['data']);
if ($this->redirect) { if ($this->redirect) {
$result['redirect'] = $this->redirect; $result['redirect'] = $this->redirect;
@ -767,5 +733,4 @@ class ActionController extends BaseController
} }
$this->view->assignMultiple($result); $this->view->assignMultiple($result);
} }
} }

View File

@ -19,18 +19,12 @@ use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Reflection\ClassSchema; use TYPO3\CMS\Extbase\Reflection\ClassSchema;
use TYPO3\CMS\Extbase\Reflection\ReflectionService; use TYPO3\CMS\Extbase\Reflection\ReflectionService;
use TYPO3\CMS\Frontend\Utility\EidUtility;
/** /**
* ValidationTrait * ValidationTrait
*/ */
trait DependencyInjectionTrait trait DependencyInjectionTrait
{ {
/*
* extension Key
*/
protected $extensionKey = null;
/* /*
* storagePids * storagePids
*/ */
@ -86,21 +80,19 @@ trait DependencyInjectionTrait
$this->objectManager = GeneralUtility::makeInstance( $this->objectManager = GeneralUtility::makeInstance(
ObjectManager::class ObjectManager::class
); );
$this->initFrontendController();
$this->configurationManager = $this->objectManager->get( $this->configurationManager = $this->objectManager->get(
ConfigurationManagerInterface::class ConfigurationManagerInterface::class
); );
$this->configurationManager->setConfiguration(
array()
);
$this->apiUtility = $this->objectManager->get( $this->apiUtility = $this->objectManager->get(
ApiUtility::class ApiUtility::class
); );
$frameworkConfiguration = $this->configurationManager->getConfiguration( $frameworkConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
$this->getExtensionKey() str_replace('_', '', $this->getExtensionKey())
);
$this->configurationManager->setConfiguration(
$frameworkConfiguration
); );
$this->configurationManager->setConfiguration($frameworkConfiguration);
$this->settings = $frameworkConfiguration; $this->settings = $frameworkConfiguration;
$this->storagePids = explode( $this->storagePids = explode(
',', ',',
@ -126,29 +118,4 @@ trait DependencyInjectionTrait
} }
} }
/**
* Initialize frontentController
*
* @return void
*/
private function initFrontendController()
{
$currentDomain = strtok(GeneralUtility::getIndpEnv('HTTP_HOST'), ':');
$frontendController = GeneralUtility::makeInstance(
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::class,
$GLOBALS['TYPO3_CONF_VARS'],
null,
0,
true
);
$GLOBALS['TSFE'] = $frontendController;
$frontendController->connectToDB();
$frontendController->fe_user = EidUtility::initFeUser();
$frontendController->id = $result[0]['pid'];
$frontendController->determineId();
$frontendController->initTemplate();
$frontendController->getConfigArray();
EidUtility::initTCA();
}
} }

View File

@ -0,0 +1,84 @@
<?php
namespace Cjel\TemplatesAide\Traits;
/***
*
* This file is part of the "Templates Aide" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2021 Philipp Dieter <philippdieter@attic-media.net>
*
***/
/**
* ValidationTrait
*/
trait FormatResultTrait
{
/**
*
*/
public function formatResult($result) {
if ($result == null) {
$result = [];
}
if (!empty($this->errors)) {
$result = array_merge(
$result,
['errors' => $this->errors]
);
}
if (!empty($this->errorLabels)) {
$result = array_merge(
$result,
['errorLabels' => $this->errorLabels]
);
}
if (is_array($this->responseStatus)) {
$result = array_merge(
$result,
['errorType' => reset($this->responseStatus)]
);
}
if ($this->pageType) {
if (is_array($this->responseStatus)) {
$this->response->setStatus(
array_key_first($this->responseStatus)
);
} else {
$this->response->setStatus($this->responseStatus);
}
if ($this->pageType == $this->ajaxPageType) {
if ($this->environmentService->isEnvironmentInBackendMode()) {
header('Content-Type: application/json');
} else {
$GLOBALS['TSFE']->setContentType('application/json');
}
}
unset($result['data']);
if ($this->redirect) {
$result['redirect'] = $this->redirect;
}
if ($this->reload) {
$result['reload'] = true;
}
return json_encode($result);
}
$result = array_merge(
$result,
['cid' => $this->contentObjectUid],
['isValid' => $this->isValid],
['componentMode' => $this->componentMode]
);
if (!empty($this->ajaxEnv)) {
$result = array_merge(
$result,
['ajaxEnv' => $this->ajaxEnv]
);
}
return $result;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Cjel\TemplatesAide\Traits;
/***
*
* This file is part of the "Templates Aide" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* (c) 2021 Philipp Dieter <philippdieter@attic-media.net>
*
***/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
/**
* ValidationTrait
*/
trait PersistenceManagerTrait
{
/**
*
*/
public function persistAll()
{
(GeneralUtility::makeInstance(
ObjectManager::class
)->get(
PersistenceManager::class
))->persistAll();
}
}

View File

@ -16,6 +16,7 @@ use \Opis\JsonSchema\{
Validator, ValidationResult, ValidationError, Schema Validator, ValidationResult, ValidationError, Schema
}; };
use Cjel\TemplatesAide\Utility\ArrayUtility; use Cjel\TemplatesAide\Utility\ArrayUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/** /**
* ValidationTrait * ValidationTrait
@ -96,4 +97,64 @@ trait ValidationTrait
return $validationResult; return $validationResult;
} }
/**
* function to add validation error manually in the controller
*/
protected function addValidationError(
$field, $keyword, $overwrite = false
) {
$this->isValid = false;
$this->responseStatus = [400 => 'validationError'];
if (!array_key_exists($field, $this->errors)
|| $overwrite == true
) {
$this->errors[$field] = [
'keyword' => $keyword,
];
$this->errorLabels[$field] = $this->getErrorLabel(
$field,
$keyword
);
}
}
/**
* gets error label based on field and keyword, uses predefined extensionkey
*/
protected function getErrorLabel($field, $keyword) {
$path = 'error.' . $field . '.' . $keyword;
$errorLabel = $this->getTranslation($path);
if ($errorLabel == null) {
return $path;
}
return $errorLabel;
}
/**
* shortcut to get translation
*
* @return void
*/
protected function getTranslation($key, $arguments = null)
{
$translation = LocalizationUtility::translate(
$key,
$this->getExtensionKey(),
$arguments
);
if ($translation) {
return $translation;
}
$translation = LocalizationUtility::translate(
$key,
'site_templates',
$arguments
);
if ($translation) {
return $translation;
}
return null;
}
} }

View File

@ -213,7 +213,13 @@ class ApiUtility
return $result; return $result;
} }
private function filereferenceToApi($object) { public function filereferenceToApi($object) {
$this->objectManager = GeneralUtility::makeInstance(
ObjectManager::class
);
$this->imageService = $this->objectManager->get(
imageService::class
);
$httpHost = GeneralUtility::getIndpEnv('HTTP_HOST'); $httpHost = GeneralUtility::getIndpEnv('HTTP_HOST');
$requestHost = GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST'); $requestHost = GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST');
$publicUrl = $object->getPublicUrl(); $publicUrl = $object->getPublicUrl();

View File

@ -36,9 +36,10 @@ class MailUtility
*/ */
public static function parseContentTemplate( public static function parseContentTemplate(
$text, $text,
$markers = [] $markers = [],
$lineEnd = "\r\n"
) { ) {
$textParts = explode("\r\n\r\n", $text); $textParts = explode($lineEnd . $lineEnd, $text);
$result = []; $result = [];
foreach ($textParts as $textPart) { foreach ($textParts as $textPart) {
$type = 'text'; $type = 'text';
@ -54,6 +55,22 @@ class MailUtility
$type = 'headline3'; $type = 'headline3';
$textPart = substr($textPart, 4); $textPart = substr($textPart, 4);
} }
if (substr($textPart, 0, 2) === '- ') {
$type = 'list';
$textPart = substr($textPart, 2);
}
if (substr($textPart, 0, 2) === '| ') {
$type = 'table';
$textPart = substr($textPart, 2);
}
if (substr($textPart, 0, 3) === '|| ') {
$type = 'tableLayout';
$textPart = substr($textPart, 3);
}
if (substr($textPart, 0, 9) === '%subject ') {
$type = 'subject';
$textPart = substr($textPart, 9);
}
foreach ($markers as $markerName => $markerContent) { foreach ($markers as $markerName => $markerContent) {
$textPart = str_replace( $textPart = str_replace(
'###' . $markerName . '###', '###' . $markerName . '###',
@ -61,10 +78,40 @@ class MailUtility
$textPart $textPart
); );
} }
switch($type) {
case 'table':
case 'tableLayout':
if (
$result[count($result) - 1]['type'] == $type
&& count($result[count($result) - 1]['data']) == 1
) {
$result[count($result) - 1]['data'][] = $textPart;
} else {
$result[] = [
'type' => $type,
'data' => [$textPart],
];
}
break;
case 'list':
if (
$result[count($result) - 1]['type'] == 'list'
) {
$result[count($result) - 1]['data'][] = $textPart;
} else {
$result[] = [
'type' => 'list',
'data' => [$textPart],
];
}
break;
default:
$result[] = [ $result[] = [
'type' => $type, 'type' => $type,
'data' => $textPart, 'data' => $textPart,
]; ];
break;
}
} }
return $result; return $result;
} }
@ -107,12 +154,22 @@ class MailUtility
$htmlView->setTemplate($templateNameHtml); $htmlView->setTemplate($templateNameHtml);
$textView = $objectManager->get(StandaloneView::class); $textView = $objectManager->get(StandaloneView::class);
if ($templatePaths) { if ($templatePaths) {
$partialRootPaths = $htmlView->getPartialRootPaths();
$partialRootPaths[] = GeneralUtility::getFileAbsFileName(
'EXT:templates_aide/Resources/Private/Partials/'
);
$htmlView->setTemplateRootPaths( $htmlView->setTemplateRootPaths(
$templatePaths->getTemplateRootPaths() $templatePaths->getTemplateRootPaths()
); );
$htmlView->setPartialRootPaths(
$partialRootPaths
);
$textView->setTemplateRootPaths( $textView->setTemplateRootPaths(
$templatePaths->getTemplateRootPaths() $templatePaths->getTemplateRootPaths()
); );
$textView->setPartialRootPaths(
$partialRootPaths
);
} else { } else {
$htmlView->getTemplatePaths()->fillDefaultsByPackageName( $htmlView->getTemplatePaths()->fillDefaultsByPackageName(
'templates_aide' 'templates_aide'
@ -130,6 +187,9 @@ class MailUtility
foreach ($data as $row) { foreach ($data as $row) {
switch($row['type']) { switch($row['type']) {
case 'text': case 'text':
case 'table':
case 'tableLayout':
case 'list':
case 'textbold': case 'textbold':
case 'headline': case 'headline':
case 'headline2': case 'headline2':
@ -220,6 +280,13 @@ class MailUtility
$bodydataText[] = $textRow; $bodydataText[] = $textRow;
$bodydataHtml[] = $htmlRow; $bodydataHtml[] = $htmlRow;
break; break;
case 'attachment':
$mail->attach(new \Swift_Attachment(
$row['data'][0],
$row['data'][1],
$row['data'][2]
));
break;
case 'attachmentBase64': case 'attachmentBase64':
$attachmentdata = explode(',', $row['data']); $attachmentdata = explode(',', $row['data']);
preg_match('/\w*:(.*);\w*/', $attachmentdata[0], $matches); preg_match('/\w*:(.*);\w*/', $attachmentdata[0], $matches);

View File

@ -27,8 +27,10 @@ class SiteConfigUtility
* @var string $path * @var string $path
* @return string * @return string
*/ */
public static function getByPath($path) public static function getByPath(
{ $path,
$limitToSiteConfig = true
) {
$pathParts = explode('.', $path); $pathParts = explode('.', $path);
$objectManager = GeneralUtility::makeInstance( $objectManager = GeneralUtility::makeInstance(
ObjectManager::class ObjectManager::class
@ -40,7 +42,10 @@ class SiteConfigUtility
ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT
); );
$typoscript = GeneralUtility::removeDotsFromTS($typoscript); $typoscript = GeneralUtility::removeDotsFromTS($typoscript);
$siteConfig = $typoscript;
if ($limitToSiteConfig) {
$siteConfig = $typoscript['config']['site']; $siteConfig = $typoscript['config']['site'];
}
$current = &$siteConfig; $current = &$siteConfig;
foreach ($pathParts as $key) { foreach ($pathParts as $key) {
$current = &$current[$key]; $current = &$current[$key];

View File

@ -1 +1,5 @@
<INCLUDE_TYPOSCRIPT: source="FILE:EXT:templates_aide/Resources/Private/PageTSConfig/lib/layout.tsconfig"> <INCLUDE_TYPOSCRIPT: source="FILE:EXT:templates_aide/Resources/Private/PageTSConfig/lib/layout.tsconfig">
[applicationContext = Development]
TCAdefaults.pages.hidden = 0
[end]

View File

@ -1,23 +1,34 @@
<f:if condition="{width}">
<f:else>
<f:variable name="width" value="640" />
</f:else>
</f:if>
<f:if condition="{padding}">
<f:else>
<f:variable name="padding" value="20" />
</f:else>
</f:if>
<f:variable name="widthPadded" value="{width - padding - padding}" />
<f:variable name="widthTableColumn" value="{widthPadded / 2}" />
<f:for each="{content}" as="row" key="rowKey" iteration="rowI" > <f:for each="{content}" as="row" key="rowKey" iteration="rowI" >
<v:condition.type.isArray value="{row.data}"> <v:condition.type.isArray value="{row.data}">
<f:then>
</f:then>
<f:else> <f:else>
<f:if condition="{v:condition.string.contains(haystack: '{row.type}', needle: 'headline', then: '1')} || {row.type} == 'text'"> <f:if condition="{v:condition.string.contains(haystack: '{row.type}', needle: 'headline', then: '1')} || {row.type} == 'text'">
<!--[if mso | IE]> <!--[if mso | IE]>
<table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:640px;" width="640" > <table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:{width}px;" width="{width}" >
<tr> <tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"> <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]--> <![endif]-->
<div style="background:#ffffff;background-color:#ffffff;margin:0px auto;max-width:640px;"> <div style="background:#ffffff;background-color:#ffffff;margin:0px auto;max-width:{width}px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;"> <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody> <tbody>
<tr> <tr>
<td style="direction:ltr;font-size:0px;padding:0 20px;text-align:center;"> <td style="direction:ltr;font-size:0px;padding:0 {padding}px;text-align:center;">
<!--[if mso | IE]> <!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"> <table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr> <tr>
<td class="" style="vertical-align:top;width:600px;" > <td class="" style="vertical-align:top;width:{widthPadded};" >
<![endif]--> <![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;"> <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
@ -68,5 +79,136 @@
<![endif]--> <![endif]-->
</f:if> </f:if>
</f:else> </f:else>
<f:then>
<f:comment>Data is array, can be table or list</f:comment>
<f:switch expression="{row.type}">
<f:case value="table">
<f:variable name="type" value="table" />
</f:case>
<f:case value="tableLayout">
<f:variable name="type" value="table" />
</f:case>
<f:defaultCase>
<f:variable name="type" value="list" />
</f:defaultCase>
</f:switch>
<f:switch expression="{type}">
<f:case value="table">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:{width}px;" width="{width}"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#ffffff;background-color:#ffffff;Margin:0px auto;max-width:{width}px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:2px {padding}px;text-align:center;vertical-align:top;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="" style="vertical-align:top;width:{widthColumn}px;" >
<![endif]-->
<div class="mj-column-per-50 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="left" style="font-size:0px;padding:0px 4px;word-break:break-word;">
<div style="font-family:Arial, sans-serif;font-size:16px;line-height:1.4;text-align:left;color:#000000;">
<div>{row.data.0 -> f:format.nl2br() -> f:format.raw()}</div>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td class="" style="vertical-align:top;width:{widthTableColumn}px;">
<![endif]-->
<div class="mj-column-per-50 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="left" style="font-size:0px;padding:0px 4px;word-break:break-word;">
<div style="font-family:Arial, sans-serif;font-size:16px;line-height:1.4;text-align:left;color:#000000;">
<div>{row.data.1 -> f:format.nl2br() -> f:format.raw()}</div>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</f:case>
<f:case value="list">
<!--[if mso | IE]>
<table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:{width}px;" width="{width}" >
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#ffffff;background-color:#ffffff;margin:0px auto;max-width:{width}px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0 {padding}px;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="" style="vertical-align:top;width:{widthPadded};" >
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
<tbody>
<tr>
<td style="vertical-align:top;padding:0;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
<tr>
<td align="left" style="font-size:0px;padding:0;word-break:break-word;">
<div style="font-family:Arial, sans-serif;font-size:16px;line-height:1.4;text-align:left;color:#000000;">
<ul style="padding-left: 14px;">
<f:for each="{row.data}" as="dataRow" key="dataRowKey" iteration="dataRowI">
<li>{dataRow -> f:format.nl2br() -> f:format.raw()}</li>
</f:for>
</ul>
</div>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</f:case>
</f:switch>
</f:then>
</v:condition.type.isArray> </v:condition.type.isArray>
</f:for> </f:for>

View File

@ -0,0 +1,50 @@
<v:variable.set name="br">
</v:variable.set>
<f:for
each="{content}"
as="row"
key="rowKey"
iteration="rowI"
><f:spaceless>
<v:condition.type.isArray value="{row.data}">
<f:else>
<f:switch expression="{row.type}">
<f:case value="headline">
# {row.data -> f:format.nl2br() -> f:format.raw()}
<f:spaceless></f:spaceless>
</f:case>
<f:case value="headline2">
## {row.data -> f:format.nl2br() -> f:format.raw()}
</f:case>
<f:case value="headline3">
### {row.data -> f:format.nl2br() -> f:format.raw()}
</f:case>
<f:defaultCase>
<f:spaceless><v:format.wordWrap limit="76" glue="{br}">
{row.data -> f:format.raw()}
</v:format.wordWrap>
</f:spaceless>{br}{br}
</f:defaultCase>
</f:switch>
</f:else>
<f:then>
<f:switch expression="{row.type}">
<f:case value="tableLayout">
{row.data.0 -> f:format.raw()}{br}{br}{row.data.1 -> f:format.raw()}{br}
</f:case>
<f:case value="table">
{row.data.0 -> f:format.raw()}: {row.data.1 -> f:format.raw()}
</f:case>
<f:case value="list">
<f:for each="{row.data}" as="dataRow" key="dataRowKey" iteration="dataRowI">- <f:spaceless><v:format.wordWrap limit="76" glue="{br} " >
{dataRow -> f:format.raw()}
</v:format.wordWrap>
</f:spaceless>{br}{br}</f:for>
</f:case>
<f:defaultCase>
</f:defaultCase>
</f:switch>
</f:then>
</v:condition.type.isArray>
</f:spaceless><f:if condition="{row.type} == 'table'"><f:then>{br}<f:if condition="{content.{rowI.cycle}.type} == 'table'"><f:else>{br}</f:else></f:if></f:then><f:else><f:if condition="{content.{rowI.cycle}}"><f:then>{br}{br}</f:then></f:if></f:else></f:if></f:for>