[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\ServerRequestInterface;
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\Extbase\Configuration\ConfigurationManagerInterface;
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\ReflectionService;
use TYPO3\CMS\Frontend\Plugin\AbstractPlugin;
use TYPO3\CMS\Frontend\Utility\EidUtility;
/**
* AbstractEIDController
@ -32,6 +34,18 @@ use TYPO3\CMS\Extbase\Reflection\ReflectionService;
class AbstractEIDController
{
/**
* ValidationTrait
*/
use ValidationTrait {
validateAgainstSchema as traitValidateAgainstSchema;
}
/**
* FormatResultTrait
*/
use FormatResultTrait;
/**
* @var BackendConfigurationManager
*/
@ -99,11 +113,13 @@ class AbstractEIDController
$this->apiUtility = $this->objectManager->get(
\Cjel\TemplatesAide\Utility\ApiUtility::class
);
$this->configurationManager->setConfiguration(array());
$frameworkConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
$this->getExtensionKey()
);
$this->configurationManager->setConfiguration(
$frameworkConfiguration
);
$this->settings = $frameworkConfiguration;
$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
* 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\Property\PropertyMapper;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationBuilder;
use TYPO3\CMS\Extbase\Service\EnvironmentService;
use TYPO3\CMS\Extbase\Service\ExtensionService;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
@ -148,6 +149,22 @@ class ActionController extends BaseController
$this->extensionService = $extensionService;
}
/**
* environmentService
*
* @var EnvironmentService
*/
protected $environmentService;
/**
* @param
*/
public function injectEnvironmentService(
EnvironmentService $environmentService
) {
$this->environmentService = $environmentService;
}
/**
* propertyMapper
*
@ -204,9 +221,11 @@ class ActionController extends BaseController
*/
public function initializeAction()
{
if ($GLOBALS['TSFE']->config['config']) {
$this->config = GeneralUtility::removeDotsFromTS(
$GLOBALS['TSFE']->config['config']
);
}
$this->pageType = GeneralUtility::_GP('type');
if (!is_numeric($this->pageType)) {
$this->pageType = 0;
@ -251,7 +270,7 @@ class ActionController extends BaseController
}
/**
* returns an instance of uribuilder
*
*/
public function persistAll()
{
@ -396,31 +415,6 @@ class ActionController extends BaseController
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());
}
/**
* 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
*
@ -594,7 +553,10 @@ class ActionController extends BaseController
->setCreateAbsoluteUri(true)
->setAddQueryString(true)
->setTargetPageType($this->ajaxPageType)
->setArguments(['cid' => $this->contentObjectUid])
->setArguments([
'cid' => $this->contentObjectUid,
'type' => $this->ajaxPageType,
])
->uriFor($this->request->getControllerActionName());
$this->ajaxEnv = [
'uri' => $uri,
@ -742,8 +704,12 @@ class ActionController extends BaseController
$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;
@ -767,5 +733,4 @@ class ActionController extends BaseController
}
$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\Reflection\ClassSchema;
use TYPO3\CMS\Extbase\Reflection\ReflectionService;
use TYPO3\CMS\Frontend\Utility\EidUtility;
/**
* ValidationTrait
*/
trait DependencyInjectionTrait
{
/*
* extension Key
*/
protected $extensionKey = null;
/*
* storagePids
*/
@ -86,21 +80,19 @@ trait DependencyInjectionTrait
$this->objectManager = GeneralUtility::makeInstance(
ObjectManager::class
);
$this->initFrontendController();
$this->configurationManager = $this->objectManager->get(
ConfigurationManagerInterface::class
);
$this->configurationManager->setConfiguration(
array()
);
$this->apiUtility = $this->objectManager->get(
ApiUtility::class
);
$frameworkConfiguration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
$this->getExtensionKey()
str_replace('_', '', $this->getExtensionKey())
);
$this->configurationManager->setConfiguration(
$frameworkConfiguration
);
$this->configurationManager->setConfiguration($frameworkConfiguration);
$this->settings = $frameworkConfiguration;
$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
};
use Cjel\TemplatesAide\Utility\ArrayUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* ValidationTrait
@ -96,4 +97,64 @@ trait ValidationTrait
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;
}
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');
$requestHost = GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST');
$publicUrl = $object->getPublicUrl();

View File

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

View File

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

View File

@ -1 +1,5 @@
<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" >
<v:condition.type.isArray value="{row.data}">
<f:then>
</f:then>
<f:else>
<f:if condition="{v:condition.string.contains(haystack: '{row.type}', needle: 'headline', then: '1')} || {row.type} == 'text'">
<!--[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>
<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: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%;">
<tbody>
<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]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="" style="vertical-align:top;width:600px;" >
<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%">
@ -68,5 +79,136 @@
<![endif]-->
</f:if>
</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>
</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>