diff --git a/Classes/Controller/LayoutController.php b/Classes/Controller/LayoutController.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a580475d16c59d435d6622618f0c3c3757c1683
--- /dev/null
+++ b/Classes/Controller/LayoutController.php
@@ -0,0 +1,196 @@
+layoutRepository = $layoutRepository;
+ }
+
+ /**
+ * @var PhpSession
+ */
+ protected $session;
+
+ /**
+ * Command array on the form [tablename][uid][command] = value.
+ * This array may get additional data set internally based on clipboard commands send in clipboardCommandArray var!
+ *
+ * @var array
+ */
+ protected $command;
+
+ /**
+ * Clipboard command array. May trigger changes in "command"
+ *
+ * @var array
+ */
+ protected $clipboardCommandArray;
+
+ /**
+ * @var Clipboard
+ */
+ protected $clipObj;
+
+ /**
+ * Initializes the Action calls
+ *
+ * @return void
+ */
+ public function initializeAction() {
+ $this->command = GeneralUtility::_GP('cmd');
+ $this->clipboardCommandArray = GeneralUtility::_GP('CB');
+ }
+
+ /**
+ * @param ViewInterface $view
+ */
+ public function initializeView(ViewInterface $view) {
+ parent::initializeView($view);
+ $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
+ $pageRenderer->addJsInlineCode(
+ 'typo3_version', 'TYPO3.version='
+ . VersionNumberUtility::convertVersionNumberToInteger(VersionNumberUtility::getCurrentTypo3Version())
+ . ';'
+ );
+ if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9.0.0', '<')) {
+ $pageRenderer->loadExtJS();
+ }
+ $this->initClipboard();
+ $view->assign('controller', 'Layout');
+ }
+
+ /**
+ * @throws NoSuchArgumentException
+ */
+ public function indexAction() {
+ $pageUid = (int) GeneralUtility::_GP('id');
+
+ if (!($this->session instanceof PhpSession)) {
+ $this->session = $this->objectManager->get(PhpSession::class);
+ $this->session->setSessionKey('sg_mail_controller_session');
+ } else {
+ $this->session->setSessionKey('sg_mail_controller_session');
+ }
+
+ if ($this->request->hasArgument('controller')) {
+ $this->session->setDataByKey('mode', $this->request->getArgument('controller'));
+ }
+
+ // create doc header component
+ $pageInfo = BackendUtility::readPageAccess($pageUid, $GLOBALS['BE_USER']->getPagePermsClause(1));
+ if ($pageInfo && (int) $pageInfo['is_siteroot'] === 1) {
+ $layouts = $this->layoutRepository->findByPidForModule($pageUid);
+ $this->view->assign('layouts', $layouts);
+ $pasteData = $this->clipObj->elFromTable('tx_sgmail_domain_model_layout');
+ if (\count($pasteData)) {
+ $pasteButton = [
+ 'message' => $this->clipObj->confirmMsgText('pages', $pageInfo, 'into', $pasteData),
+ 'url' => $this->clipObj->pasteUrl('', $pageUid)
+ ];
+ $this->view->assign('pasteButton', $pasteButton);
+ }
+ } else {
+ $this->view->assign('pages', BackendService::getPages());
+ }
+ $this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class);
+ if ($pageInfo === FALSE) {
+ $pageInfo = ['uid' => $pageUid];
+ }
+ $this->docHeaderComponent->setMetaInformation($pageInfo);
+ BackendService::makeButtons($this->docHeaderComponent, $this->request);
+ $this->view->assign('pageUid', $pageUid);
+ $this->view->assign('docHeader', $this->docHeaderComponent->docHeaderContent());
+ $this->view->assign('typo3Version', VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version));
+ }
+
+ /**
+ * Clipboard pasting and deleting.
+ *
+ * @return void
+ * @throws \InvalidArgumentException
+ */
+ protected function initClipboard() {
+ if (!$this->clipObj) {
+ $this->clipObj = GeneralUtility::makeInstance(Clipboard::class);
+ }
+ $this->clipObj->initializeClipboard();
+ if (\is_array($this->clipboardCommandArray)) {
+ if ($this->clipboardCommandArray['paste']) {
+ $this->clipObj->setCurrentPad($this->clipboardCommandArray['pad']);
+ $this->command = $this->clipObj->makePasteCmdArray(
+ $this->clipboardCommandArray['paste'],
+ $this->command,
+ $this->clipboardCommandArray['update'] ?? NULL
+ );
+ }
+ if ($this->clipboardCommandArray['delete']) {
+ $this->clipObj->setCurrentPad($this->clipboardCommandArray['pad']);
+ $this->command = $this->clipObj->makeDeleteCmdArray($this->command);
+ }
+ if ($this->clipboardCommandArray['el']) {
+ $this->clipboardCommandArray['setP'] = 'normal';
+ $this->clipObj->setCmd($this->clipboardCommandArray);
+ $this->clipObj->cleanCurrent();
+ $this->clipObj->endClipboard();
+ }
+ }
+ }
+}
diff --git a/Classes/Controller/MailController.php b/Classes/Controller/MailController.php
index 2d9a357c1a7e3b1af14e542849efd3c43e83ab01..4891dc7269821cf22428ca03e4c6cb98ac5676be 100644
--- a/Classes/Controller/MailController.php
+++ b/Classes/Controller/MailController.php
@@ -69,6 +69,20 @@ class MailController extends ActionController {
$this->templateRepository = $templateRepository;
}
+ /**
+ * @var LayoutRepository
+ */
+ protected $layoutRepository;
+
+ /**
+ * Inject the LayoutRepository
+ *
+ * @param LayoutRepository $layoutRepository
+ */
+ public function injectLayoutRepository(LayoutRepository $layoutRepository) {
+ $this->layoutRepository = $layoutRepository;
+ }
+
/**
* @var \SGalinski\SgMail\Session\PhpSession
*/
@@ -248,6 +262,15 @@ class MailController extends ActionController {
$this->view->assign('selectedTemplateKey', $parameters['selectedTemplate']);
$this->view->assign('selectedExtensionKey', $parameters['selectedExtension']);
$this->view->assign('mode', 'editor');
+ $layouts = $this->layoutRepository->findByPidForModule($pageUid);
+ $layoutOptions = [
+ 0 => LocalizationUtility::translate('backend.layout.default', 'SgMail'),
+ -1 => LocalizationUtility::translate('backend.layout.none', 'SgMail')
+ ];
+ foreach ($layouts as $layout) {
+ $layoutOptions[(int) $layout['uid']] = $layout['name'];
+ }
+ $this->view->assign('layoutOptions', $layoutOptions);
} else {
$this->view->assign('pages', BackendService::getPages());
}
diff --git a/Classes/Domain/Model/Layout.php b/Classes/Domain/Model/Layout.php
new file mode 100644
index 0000000000000000000000000000000000000000..53e5c6ac0d549485a88196076b156f39c2907d9b
--- /dev/null
+++ b/Classes/Domain/Model/Layout.php
@@ -0,0 +1,73 @@
+name;
+ }
+
+ /**
+ * @param string $name
+ */
+ public function setName($name) {
+ $this->name = $name;
+ }
+
+ /**
+ * @return string
+ */
+ public function getContent(): string {
+ return $this->content;
+ }
+
+ /**
+ * @param string $content
+ */
+ public function setContent($content) {
+ $this->content = $content;
+ }
+}
diff --git a/Classes/Domain/Model/Template.php b/Classes/Domain/Model/Template.php
index 993cc472f44e099fd9a815dbf6bb91c440d2d90b..b44f7582aaa93c14307e151abb9f57570a51eb26 100644
--- a/Classes/Domain/Model/Template.php
+++ b/Classes/Domain/Model/Template.php
@@ -37,6 +37,11 @@ class Template extends AbstractEntity {
*/
protected $extensionKey = '';
+ /**
+ * @var int
+ */
+ protected $layout = 0;
+
/**
* @var string
*/
@@ -259,4 +264,18 @@ class Template extends AbstractEntity {
public function setToAddress($toAddress) {
$this->toAddress = $toAddress;
}
+
+ /**
+ * @return int
+ */
+ public function getLayout(): int {
+ return $this->layout;
+ }
+
+ /**
+ * @param int $layout
+ */
+ public function setLayout(int $layout) {
+ $this->layout = $layout;
+ }
}
diff --git a/Classes/Domain/Repository/LayoutRepository.php b/Classes/Domain/Repository/LayoutRepository.php
new file mode 100644
index 0000000000000000000000000000000000000000..0155f3e39a8617fec2003ffa6a755ddf53ee7502
--- /dev/null
+++ b/Classes/Domain/Repository/LayoutRepository.php
@@ -0,0 +1,111 @@
+objectManager->get(Typo3QuerySettings::class);
+ $querySettings->setRespectStoragePage(FALSE);
+ $querySettings->setLanguageOverlayMode(TRUE);
+ $querySettings->setLanguageMode('content_fallback');
+ $querySettings->setRespectSysLanguage(FALSE);
+ $this->setDefaultQuerySettings($querySettings);
+ }
+
+ /**
+ * Fetches the layout by uid or the default by pid
+ *
+ * @param int $uid
+ * @param int $pid
+ * @param int $languageUid
+ * @return array|NULL
+ */
+ public function findByUidOrDefault(int $uid, int $pid, int $languageUid = 0) {
+ $query = $this->createQuery();
+ $querySettings = $query->getQuerySettings();
+ $querySettings->setLanguageUid($languageUid);
+ $query->setQuerySettings($querySettings);
+ $query->setLimit(1);
+
+ if ($uid > 0) {
+ $result = $query->matching($query->equals('uid', $uid))->execute(TRUE)[0] ?? NULL;
+ if ($result) {
+ return $result;
+ }
+ }
+
+ return $query->matching(
+ $query->logicalAnd([
+ $query->equals('pid', $pid),
+ $query->equals('default', 1)
+ ])
+ )->execute(TRUE)[0] ?? NULL;
+ }
+
+ /**
+ * Returns the layout records for the given page uid
+ *
+ * @param int $pageUid
+ * @return array
+ */
+ public function findByPidForModule(int $pageUid): array {
+ $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
+ self::LAYOUT_TABLE_NAME
+ );
+ $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
+ return $queryBuilder->selectLiteral('l.*')->from(self::LAYOUT_TABLE_NAME, 'l')
+ ->where(
+ $queryBuilder->expr()->andX(
+ $queryBuilder->expr()->eq(
+ 'l.pid', $queryBuilder->createNamedParameter($pageUid, Connection::PARAM_INT)
+ ),
+ $queryBuilder->expr()->in(
+ 'l.sys_language_uid', $queryBuilder->createNamedParameter([0, -1], Connection::PARAM_INT_ARRAY)
+ )
+ )
+ )
+ ->orderBy('l.name')->execute()->fetchAll();
+ }
+}
diff --git a/Classes/Form/NodeExpansion/FieldInformation.php b/Classes/Form/NodeExpansion/FieldInformation.php
new file mode 100644
index 0000000000000000000000000000000000000000..08a44f250a3b1223c8df643ccf48984f4b5fa2da
--- /dev/null
+++ b/Classes/Form/NodeExpansion/FieldInformation.php
@@ -0,0 +1,81 @@
+initializeResultArray();
+ $options = $this->data['renderData']['fieldInformationOptions']
+ ?? $this->data['renderData']['fieldWizardOptions'];
+
+ if (
+ !isset($options['text'])
+ && (!isset($options['parentFields'], $options['parentTable'], $options['parentUidField']))
+ ) {
+ return $result;
+ }
+
+ $text = \trim($options['text'] ?? '');
+
+ if ($text === '') {
+ return $result;
+ }
+
+ if (\strpos($text, 'LLL') === 0) {
+ $text = LocalizationUtility::translate($text);
+ }
+
+ $tagOpen = '';
+ $tagClose = '';
+
+ if (isset($options['tag'])) {
+ $tag = \trim(\str_replace(['<', '>'], '', $options['tag']));
+ $tagSplit = GeneralUtility::trimExplode(' ', $tag);
+ $tagName = $tagSplit[0];
+
+ if ($tagName !== '') {
+ $tagOpen = '<' . $tag . '>';
+ $tagClose = '' . $tagName . '>';
+ }
+ }
+
+ $result['html'] = '
' . $tagOpen . $text . $tagClose . '
';
+
+ return $result;
+ }
+}
diff --git a/Classes/Hooks/ProcessDatamap.php b/Classes/Hooks/ProcessDatamap.php
new file mode 100644
index 0000000000000000000000000000000000000000..9937139ee139340a91bacc75960df9c3ecbf3f80
--- /dev/null
+++ b/Classes/Hooks/ProcessDatamap.php
@@ -0,0 +1,88 @@
+ 0) {
+ return;
+ }
+
+ $pid = (int) $updatedRow['pid'];
+ } else {
+ if ((int) $fieldArray['sys_language_uid'] > 0) {
+ return;
+ }
+ $id = (int) $dataHandler->substNEWwithIDs[$id];
+ $pid = (int) $fieldArray['pid'];
+ }
+ $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
+ 'tx_sgmail_domain_model_layout'
+ );
+ $queryBuilder->getRestrictions()->removeAll();
+ $queryBuilder->update('tx_sgmail_domain_model_layout')
+ ->where(
+ $queryBuilder->expr()->andX(
+ $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid)),
+ $queryBuilder->expr()->neq('l10n_parent', $queryBuilder->createNamedParameter($id)),
+ $queryBuilder->expr()->neq('uid', $queryBuilder->createNamedParameter($id))
+ )
+ )
+ ->set('default', 0)
+ ->execute();
+ }
+ }
+}
diff --git a/Classes/Service/BackendService.php b/Classes/Service/BackendService.php
index 08e9d7ef5f2a14564a9b7fe2449c6f7f24f00310..afd3a00caf08f9e4501683096f13490e9828e04f 100644
--- a/Classes/Service/BackendService.php
+++ b/Classes/Service/BackendService.php
@@ -331,6 +331,7 @@ class BackendService {
$template->setExtensionKey($selectedExtension);
$template->setTemplateName($selectedTemplate);
$template->setLanguage($language);
+ $template->setLayout($templateData['layout']);
$template->setContent($templateData['content']);
$template->setSubject($templateData['subject']);
$template->setFromName($templateData['fromName']);
diff --git a/Classes/Service/MailTemplateService.php b/Classes/Service/MailTemplateService.php
index 1ae7146371a57fc338457bdf416becb1c852cbf8..bd41f47d369021d8ab68e24de3d7bcb9c211e11c 100644
--- a/Classes/Service/MailTemplateService.php
+++ b/Classes/Service/MailTemplateService.php
@@ -29,6 +29,7 @@ namespace SGalinski\SgMail\Service;
use DateTime;
use SGalinski\SgMail\Domain\Model\Mail;
use SGalinski\SgMail\Domain\Model\Template;
+use SGalinski\SgMail\Domain\Repository\LayoutRepository;
use SGalinski\SgMail\Domain\Repository\MailRepository;
use SGalinski\SgMail\Domain\Repository\TemplateRepository;
use Swift_Attachment;
@@ -37,7 +38,9 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Mail\MailMessage;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\Core\Routing\SiteMatcher;
use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\VersionNumberUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
@@ -150,6 +153,11 @@ class MailTemplateService {
*/
protected $templateRepository;
+ /**
+ * @var \SGalinski\SgMail\Domain\Repository\LayoutRepository
+ */
+ protected $layoutRepository;
+
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
*/
@@ -186,6 +194,7 @@ class MailTemplateService {
$typoScriptSettingsService = $this->objectManager->get(TypoScriptSettingsService::class);
$tsSettings = $typoScriptSettingsService->getSettings(0, 'tx_sgmail');
$this->templateRepository = $this->objectManager->get(TemplateRepository::class);
+ $this->layoutRepository = $this->objectManager->get(LayoutRepository::class);
$this->persistenceManager = $this->objectManager->get(PersistenceManager::class);
$this->resourceFactory = $this->objectManager->get(ResourceFactory::class);
@@ -710,7 +719,10 @@ class MailTemplateService {
$subject = $emailView->render();
$emailView->setTemplateSource(
- empty($overwrittenEmailBody) ? $template->getContent() : $overwrittenEmailBody
+ $this->getTemplateSource(
+ empty($overwrittenEmailBody) ? $template->getContent() : $overwrittenEmailBody,
+ $template->getLayout(), $siteRootId
+ )
);
} else {
$subject = $registerService->getRegisterArray()[$this->extensionKey][$this->templateName]['subject'];
@@ -725,7 +737,10 @@ class MailTemplateService {
$subject = $emailView->render();
$emailView->setTemplateSource(
- empty($overwrittenEmailBody) ? $defaultTemplateContent : $overwrittenEmailBody
+ $this->getTemplateSource(
+ empty($overwrittenEmailBody) ? $defaultTemplateContent : $overwrittenEmailBody,
+ 0, $siteRootId
+ )
);
}
@@ -753,6 +768,78 @@ class MailTemplateService {
return $success;
}
+ /**
+ * Combines the template content with the layout and returns the result
+ *
+ * @param string $content
+ * @param int $layoutUid
+ * @param int $siteRootId
+ * @return string
+ */
+ private function getTemplateSource(string $content, int $layoutUid, int $siteRootId): string {
+ if ($layoutUid === -1) {
+ return $content;
+ }
+
+ $languageUid = 0;
+ if ($this->language !== self::DEFAULT_LANGUAGE) {
+ $languageUid = (int) array_search($this->language, $this->getAvailableLanguages(), TRUE);
+ }
+
+ $frontendSimulated = FALSE;
+ if (!isset($GLOBALS['TSFE'])) {
+ $frontendSimulated = TRUE;
+ $GLOBALS['TSFE'] = new TypoScriptFrontendController(NULL, $siteRootId, 0);
+ }
+ /** @var array $layout */
+ $layout = $this->layoutRepository->findByUidOrDefault($layoutUid, $siteRootId, $languageUid);
+ if ($frontendSimulated) {
+ unset($GLOBALS['TSFE']);
+ }
+
+ if ($layout === NULL) {
+ return $content;
+ }
+
+ return str_replace('###CONTENT###', $content, $layout['content']);
+ }
+
+ /**
+ * Returns the list of avalilable translation languages
+ *
+ * @return array
+ */
+ private function getAvailableLanguages(): array {
+ $out = [0 => ''];
+ if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9.0.0', '<')) {
+ $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
+ 'sys_language'
+ );
+ $rows = $queryBuilder->select('*')
+ ->from('sys_language')->execute()->fetchAll();
+
+ foreach ($rows as $row) {
+ $out[(int) $row['uid']] = $row['language_isocode'];
+ }
+ } else {
+ try {
+ $site = GeneralUtility::makeInstance(SiteMatcher::class)->matchByPageId(0);
+ } catch (\Exception $exception) {
+ return [0 => ''];
+ }
+ $availableLanguages = $site->getLanguages();
+ $out = [];
+ foreach ($availableLanguages as $language) {
+ $languageId = $language->getLanguageId();
+ if ($languageId < 0) {
+ continue;
+ }
+ $out[$language->getLanguageId()] = strtolower($language->getTwoLetterIsoCode());
+ }
+ }
+ return $out;
+ }
+
/**
* Adds a new mail to the mail queue.
*
diff --git a/Classes/ViewHelpers/Backend/ControlViewHelper.php b/Classes/ViewHelpers/Backend/ControlViewHelper.php
index 843cbb8232701f3dff9e87a305a947a5943b73f6..4b20c204e3718ef9b3ab68fd829ebaffa8486a9b 100644
--- a/Classes/ViewHelpers/Backend/ControlViewHelper.php
+++ b/Classes/ViewHelpers/Backend/ControlViewHelper.php
@@ -27,6 +27,7 @@ namespace SGalinski\SgMail\ViewHelpers\Backend;
***************************************************************/
use SGalinski\SgMail\ViewHelpers\AbstractViewHelper;
+use TYPO3\CMS\Backend\Clipboard\Clipboard;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList;
@@ -43,6 +44,7 @@ class ControlViewHelper extends AbstractViewHelper {
parent::initializeArguments();
$this->registerArgument('table', 'string', 'The table to control', TRUE);
$this->registerArgument('row', 'array', 'The row of the record', TRUE);
+ $this->registerArgument('clipboard', 'bool', 'If true, renders the clipboard controls', FALSE);
}
/**
@@ -55,10 +57,19 @@ class ControlViewHelper extends AbstractViewHelper {
public function render() {
$table = $this->arguments['table'];
$row = $this->arguments['row'];
+ $clipboard = (bool) $this->arguments['clipboard'];
/** @var DatabaseRecordList $databaseRecordList */
$databaseRecordList = GeneralUtility::makeInstance(DatabaseRecordList::class);
$pageInfo = BackendUtility::readPageAccess($row['pid'], $GLOBALS['BE_USER']->getPagePermsClause(1));
$databaseRecordList->calcPerms = $GLOBALS['BE_USER']->calcPerms($pageInfo);
- return $databaseRecordList->makeControl($table, $row);
+ $out = $databaseRecordList->makeControl($table, $row);
+ if ($clipboard) {
+ $databaseRecordList->MOD_SETTINGS['clipBoard'] = TRUE;
+ $databaseRecordList->clipObj = GeneralUtility::makeInstance(Clipboard::class);
+ $databaseRecordList->clipObj->initializeClipboard();
+ $GLOBALS['SOBE'] = $databaseRecordList;
+ $out .= $databaseRecordList->makeClip($table, $row);
+ }
+ return $out;
}
}
diff --git a/Configuration/TCA/tx_sgmail_domain_model_layout.php b/Configuration/TCA/tx_sgmail_domain_model_layout.php
new file mode 100644
index 0000000000000000000000000000000000000000..53127a061dd471cd6056f83afa8ffd4dc72f39de
--- /dev/null
+++ b/Configuration/TCA/tx_sgmail_domain_model_layout.php
@@ -0,0 +1,143 @@
+ [
+ 'title' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_layout',
+ 'label' => 'name',
+ 'tstamp' => 'tstamp',
+ 'crdate' => 'crdate',
+ 'cruser_id' => 'cruser_id',
+ 'searchFields' => 'name, content',
+ 'dividers2tabs' => TRUE,
+ 'delete' => 'deleted',
+ 'languageField' => 'sys_language_uid',
+ 'transOrigPointerField' => 'l10n_parent',
+ 'transOrigDiffSourceField' => 'l10n_diffsource',
+ 'enablecolumns' => [
+ 'disabled' => 'hidden',
+ ],
+ 'default_sortby' => 'name',
+ 'hideTable' => TRUE,
+ 'iconfile' => 'EXT:sg_mail/Resources/Public/Icons/ModuleIconTCA.svg'
+ ],
+ 'interface' => [
+ 'showRecordFieldList' => 'sys_language_uid, l10n_parent, l10n_diffsource, name, content, default'
+ ],
+ 'types' => [
+ '1' => [
+ 'showitem' => 'hidden, --palette--;;name, content, '
+ ],
+ ],
+ 'palettes' => [
+ 'name' => [
+ 'showitem' => 'name, default'
+ ],
+ ],
+ 'columns' => [
+ 'hidden' => [
+ 'exclude' => TRUE,
+ 'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:hidden.I.0',
+ 'config' => [
+ 'type' => 'check',
+ ],
+ ],
+ 'sys_language_uid' => [
+ 'exclude' => true,
+ 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.language',
+ 'config' => [
+ 'type' => 'select',
+ 'renderType' => 'selectSingle',
+ 'foreign_table' => 'sys_language',
+ 'foreign_table_where' => 'ORDER BY sys_language.title',
+ 'items' => [
+ ['LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages', -1],
+ ['LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.default_value', 0]
+ ],
+ 'default' => 0,
+ 'fieldWizard' => [
+ 'selectIcons' => [
+ 'disabled' => false,
+ ],
+ ],
+ ]
+ ],
+ 'l10n_parent' => [
+ 'displayCond' => 'FIELD:sys_language_uid:>:0',
+ 'exclude' => true,
+ 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
+ 'config' => [
+ 'type' => 'select',
+ 'renderType' => 'selectSingle',
+ 'items' => [
+ ['', 0]
+ ],
+ 'foreign_table' => 'tx_sgmail_domain_model_layout',
+ 'foreign_table_where' => 'AND tx_sgmail_domain_model_layout.uid=###REC_FIELD_l10n_parent### AND tx_sgmail_domain_model_layout.sys_language_uid IN (-1,0)',
+ 'default' => 0
+ ]
+ ],
+ 'l10n_diffsource' => [
+ 'config' => [
+ 'type' => 'passthrough',
+ 'default' => ''
+ ]
+ ],
+ 'default' => [
+ 'exclude' => TRUE,
+ 'l10n_mode' => 'exclude',
+ 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_layout.default',
+ 'config' => [
+ 'type' => 'check',
+ ],
+ ],
+ 'name' => [
+ 'exclude' => TRUE,
+ 'l10n_display' => 'defaultAsReadonly',
+ 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_layout.name',
+ 'config' => [
+ 'type' => 'input',
+ 'eval' => 'required, trim'
+ ],
+ ],
+ 'content' => [
+ 'exclude' => TRUE,
+ 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_layout.content',
+ 'config' => [
+ 'type' => 'text',
+ 'renderType' => 't3editor',
+ 'fieldInformation' => [
+ 'info' => [
+ 'renderType' => 'sgMailFieldInformation',
+ 'options' => [
+ 'text' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_layout.content.info'
+ ]
+ ],
+ ],
+ ],
+ ],
+ ]
+];
diff --git a/Configuration/TCA/tx_sgmail_domain_model_template.php b/Configuration/TCA/tx_sgmail_domain_model_template.php
index 3ff152ab419f62a45d411122ef19b704e374cdbf..9b42cee13069c2d877bb326631c03efd7cb14b47 100644
--- a/Configuration/TCA/tx_sgmail_domain_model_template.php
+++ b/Configuration/TCA/tx_sgmail_domain_model_template.php
@@ -43,7 +43,7 @@ return [
'iconfile' => 'EXT:sg_mail/Resources/Public/Icons/ModuleIconTCA.svg'
],
'interface' => [
- 'showRecordFieldList' => 'extension_key, template_name, language, content, subject, fromName, fromMail, cc, bcc, replyTo, to_address'
+ 'showRecordFieldList' => 'layout, extension_key, template_name, language, content, subject, fromName, fromMail, cc, bcc, replyTo, to_address'
],
'types' => [
'1' => [
@@ -58,6 +58,20 @@ return [
'type' => 'check',
],
],
+ 'layout' => [
+ 'exclude' => TRUE,
+ 'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_template.layout',
+ 'config' => [
+ 'type' => 'select',
+ 'renderType' => 'selectSingle',
+ 'items' => [
+ ['', 0]
+ ],
+ 'foreign_table' => 'tx_sgmail_domain_model_layout',
+ 'foreign_table_where' => 'AND tx_sgmail_domain_model_layout.pid=###CURRENT_PID### AND tx_sgmail_domain_model_layout.sys_language_uid IN (-1,0)',
+ 'default' => 0
+ ],
+ ],
'extension_key' => [
'exclude' => TRUE,
'label' => 'LLL:EXT:sg_mail/Resources/Private/Language/locallang_db.xlf:tx_sgmail_domain_model_template.extension_key',
diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf
index cb1be9f1344eab1daa23b32cc6b9a460410c55b6..54e4a6f72fbf535f563721afcf408820dd83366b 100644
--- a/Resources/Private/Language/de.locallang.xlf
+++ b/Resources/Private/Language/de.locallang.xlf
@@ -33,10 +33,18 @@
+
+
+
+
+
+
+
+
@@ -252,6 +260,22 @@ Bitte registrieren Sie Ihre Templates in den entsprechenden ext_localconf.php Da
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -292,6 +316,10 @@ Bitte registrieren Sie Ihre Templates in den entsprechenden ext_localconf.php Da
+
+
+
+
diff --git a/Resources/Private/Language/de.locallang_db.xlf b/Resources/Private/Language/de.locallang_db.xlf
index fd01b7596fb3082326cef0e8e695a25505024287..693b6a07e436bb6b36a02dcc68db2a299c075166 100644
--- a/Resources/Private/Language/de.locallang_db.xlf
+++ b/Resources/Private/Language/de.locallang_db.xlf
@@ -9,6 +9,26 @@
torsten@sgalinski.de
+
+ Mail Layout
+ Mail-Layout
+
+
+ Layout
+ Layout
+
+
+ To include the Mail Template content, use the '###CONTENT###' marker.
+ Verwenden Sie die Markierung "###CONTENT###", um den Inhalt des Mail-Templates einzuschließen.
+
+
+ Default
+ Default
+
+
+ Name
+ Name
+
Mail Queue Entry
Mail-Queue-Eintrag
@@ -125,6 +145,10 @@
Language
Sprache
+
+ Layout
+ Layout
+
Reply To
Antwort an
diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf
index 45d2ccaabe77b2aef290ff780e35853019825730..d6f598ef1321b1bf234e57e7479c30b0ff7f990d 100644
--- a/Resources/Private/Language/locallang.xlf
+++ b/Resources/Private/Language/locallang.xlf
@@ -27,9 +27,15 @@
+
+
+
+
+
+
@@ -194,6 +200,18 @@ Please register your configurations in the according ext_localconf.php.]]>
+
+
+
+
+
+
+
+
+
+
+
+
@@ -224,6 +242,9 @@ Please register your configurations in the according ext_localconf.php.]]>
+
+
+
diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf
index 0c8fb92484929ea34ef476e970ffc51ba4e0efe7..0592bb867ba44793373ae618e37beedb5ff3dd1a 100644
--- a/Resources/Private/Language/locallang_db.xlf
+++ b/Resources/Private/Language/locallang_db.xlf
@@ -9,6 +9,21 @@
torsten@sgalinski.de
+
+ Mail Layout
+
+
+ Layout
+
+
+ To include the Mail Template content, use the '###CONTENT###' marker.
+
+
+ Default
+
+
+ Name
+
Mail Queue Entry
@@ -96,6 +111,9 @@
Language
+
+ Layout
+
Reply To
diff --git a/Resources/Private/Partials/Layout/Empty.html b/Resources/Private/Partials/Layout/Empty.html
new file mode 100644
index 0000000000000000000000000000000000000000..ecceff62b936325a2c1d6c89b0229d3bcbb51a53
--- /dev/null
+++ b/Resources/Private/Partials/Layout/Empty.html
@@ -0,0 +1,3 @@
+
+ {f:translate(key:'backend.no_layout_entries')}
+
diff --git a/Resources/Private/Partials/Module/DocHeader.html b/Resources/Private/Partials/Module/DocHeader.html
index 09cffd21f8c0aea96a164122d5240e6d54446853..09bde8ebe777850ac523091e02839b786143b7e1 100644
--- a/Resources/Private/Partials/Module/DocHeader.html
+++ b/Resources/Private/Partials/Module/DocHeader.html
@@ -71,6 +71,10 @@
partial="Module/DocHeader"
section="actionMenuItem"
arguments="{controller:'Queue', action: 'index', label: '{f:translate(key:\'backend.mail_queue\')}', selectedTemplate: selectedTemplateKey, selectedExtension: selectedExtensionKey, simpleActionItem: 1}" />
+
diff --git a/Resources/Private/Templates/Layout/Index.html b/Resources/Private/Templates/Layout/Index.html
new file mode 100644
index 0000000000000000000000000000000000000000..1a97fbbd3b40026a1fc2aeda9f96c1b3c70eea34
--- /dev/null
+++ b/Resources/Private/Templates/Layout/Index.html
@@ -0,0 +1,81 @@
+{namespace sg=SGalinski\SgMail\ViewHelpers}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {page._thePathFull}
+
+ |
+
+
+
+
+
+
+
+
diff --git a/Resources/Private/Templates/Mail/Index.html b/Resources/Private/Templates/Mail/Index.html
index f7249ecd850a8ac6c78d222a1a633d61777b521a..eccce1a7cda32b493302da63c8f1547e97ea79fe 100644
--- a/Resources/Private/Templates/Mail/Index.html
+++ b/Resources/Private/Templates/Mail/Index.html
@@ -150,6 +150,11 @@
+
+
+
+
diff --git a/ext_localconf.php b/ext_localconf.php
index 59a1e56bb3edaea80fb4cb420fbada104fe872f1..a78784e2f1c4a62f30752da2f80344fb616c4e72 100644
--- a/ext_localconf.php
+++ b/ext_localconf.php
@@ -51,6 +51,16 @@ call_user_func(
'className' => \SGalinski\SgMail\XClass\Form\FormManagerController::class,
];
+ // Register FormEngine node type resolvers
+ $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry']['sgMailFieldInformation'] = [
+ 'nodeName' => 'sgMailFieldInformation',
+ 'priority' => 10,
+ 'class' => \SGalinski\SgMail\Form\NodeExpansion\FieldInformation::class,
+ ];
+
+ // Datamap process hook
+ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = \SGalinski\SgMail\Hooks\ProcessDatamap::class;
+
// Cache registration
$registerService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
\SGalinski\SgMail\Service\RegisterService::class
diff --git a/ext_tables.php b/ext_tables.php
index 5080e408340b43d1a13858268517374cd016c641..9895715542f3feae2ea4152b2cdbdabb1d467204 100644
--- a/ext_tables.php
+++ b/ext_tables.php
@@ -34,6 +34,7 @@ call_user_func(
'Mail' => 'index, sendTestMail, empty, reset',
'Queue' => 'index, sendMail, export',
'Configuration' => 'index, create, edit, delete',
+ 'Layout' => 'index',
],
[
'access' => 'user,group',
@@ -46,5 +47,6 @@ call_user_func(
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages(
'tx_sgmail_domain_model_template'
);
+ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_sgmail_domain_model_layout');
}, 'sg_mail'
);
diff --git a/ext_tables.sql b/ext_tables.sql
index 52b2c71ef5dcd92f7ac209b7fad7fb9e15e013f7..aee2329b4226350bbb2f90e1390b40fb2251f884 100644
--- a/ext_tables.sql
+++ b/ext_tables.sql
@@ -35,6 +35,7 @@ CREATE TABLE tx_sgmail_domain_model_template (
uid int(11) NOT NULL auto_increment,
pid int(11) DEFAULT '0' NOT NULL,
+ layout int(11) DEFAULT '0' NOT NULL,
subject text NOT NULL,
extension_key varchar(255) DEFAULT '' NOT NULL,
template_name varchar(255) DEFAULT '' NOT NULL,
@@ -57,3 +58,24 @@ CREATE TABLE tx_sgmail_domain_model_template (
PRIMARY KEY (uid),
KEY parent (pid)
);
+
+CREATE TABLE tx_sgmail_domain_model_layout (
+ uid int(11) NOT NULL auto_increment,
+ pid int(11) DEFAULT '0' NOT NULL,
+ tstamp int(11) DEFAULT '0' NOT NULL,
+ crdate int(11) DEFAULT '0' NOT NULL,
+ cruser_id int(11) DEFAULT '0' NOT NULL,
+ deleted tinyint(4) DEFAULT '0' NOT NULL,
+ hidden tinyint(4) DEFAULT '0' NOT NULL,
+ default tinyint(4) DEFAULT '0' NOT NULL,
+
+ sys_language_uid int(11) DEFAULT '0' NOT NULL,
+ l10n_parent int(11) DEFAULT '0' NOT NULL,
+ l10n_diffsource mediumblob,
+
+ name tinytext NOT NULL,
+ content text,
+
+ PRIMARY KEY (uid),
+ KEY layout_list (pid,deleted,sys_language_uid)
+);