Compare commits

...

63 Commits

Author SHA1 Message Date
2b549c7b38 [TASK] Work on compatibility for TYPO3 11 2025-08-21 15:55:33 +02:00
5b0ef1ccdf [BUGFIX] Mark function getRandomString as static 2025-08-20 13:17:29 +02:00
wadichaabene
a329a52505 [BUGFIX] Fix Captcha Validator 2025-06-20 09:31:20 +01:00
f52f1c2c35 [BUGFIX] API Utility: Check if method is object before checking for class 2025-05-26 18:13:23 +02:00
a4faec9eb3 [MERGE] Branch 'master' of ssh://phabricator.glanzstueck.agency/source/typo3-template_aide 2025-05-20 16:23:10 +02:00
8958f95806 [FEAUTRE] TCA Utility: Add function listMoveFieldBeforeField 2025-05-20 16:22:25 +02:00
998ee898fd [BUGFIX] Api utility does not resolve LazyLoadingProxy 2025-03-31 18:25:34 +02:00
wadichaabene
22a5b811b6 [BUGFIX] Remove last commit about Backend Table Mask 2025-03-24 11:50:38 +01:00
wadichaabene
2d9bc26ce6 [BUGFIX] Mask: Fix Backend Table Mask FMC0-I17 2025-03-22 15:16:27 +01:00
wadichaabene
9acf239483 [BUGFIX] Fix Language in typo3 9.5 2025-03-10 22:32:37 +01:00
wadichaabene
cd116df569 [BUGFIX] Change protection page form 2025-01-31 21:52:58 +01:00
wadichaabene
dede4d0efa [BUGFIX] Adapt Argument php 8 2025-01-31 21:42:13 +01:00
nourmkaouar
c191e6e635 [BUGFIX] Adapt mail to the new format 2025-01-17 17:58:34 +01:00
nourmkaouar
74f9767cf4 [TASK] add captcha validator 2025-01-06 17:47:49 +01:00
nourmkaouar
6f1383ce50 [TASK] Add DataProtection link 2024-12-30 15:10:07 +01:00
8502ea3910 [BUGFIX] Restore compatibilty with TYPO3 9 2024-12-12 20:51:05 +01:00
1bc7ad1eb0 [TASK] Array utility: Add depth function 2024-12-12 15:23:01 +01:00
5c42fa2d1d [TASK] Work on compatibility for TYPO3 11 2024-12-09 14:33:03 +01:00
d66fdf29a1 [TASK] Work on compatibility for TYPO3 11 2024-12-02 18:44:51 +01:00
786c200609 [MERGE] Branch 'master' of ssh://phabricator.glanzstueck.agency/source/typo3-template_aide 2024-11-28 15:21:46 +01:00
7f3123b61a [TASK] Work on compatibility for TYPO3 11 2024-11-28 15:19:38 +01:00
wadichaabene
d9e0ae6c44 [BUGFIX] Upgrade extension registerPlugin 2024-11-21 17:46:57 +01:00
fb54d608a6 [TASK] Start compatibility for TYPO3 11 2024-08-29 18:16:52 +02:00
94296d4a4d [TASK] Add style options to html mail partial 2024-07-19 11:35:21 +02:00
1a3aab9f36 [REVERT][TASK] new changes Mail
This reverts commit 14b3a54a9960f485f28ab0c529d3a6d45d0536eb.
2024-07-19 11:30:27 +02:00
wadichaabene
14b3a54a99 [TASK] new changes Mail 2024-07-18 14:20:51 +01:00
0045f87815 [REVERT][TASK] new changes Mail
This reverts commit 9ba671cfd0ce4cd245933225b645f7761291cb8e.
2024-07-18 10:56:02 +02:00
wadichaabene
9ba671cfd0 [TASK] new changes Mail 2024-07-17 23:58:53 +01:00
0e15cad446 [TASK] Make api utility image processing more fault tolerant 2024-03-14 18:39:04 +01:00
fe7b034599 [MERGE] Branch 'master' of https://phabricator.glanzstueck.agency/source/typo3-template_aide 2024-02-09 11:04:10 +01:00
ddbb0c35b0 [FEATURE] Add backend for loading translations via ajax 2024-02-09 11:04:01 +01:00
2ee1d6b18e [MERGE] Branch 'master' of git.datentonne.net:typo3/template_aide 2023-12-08 11:46:45 +01:00
869b3df738 [FEATURE] Add contentBlockHtml and diver to mail utility 2023-12-08 11:41:35 +01:00
0f3e88ac96 [BUGFIX] Fix hr layout in outlook 2023-08-04 14:11:20 +02:00
329de2771e [TASK] Mail: Add hr, right aligned table, debugging output 2022-12-09 01:42:02 +01:00
e126e674c7 [TASK] ObjectUtility: Add function to clear object data 2022-11-17 14:31:34 +01:00
ec7bb84f5e [TASK] EIDUtility: Improve function resolving and error translation handling 2022-11-09 19:18:34 +01:00
252d398174 [MERGE] Branch 'master' of https://phabricator.glanzstueck.agency/source/typo3-template_aide 2022-10-20 12:41:41 +02:00
ee10268784 [TASK] Add testAndCreateIndex function to DatabaseUtility 2022-10-20 12:41:29 +02:00
a99bbf92e1 [FEATURE] Add camelcase to kebabcase viewhelper 2022-10-10 20:53:32 +02:00
660bc3f275 [TASK] Add target _blank to html emails 2022-09-29 14:14:02 +02:00
21725f0f1e [BUGFIX] Preventing forcefully wrapping of long lines in text emails 2022-08-30 19:56:54 +02:00
42a035ccba [BUGFIX] Unset eID conditionally if in array 2022-08-30 19:55:44 +02:00
c83cb2622a [FEATURE] Add IsEmptyViewHelper 2022-08-24 16:43:03 +02:00
53ac1436db [TASK] Add return connection function to database utility 2022-08-09 18:28:02 +02:00
444a0e0158 [TASK] Add persist all function to abstract eID controller 2022-08-09 18:24:46 +02:00
15e949e0e5 [TASK] Unset eID befrore validation 2022-08-09 18:19:59 +02:00
Philipp Dieter
24f25388ce [TASK] Remove superfluous tca file 2022-06-28 23:30:41 +02:00
Philipp Dieter
902816e1f2 [TASK] Improve translation handling 2022-06-25 00:21:17 +02:00
Philipp Dieter
2dc7630390 [MERGE] Branch 'master' of https://phabricator.glanzstueck.agency/source/typo3-template_aide 2022-06-13 14:49:21 +02:00
Philipp Dieter
0e9b031feb [TASK] Fix rending buttons in email templates 2022-06-13 14:49:02 +02:00
Philipp Dieter
ff36e401a7 [MERGE] Branch 'master' of ssh://phabricator.glanzstueck.agency/source/typo3-template_aide 2022-05-07 02:34:12 +02:00
Philipp Dieter
ea847996cf [TASK] Add stack to mark external links 2022-05-07 02:33:22 +02:00
Philipp Dieter
007c3368f7 [MERGE] Branch 'master' of https://phabricator.glanzstueck.agency/source/typo3-template_aide 2022-04-29 11:01:33 +02:00
Philipp Dieter
8927f3c402 [TASK] Make array fault tolerant for recieving objects 2022-04-29 11:01:26 +02:00
Philipp Dieter
43c088850b [TASK] Add user settings option to disable drag n drop confirmation 2022-04-28 13:07:40 +02:00
Philipp Dieter
138c9373ff [TASK] Enable site config utility to handle references 2022-04-27 13:28:02 +02:00
Philipp Dieter
c72f1fd4de [TASK] Add Makefile action to add upstreams 2022-04-22 14:06:24 +02:00
Philipp Dieter
6518020594 [TASK] Add patches for debugging imports 2022-04-22 14:02:55 +02:00
Philipp Dieter
e08526325d [MERGE] Branch 'master' of https://phabricator.glanzstueck.agency/source/typo3-template_aide 2022-04-01 19:09:39 +02:00
Philipp Dieter
c959e29612 [TASK] Start working on site config and translation viewhelpers 2022-04-01 19:09:27 +02:00
Philipp Dieter
316c0d5b8d [BUGFIX] Fix backend stylesheed directory collision 2022-03-30 16:59:48 +02:00
Philipp Dieter
94a7c42289 [TASK] MailUtility: Add function extractByType 2022-03-24 18:06:06 +01:00
54 changed files with 2147 additions and 312 deletions

View File

@ -12,17 +12,28 @@ namespace Cjel\TemplatesAide\Controller;
* *
***/ ***/
use Cjel\TemplatesAide\Traits\ValidationTrait;
use Cjel\TemplatesAide\Traits\FormatResultTrait; use Cjel\TemplatesAide\Traits\FormatResultTrait;
use Cjel\TemplatesAide\Traits\ValidationTrait;
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;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer; use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer;
use TYPO3\CMS\Core\Http\Response;
use TYPO3\CMS\Core\Http\ServerRequestFactory;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
use TYPO3\CMS\Core\Log\LogManager; use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Routing\SiteMatcher;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\TypoScript\TemplateService;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\RootlineUtility;
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\Extbase\Persistence\Generic\Mapper\DataMapper;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
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\Plugin\AbstractPlugin;
@ -86,6 +97,16 @@ class AbstractEIDController
*/ */
protected $importLogger = null; protected $importLogger = null;
/**
* uriMapping
*/
protected $uriMapping = null;
/**
* uriMappingValues
*/
protected $uriMappingValues = [];
/* /*
* returns the extensionkey set in the exended calss * returns the extensionkey set in the exended calss
@ -135,15 +156,26 @@ class AbstractEIDController
$this->importLogger = $this->logManager->getLogger( $this->importLogger = $this->logManager->getLogger(
'importLogger' 'importLogger'
); );
$this->reflectionService = GeneralUtility::makeInstance( if (version_compare(TYPO3_branch, '10.0', '>=')) {
ReflectionService::class, GeneralUtility::makeInstance( $this->reflectionService = GeneralUtility::makeInstance(
CacheManager::class ReflectionService::class
) );
); } else {
$this->reflectionService = GeneralUtility::makeInstance(
ReflectionService::class, GeneralUtility::makeInstance(
CacheManager::class
)
);
}
$classInfo = $this->reflectionService->getClassSchema( $classInfo = $this->reflectionService->getClassSchema(
get_class($this) get_class($this)
); );
foreach ($classInfo->getInjectMethods() as $method => $className) { foreach ($classInfo->getInjectMethods() as $method => $className) {
if (version_compare(TYPO3_branch, '10.0', '>=')) {
$className = $className
->getFirstParameter()
->getDependency();
}
$class = $this->objectManager->get( $class = $this->objectManager->get(
$className $className
); );
@ -156,45 +188,37 @@ class AbstractEIDController
*/ */
private function initFrontendController() private function initFrontendController()
{ {
$currentDomain = strtok(GeneralUtility::getIndpEnv('HTTP_HOST'), ':'); $request = ServerRequestFactory::fromGlobals();
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) $context = GeneralUtility::makeInstance(Context::class);
->getQueryBuilderForTable('sys_domain'); $siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
$queryBuilder->setRestrictions( $siteMatcher = GeneralUtility::makeInstance(SiteMatcher::class);
GeneralUtility::makeInstance(DefaultRestrictionContainer::class) $site = $siteMatcher->matchRequest($request);
$pageId = $site->getSite()->getRootPageId();
$template = GeneralUtility::makeInstance(TemplateService::class);
$template->tt_track = false;
$rootline = GeneralUtility::makeInstance(
RootlineUtility::class, $pageId
)->get();
$template->runThroughTemplates($rootline, 0);
$template->generateConfig();
$setup = $template->setup;
$setup = GeneralUtility::removeDotsFromTS($setup);
$extKey = 'tx_' . $this->getExtensionKey();
if (array_key_exists('plugin', $setup)
&& array_key_exists($extKey, $setup['plugin'])
&& array_key_exists('persistence', $setup['plugin'][$extKey])
&& array_key_exists('storagePid', $setup['plugin'][$extKey]['persistence'])
) {
$storagePids = $setup['plugin'][$extKey]['persistence']['storagePid'];
$this->storagePids = GeneralUtility::trimExplode(
',',
$storagePids
);
}
$languageServiceFactory = GeneralUtility::makeInstance(
LanguageServiceFactory::class
); );
$result = $queryBuilder $GLOBALS['LANG'] = $languageServiceFactory->create('default');
->select('uid', 'pid', 'domainName')
->from('sys_domain')
->where(
$queryBuilder->expr()->eq(
'domainName',
$queryBuilder->createNamedParameter(
$currentDomain,
\PDO::PARAM_STR
)
)
)
->orderBy('sorting', 'ASC')
->execute()
->fetchAll();
//if (count($result) < 1) {
// throw new \Exception('Domain not configured');
//}
$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();
} }
/** /**
@ -217,16 +241,46 @@ class AbstractEIDController
return $response->withStatus(404); return $response->withStatus(404);
} }
$httpMethod = strtolower($request->getMethod()); $httpMethod = strtolower($request->getMethod());
if ($apiObjectId) { if ($this->uriMapping) {
$requestMethod = $httpMethod $uriParts = explode('/', $request->getUri()->getPath());
. ucfirst($apiObject) $uriParts = array_slice($uriParts, 3);
. 'SingleRequest'; foreach ($this->uriMapping[$httpMethod] as $mapping => $function) {
$request->apiObjectId = $apiObjectId; $mappingParts = explode('/', $mapping);
$mappingParts = array_slice($mappingParts, 1);
$max = max(count($mappingParts), count($uriParts));
$mappingMatching = true;
for ($i = 0; $i < $max; $i++) {
if ($uriParts[$i] == $mappingParts[$i]) {
continue;
}
if (
$uriParts[$i]
&& substr($mappingParts[$i], 0, 1) == '{'
&& substr($mappingParts[$i], -1, 1) == '}'
) {
$mappingKey = substr($mappingParts[$i], 1, -1);
$this->uriMappingValues[$mappingKey] = $uriParts[$i];
continue;
}
$mappingMatching = false;
}
if ($mappingMatching == true) {
$requestMethod = $function . 'Request';
}
}
} else { } else {
$requestMethod = $httpMethod if ($apiObjectId) {
. ucfirst($apiObject) $requestMethod = $httpMethod
. 'Request'; . ucfirst($apiObject)
. 'SingleRequest';
$request->apiObjectId = $apiObjectId;
} else {
$requestMethod = $httpMethod
. ucfirst($apiObject)
. 'Request';
}
} }
$response = new Response();
if (method_exists($this, $requestMethod)) { if (method_exists($this, $requestMethod)) {
$responseData = $this->$requestMethod($request, $response); $responseData = $this->$requestMethod($request, $response);
$response = $response->withHeader( $response = $response->withHeader(
@ -257,6 +311,17 @@ class AbstractEIDController
} }
} }
/**
*
*/
public function persistAll()
{
($this->objectManager->get(
PersistenceManager::class
))->persistAll();
}
/** /**
* return function * return function
* *

View File

@ -27,6 +27,8 @@ use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationBuilder;
use TYPO3\CMS\Extbase\Service\EnvironmentService; 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;
use Blueways\BwCaptcha\Validation\Validator\CaptchaValidator;
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
class ActionController extends BaseController class ActionController extends BaseController
{ {
@ -141,6 +143,11 @@ class ActionController extends BaseController
*/ */
protected $propertyMapperConfigurationBuilder; protected $propertyMapperConfigurationBuilder;
/**
* translation extensions
*/
protected $translations = [];
/** /**
* @param \TYPO3\CMS\Extbase\Service\ExtensionService $extensionService * @param \TYPO3\CMS\Extbase\Service\ExtensionService $extensionService
*/ */
@ -165,22 +172,6 @@ class ActionController extends BaseController
$this->environmentService = $environmentService; $this->environmentService = $environmentService;
} }
/**
* propertyMapper
*
* @var PropertyMapper
*/
protected $propertyMapper;
/**
* @param
*/
public function injectPropertyMapper(
PropertyMapper $propertyMapper
) {
$this->propertyMapper = $propertyMapper;
}
/** /**
* propertyMappingConfigurationBuilder * propertyMappingConfigurationBuilder
* *
@ -488,18 +479,8 @@ class ActionController extends BaseController
if ($error->keyword() == 'additionalProperties') { if ($error->keyword() == 'additionalProperties') {
continue; continue;
} }
if ($error->keyword() != 'required') { switch ($error->keyword()) {
$errorLabel = $this->getTranslation( case 'required':
'error.' . $field . '.' . $error->keyword()
);
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
} else {
$errorLabel = $this->getTranslation( $errorLabel = $this->getTranslation(
'error.' . $field . '.required' 'error.' . $field . '.required'
); );
@ -518,6 +499,59 @@ class ActionController extends BaseController
. $error->keyword(); . $error->keyword();
} }
$this->errorLabels[$field] = $errorLabel; $this->errorLabels[$field] = $errorLabel;
break;
case 'pattern':
$errorLabel = $this->getTranslation(
'error.' . $field . '.pattern'
);
if ($errorLabel == null) {
$fieldLabel = $this->getTranslation(
'field.' . $field
);
$errorLabel = $this->getTranslation(
'error.pattern', [$fieldLabel]
);
}
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
break;
case 'format':
$errorLabel = $this->getTranslation(
'error.' . $field . '.format'
);
if ($errorLabel == null) {
$fieldLabel = $this->getTranslation(
'field.' . $field
);
$errorLabel = $this->getTranslation(
'error.format', [$fieldLabel]
);
}
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
break;
default:
$errorLabel = $this->getTranslation(
'error.' . $field . '.' . $error->keyword()
);
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
break;
} }
} }
} }
@ -552,7 +586,7 @@ class ActionController extends BaseController
if (in_array($argument->getName(), ['step', 'submit', $object])) { if (in_array($argument->getName(), ['step', 'submit', $object])) {
continue; continue;
} }
if (method_exists($argument->getValue(), 'getUid')) { if (is_string($argument->getValue()) && method_exists($argument->getValue(), 'getUid')) {
$pluginArguments[$argument->getName()] $pluginArguments[$argument->getName()]
= $argument->getValue()->getUid(); = $argument->getValue()->getUid();
} else { } else {
@ -573,10 +607,26 @@ class ActionController extends BaseController
$this->request->getControllerActionName(), $this->request->getControllerActionName(),
$pluginArguments $pluginArguments
); );
$uriTranslation = $this->getControllerContext()
->getUriBuilder()
->reset()
->setCreateAbsoluteUri(true)
->setAddQueryString(true)
->setTargetPageType(6001)
->uriFor(
'translations',
[
'extensions' => $this->translations,
],
'Translation',
'TemplatesAide',
'Translationplugin'
);
$this->ajaxEnv = [ $this->ajaxEnv = [
'uri' => $uri, 'uri' => $uri,
'object' => $object, 'uriTranslation' => $uriTranslation,
'namespace' => $this->getPluginNamespace(), 'object' => $object,
'namespace' => $this->getPluginNamespace(),
]; ];
} }
@ -712,11 +762,36 @@ class ActionController extends BaseController
} }
if ($this->pageType) { if ($this->pageType) {
if (is_array($this->responseStatus)) { if (is_array($this->responseStatus)) {
$this->response->setStatus( if (version_compare(TYPO3_branch, '10.0', '>=')) {
array_key_first($this->responseStatus) $response = $this
); ->responseFactory
->createResponse()
->withHeader(
'Content-Type',
'application/json; charset=utf-8'
)
->withStatus(
array_key_first($this->responseStatus),
''
);
} else {
$this->response->setStatus(
array_key_first($this->responseStatus)
);
}
} else { } else {
$this->response->setStatus($this->responseStatus); if (version_compare(TYPO3_branch, '10.0', '>=')) {
$response = $this
->responseFactory
->createResponse()
->withHeader(
'Content-Type',
'application/json; charset=utf-8'
)
->withStatus($this->responseStatus, '');
} else {
$this->response->setStatus($this->responseStatus);
}
} }
if ($this->pageType == $this->ajaxPageType) { if ($this->pageType == $this->ajaxPageType) {
if ($this->environmentService->isEnvironmentInBackendMode()) { if ($this->environmentService->isEnvironmentInBackendMode()) {
@ -732,7 +807,12 @@ class ActionController extends BaseController
if ($this->reload) { if ($this->reload) {
$result['reload'] = true; $result['reload'] = true;
} }
return json_encode($result); if (version_compare(TYPO3_branch, '10.0', '>=')) {
$response->getBody()->write(json_encode($result));
return $response;
} else {
return json_encode($result);
}
} }
$result = array_merge( $result = array_merge(
$result, $result,
@ -747,5 +827,53 @@ class ActionController extends BaseController
); );
} }
$this->view->assignMultiple($result); $this->view->assignMultiple($result);
if (version_compare(TYPO3_branch, '10.0', '>=')) {
return $this
->responseFactory
->createResponse()
->withHeader('Content-Type', 'text/html; charset=utf-8')
->withBody($this->streamFactory->createStream(
(string)($html ?? $this->view->render()))
);
}
}
/** **/
protected function valideCaptcha($captchaId, $value
) {
$captchaPhrases = $this->getFeUser()->getKey('ses', 'captchaPhrases');
if (!$captchaPhrases || !is_array($captchaPhrases) || !is_string($value)) {
$this->addValidationError(
'captcha',
'validator.notvalid'
);
}
// get captcha secret from cache and compare
$time = time();
$captchaPhrases = array_filter(
$captchaPhrases,
function ($captchaLifetime) use ($time) {
return $captchaLifetime > $time;
},
ARRAY_FILTER_USE_KEY
);
foreach ($captchaPhrases as $lifetime => $captchaPhrase) {
$isValid = !empty($captchaPhrase) && $captchaPhrase === $value;
if ($isValid) {
// remove solved captcha
unset($captchaPhrases[$lifetime]);
$this->getFeUser()->setKey('ses', 'captchaPhrases', $captchaPhrases);
$this->getFeUser()->storeSessionData();
return true;
}
}
$this->addValidationError(
'captcha',
'validator.notvalid'
);
}
protected function getFeUser(): FrontendUserAuthentication
{
return $GLOBALS['TSFE']->fe_user;
} }
} }

View File

@ -0,0 +1,66 @@
<?php
namespace Cjel\TemplatesAide\Controller;
/***
*
* 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) 2024 Philipp Dieter <philippdieter@attic-media.net>
*
***/
use TYPO3\CMS\Core\Localization\LocalizationFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* TranslationController
*/
class TranslationController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
protected static $locallangPath = 'Resources/Private/Language/';
/**
* action translations
*
* @param array $extensions
* @return void
*/
public function translationsAction($extensions = [])
{
$result = [];
foreach ($extensions as $extension) {
$langfilePath = 'EXT:'
. GeneralUtility::camelCaseToLowerCaseUnderscored($extension)
. '/'
. self::$locallangPath
. 'locallang.xlf';
$languageFactory = GeneralUtility::makeInstance(
LocalizationFactory::class
);
if (version_compare(TYPO3_branch, '10.0', '>=')) {
$language = $this->request->getAttribute('language');
} else {
$language = $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
}
$locale = $language->getLocale();
//\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
// $locale, '$locale', 3, true, false
//);
$langfileContent = $languageFactory->getParsedData(
$langfilePath,
$locale
);
$langfileResult = [];
foreach (reset($langfileContent) as $key => $row) {
$langfileResult[$key] = reset($row)['target'];
}
$result[$extension] = $langfileResult;
}
$GLOBALS['TSFE']->setContentType('application/json');
return json_encode($result);
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Cjel\TemplatesAide\Domain\Model;
/***
*
* 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) 2024 Philipp Dieter <philippdieter@attic-media.net>
*
***/
/**
* Translation
*/
class Translation extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
}

View File

@ -102,11 +102,17 @@ trait DependencyInjectionTrait
$frameworkConfiguration['persistence']['storagePid'] $frameworkConfiguration['persistence']['storagePid']
) )
); );
$this->reflectionService = GeneralUtility::makeInstance( if (version_compare(TYPO3_branch, '10.0', '>=')) {
ReflectionService::class, GeneralUtility::makeInstance( $this->reflectionService = GeneralUtility::makeInstance(
CacheManager::class ReflectionService::class
) );
); } else {
$this->reflectionService = GeneralUtility::makeInstance(
ReflectionService::class, GeneralUtility::makeInstance(
CacheManager::class
)
);
}
$classInfo = $this->reflectionService->getClassSchema( $classInfo = $this->reflectionService->getClassSchema(
get_class($this) get_class($this)
); );

View File

@ -119,10 +119,14 @@ trait ValidationTrait
* @param schema * @param schema
* @return void * @return void
*/ */
protected function validateAgainstSchema($input, $schema) protected function validateAgainstSchema(
{ $input, $schema, $translate = false
) {
$validator = new Validator(); $validator = new Validator();
$input = ArrayUtility::removeEmptyStrings($input); $input = ArrayUtility::removeEmptyStrings($input);
if (is_array($input) && array_key_exists('eID', $input)) {
unset($input['eID']);
}
//@TODO make optional when usiing rest api //@TODO make optional when usiing rest api
//array_walk_recursive( //array_walk_recursive(
// $input, // $input,
@ -138,6 +142,7 @@ trait ValidationTrait
json_encode($schema), json_encode($schema),
-1 -1
); );
if (!$validationResult->isValid()) { if (!$validationResult->isValid()) {
$this->isValid = false; $this->isValid = false;
$this->responseStatus = [400 => 'validationError']; $this->responseStatus = [400 => 'validationError'];
@ -163,6 +168,9 @@ trait ValidationTrait
]; ];
} }
} }
if ($translate) {
$this->translateErrorMessages($validationResult);
}
} }
return $validationResult; return $validationResult;
} }
@ -210,7 +218,8 @@ trait ValidationTrait
$translation = LocalizationUtility::translate( $translation = LocalizationUtility::translate(
$key, $key,
$this->getExtensionKey(), $this->getExtensionKey(),
$arguments $arguments,
'de'
); );
if ($translation) { if ($translation) {
return $translation; return $translation;
@ -226,5 +235,97 @@ trait ValidationTrait
return null; return null;
} }
/**
* translate error messages to user readable strings
*/
protected function translateErrorMessages($validationResult)
{
foreach ($validationResult->getErrors() as $error){
$errorLabel = null;
$field = implode('.', $error->dataPointer());
if ($error->keyword() == 'required') {
$tmp = $error->dataPointer();
array_push($tmp, $error->keywordArgs()['missing']);
$field = implode('.', $tmp);
}
if ($error->keyword() == 'additionalProperties') {
continue;
}
switch ($error->keyword()) {
case 'required':
$errorLabel = $this->getTranslation(
'error.' . $field . '.required'
);
if ($errorLabel == null) {
$fieldLabel = $this->getTranslation(
'field.' . $field
);
$errorLabel = $this->getTranslation(
'error.required', [$fieldLabel]
);
}
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
break;
case 'pattern':
$errorLabel = $this->getTranslation(
'error.' . $field . '.pattern'
);
if ($errorLabel == null) {
$fieldLabel = $this->getTranslation(
'field.' . $field
);
$errorLabel = $this->getTranslation(
'error.pattern', [$fieldLabel]
);
}
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
break;
case 'format':
$errorLabel = $this->getTranslation(
'error.' . $field . '.format'
);
if ($errorLabel == null) {
$fieldLabel = $this->getTranslation(
'field.' . $field
);
$errorLabel = $this->getTranslation(
'error.format', [$fieldLabel]
);
}
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
break;
default:
$errorLabel = $this->getTranslation(
'error.' . $field . '.' . $error->keyword()
);
if ($errorLabel == null) {
$errorLabel = 'error.'
. $field
. '.'
. $error->keyword();
}
$this->errorLabels[$field] = $errorLabel;
break;
}
}
}
} }

View File

@ -0,0 +1,78 @@
<?php
namespace Cjel\TemplatesAide\UserFunc;
/**
* This file is part of the "Site Templates" 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 <philipp@glanzstueck.agency>, Glanzstück GmbH
*/
use DiDom\Document;
use DiDom\Element;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class ParseExternalLinks
{
/**
* @return string
*/
public function render($content, $conf = [])
{
$domDocument = new \DOMDocument();
$testdocument = $domDocument->loadXML($content);
if ($testdocument === false) {
return $content;
}
$document = new Document($content);
$a = $document->find('a')[0];
$href = $a->getAttribute('href');
if (substr($href, 0, 7) != "http://"
&& substr($href, 0, 8) != "https://"
) {
return $content;
}
$parsedHref = parse_url($href);
if ($_SERVER['SERVER_NAME'] == $parsedHref['host']) {
return $content;
}
if ($a->getAttribute('target') == '_blank') {
$a->setAttribute('rel', 'noopener');
}
$class = $a->getAttribute('class');
if ($class) {
$class .= ' link link-external';
} else {
$class = 'link link-external';
}
$a->setAttribute('class', $class);
if ($conf['linkText']) {
$screenreaderHint = new Element('span', $conf['linkText'] . ' ');
$screenreaderHint->setAttribute('class', 'link-external-sr-only');
$a->prependChild($screenreaderHint);
}
if ($conf['iconFile']) {
$iconDataFile = GeneralUtility::getFileAbsFileName(
$conf['iconFile']
);
$iconData = file_get_contents($iconDataFile);
$icon = new Element('span');
$icon->setInnerHtml($iconData);
$icon->setAttribute('class', 'icon-link-external');
if ($iconPosition == 'start') {
$a->prepentChild($icon);
} else {
$a->appendChild($icon);
}
}
$innerHtml = $a->innerHtml();
$a->setInnerHtml(
'<span class="link-external-inner">'
. $innerHtml
. '</span>'
);
return $document->find('body')[0]->innerHtml();
}
}

View File

@ -12,10 +12,12 @@ namespace Cjel\TemplatesAide\Utility;
* *
***/ ***/
use TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException;
use TYPO3\CMS\Core\Resource\FileReference as CoreFileReference; use TYPO3\CMS\Core\Resource\FileReference as CoreFileReference;
use TYPO3\CMS\Extbase\Domain\Model\FileReference as ExtbaseFileReference;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference as ExtbaseFileReference;
use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage; use TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage; use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Service\ImageService; use TYPO3\CMS\Extbase\Service\ImageService;
@ -75,6 +77,11 @@ class ApiUtility
if (substr($method, 0, 3) === 'get') { if (substr($method, 0, 3) === 'get') {
$methodResult = call_user_func([$row, $method]); $methodResult = call_user_func([$row, $method]);
$attributeName = lcfirst(substr($method, 3)); $attributeName = lcfirst(substr($method, 3));
if (is_object($methodResult)
&& get_class($methodResult) == LazyLoadingProxy::class
) {
$methodResult = $methodResult->_loadRealInstance();
}
$propertieResults[$attributeName] = $methodResult; $propertieResults[$attributeName] = $methodResult;
} }
} }
@ -229,11 +236,15 @@ class ApiUtility
$absoluteUrl = $requestHost $absoluteUrl = $requestHost
. '/' . '/'
. $publicUrl; . $publicUrl;
$imagePreview = $this->imageService->getImage( try {
$publicUrl, $imagePreview = $this->imageService->getImage(
null, $publicUrl,
0 null,
); 0
);
} catch (FolderDoesNotExistException $e) {
return [];
}
$processingInstructionsPreview = array( $processingInstructionsPreview = array(
//'width' => '1024c', //'width' => '1024c',
//'height' => '768c', //'height' => '768c',

View File

@ -45,7 +45,11 @@ class ArrayUtility
$value = self::removeEmptyStrings($value); $value = self::removeEmptyStrings($value);
} else { } else {
if (is_string($value) && !strlen($value)) { if (is_string($value) && !strlen($value)) {
unset($array[$key]); if (is_array($array)) {
unset($array[$key]);
} else {
unset($array->$key);
}
} }
} }
} }
@ -63,4 +67,20 @@ class ArrayUtility
return array_keys($arr) !== range(0, count($arr) - 1); return array_keys($arr) !== range(0, count($arr) - 1);
} }
/**
* Returns the depth of an array
*/
function depth(array $array) {
$depthMax = 1;
foreach ($array as $value) {
if (is_array($value)) {
$depth = self::depth($value) + 1;
if ($depth > $depthMax) {
$depthMax = $depth;
}
}
}
return $depthMax;
}
} }

View File

@ -0,0 +1,114 @@
<?php
namespace Cjel\TemplatesAide\Utility;
/***
*
* 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) 2022 Philipp Dieter
*
***/
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
/**
* Holds functions to help with database interactions
*/
class DatabaseUtility
{
/**
* Mysql date format
*/
const MYSQL_DATE_FORMAT = 'Y-m-d H:i:s';
/**
* Returns table name by model
*
* @param $model object model
* @return string table name
*/
public static function getTableNameFromModelClass($class)
{
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$dataMapper = $objectManager->get(DataMapper::class);
return $dataMapper->getDataMap($class)->getTableName();
}
/**
* Creates a new query builder and returns it
*
* @param $tablename string table name
* @return object queryBuilder
*/
public static function getQueryBuilderFromTableName($tableName)
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable($tableName)
->createQueryBuilder();
return $queryBuilder;
}
/**
* Gets a connection for a table and returns it
*
* @param $tablename string table name
* @return object connection
*/
public static function getConnectionFromTableName($tableName)
{
return GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable($tableName);
}
/**
* testAndCreateIndex
*/
public static function testAndCreateIndex(
$table, $indexName, $indexColumns, $type
) {
$connection = GeneralUtility::makeInstance(
ConnectionPool::class
)->getConnectionForTable($table);
$existTestQuery = "
SHOW TABLES LIKE '${table}'
";
$existTestResult = $connection
->executeQuery($existTestQuery)
->fetchAll();
if (!count($existTestResult)) {
return;
}
$indexTestQuery = "
SHOW INDEX FROM ${table}
WHERE Key_name = '${indexName}'
";
$indexTestResult = $connection
->executeQuery($indexTestQuery)
->fetchAll();
if (count($indexTestResult)) {
return;
}
switch ($type) {
case 'btree':
$queryCreate = "
CREATE INDEX ${indexName}
USING BTREE ON ${table} (${indexColumns})
";
break;
case 'fulltext':
$queryCreate = "
CREATE FULLTEXT INDEX ${indexName}
ON ${table} (${indexColumns})
";
break;
}
$connection->executeQuery($queryCreate);
}
}

View File

@ -20,7 +20,8 @@ use TYPO3\CMS\Extbase\Service\ImageService;
use TYPO3\CMS\Fluid\View\StandaloneView; use TYPO3\CMS\Fluid\View\StandaloneView;
use TYPO3\CMS\Fluid\View\TemplatePaths; use TYPO3\CMS\Fluid\View\TemplatePaths;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use Symfony\Component\Mime\Address;
use TYPO3\CMS\Frontend\Page\PageRepository;
/** /**
* *
*/ */
@ -79,6 +80,10 @@ class MailUtility
$type = 'tableLayout'; $type = 'tableLayout';
$textPart = substr($textPart, 3); $textPart = substr($textPart, 3);
} }
if (substr($textPart, 0, 3) === '---') {
$type = 'divider';
$textPart = substr($textPart, 3);
}
if (substr($textPart, 0, 9) === '%subject ') { if (substr($textPart, 0, 9) === '%subject ') {
$type = 'subject'; $type = 'subject';
$textPart = substr($textPart, 9); $textPart = substr($textPart, 9);
@ -128,6 +133,28 @@ class MailUtility
return $result; return $result;
} }
/**
* Gets row from content by given type
*
* @param array $content the mail content
* @param string $type the type to search
*/
public static function extractByType($content, $type)
{
$elementPosition = array_search(
$type,
array_column($content, 'type')
);
if (!$elementPosition === false) {
return;
}
if (!array_key_exists('data', $content[$elementPosition])) {
return;
}
return $content[$elementPosition]['data'];
}
/** /**
* tages maildata, builds html and text mails an decides where to send them * tages maildata, builds html and text mails an decides where to send them
* allows to intercept sender for testing * allows to intercept sender for testing
@ -193,14 +220,20 @@ class MailUtility
} }
$textView->setTemplate($templateNameText); $textView->setTemplate($templateNameText);
$mail = GeneralUtility::makeInstance(MailMessage::class); $mail = GeneralUtility::makeInstance(MailMessage::class);
$mail->setFrom($sender); if (version_compare(TYPO3_branch, '10.0', '>=')) {
$mail->setSubject($subject); $mail->from(new Address(key($sender),$sender[key($sender)]));
$mail->subject($subject);
} else {
$mail->setFrom($sender);
$mail->setSubject($subject);
}
$bodydataText = []; $bodydataText = [];
$bodydataHtml = []; $bodydataHtml = [];
foreach ($data as $row) { foreach ($data as $row) {
switch($row['type']) { switch($row['type']) {
case 'text': case 'text':
case 'table': case 'table':
case 'tablelr':
case 'tableLayout': case 'tableLayout':
case 'list': case 'list':
case 'textbold': case 'textbold':
@ -211,6 +244,8 @@ class MailUtility
case 'buttonleft': case 'buttonleft':
case 'buttoncenter': case 'buttoncenter':
case 'buttonright': case 'buttonright':
case 'divider':
case 'hr':
$row['data'] = str_replace( $row['data'] = str_replace(
"\\\n", "\\\n",
'', '',
@ -229,19 +264,15 @@ class MailUtility
case 'buttonleft': case 'buttonleft':
case 'buttoncenter': case 'buttoncenter':
case 'buttonright': case 'buttonright':
return '<a style="display: inline-block;" href="' return json_encode([
. $matchesInner[1] $matchesInner[1],
. '">' $matchesInner[2]
. '<span style="display: inline-block; padding: 10px 15px; border-radius: 3px; background-color: red;">' ]);
. 'Button!!!! '
. $matchesInner[2]
. '</span>'
. '</a>';
break; break;
default: default:
return '<a href="' return '<a href="'
. $matchesInner[1] . $matchesInner[1]
. '">' . '" target="_blank">'
. $matchesInner[2] . $matchesInner[2]
. '</a>'; . '</a>';
break; break;
@ -290,83 +321,24 @@ class MailUtility
$bodydataText[] = $textRow; $bodydataText[] = $textRow;
$bodydataHtml[] = $htmlRow; $bodydataHtml[] = $htmlRow;
break; break;
//case 'button': case 'contentBlockHtml':
// $row['data'] = str_replace( $htmlRow = $row;
// "\\\n", $bodydataHtml[] = $htmlRow;
// '', break;
// $row['data']
// );
// $htmlRow = $row;
// $htmlRow['data'] = preg_replace_callback(
// '/\[.*\]/mU',
// function($matches) {
// foreach ($matches as $match) {
// $test = preg_replace_callback(
// '/\[(\S*)\s(.*)\]/mU',
// function($matchesInner) {
//
// return '<a href="'
// . $matchesInner[1]
// . '">'
// . $matchesInner[2]
// . '</a>';
// },
// $match
// );
// \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
// $test, null, 3, true, false
// );
// return $test;
// }
// },
// $htmlRow['data']
// );
// \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
// $htmlRow['data'], null, 3, true, false
// );
// $htmlRow['data'] = preg_replace_callback(
// '/\*.*\*/mU',
// function($matches) {
// foreach ($matches as $match) {
// return '<b>'
// . substr($match, 1, -1)
// . '</b>';
// }
// },
// $htmlRow['data']
// );
// $textRow = $row;
// $textRow['data'] = preg_replace_callback(
// '/\[.*\]/mU',
// function($matches) {
// foreach ($matches as $match) {
// return preg_replace_callback(
// '/\[(\S*)\s(.*)\]/mU',
// function($matchesInner) {
// if (
// $matchesInner[2] == $matchesInner[1]
// ) {
// return $matchesInner[1];
// }
// return $matchesInner[2]
// . ': '
// . $matchesInner[1];
// },
// $match
// );
// }
// },
// $textRow['data']
// );
// $bodydataText[] = $textRow;
// $bodydataHtml[] = $htmlRow;
// break;
case 'attachment': case 'attachment':
$mail->attach(new \Swift_Attachment( if (version_compare(TYPO3_branch, '10.0', '>=')) {
$row['data'][0], $mail->attach(
$row['data'][1], $row['data'][0],
$row['data'][2] $row['data'][1],
)); $row['data'][2]
);
} else {
$mail->attach(new \Swift_Attachment(
$row['data'][0],
$row['data'][1],
$row['data'][2]
));
}
break; break;
case 'attachmentBase64': case 'attachmentBase64':
$attachmentdata = explode(',', $row['data']); $attachmentdata = explode(',', $row['data']);
@ -374,24 +346,39 @@ class MailUtility
$mimetype = $matches[1]; $mimetype = $matches[1];
preg_match('/\w*\/(.*);\w*/', $attachmentdata[0], $matches); preg_match('/\w*\/(.*);\w*/', $attachmentdata[0], $matches);
$fileextension = $matches[1]; $fileextension = $matches[1];
$mail->attach(new \Swift_Attachment( if (version_compare(TYPO3_branch, '10.0', '>=')) {
base64_decode($attachmentdata[1]), $mail->attach(
'attachment.' . $fileextension, base64_decode($attachmentdata[1]),
$mimetype 'attachment.' . $fileextension,
)); $mimetype
);
} else {
$mail->attach(new \Swift_Attachment(
base64_decode($attachmentdata[1]),
'attachment.' . $fileextension,
$mimetype
));
}
break; break;
} }
} }
$textView->assign('content', $bodydataText); $textView->assign('content', $bodydataText);
$htmlView->assign('content', $bodydataHtml); $htmlView->assign('content', $bodydataHtml);
//\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
// $bodydataHtml, null, 8, true, false
//);
$domain = $settings['mailDomain']; $domain = $settings['mailDomain'];
if ($assetDomain) { if ($assetDomain) {
$domain = $assetDomain; $domain = $assetDomain;
} }
$dataProtectionPid = $settings['dataProtectionPid'];
$uriBuilder = $objectManager->get(
UriBuilder::class
);
if ($dataProtectionPid) {
$pageRepository = GeneralUtility::makeInstance(PageRepository::class);
$urlPage = $pageRepository->getPage($settings['dataProtectionPid']);
$dataProtectionPid = $domain.$urlPage['slug'];
}
$htmlView->assign('domain', $domain); $htmlView->assign('domain', $domain);
$htmlView->assign('linkDataprotection', $dataProtectionPid);
$textBody = $textView->render(); $textBody = $textView->render();
$htmlBody = $htmlView->render(); $htmlBody = $htmlView->render();
if ($domain) { if ($domain) {
@ -425,18 +412,48 @@ class MailUtility
); );
foreach ($recipientsIntercecpted as $recipientIntercepted) { foreach ($recipientsIntercecpted as $recipientIntercepted) {
foreach ($recipients as $recipient) { foreach ($recipients as $recipient) {
$mail->setSubject( if (version_compare(TYPO3_branch, '10.0', '>=')) {
$subjectOrig . ' [ORIG-TO: ' . trim($recipient) . ']' $mail->subject(
); $subjectOrig . ' [ORIG-TO: ' . trim($recipient) . ']'
$mail->setTo(trim($recipientIntercepted)); );
$mail->to(new Address(trim($recipientIntercepted)));
} else {
$mail->setSubject(
$subjectOrig . ' [ORIG-TO: ' . trim($recipient) . ']'
);
$mail->setTo(trim($recipientIntercepted));
}
$mail->send(); $mail->send();
} }
} }
} else { } else {
foreach ($recipients as $recipient) { foreach ($recipients as $recipient) {
$mail->setTo(trim($recipient)); if (version_compare(TYPO3_branch, '10.0', '>=')) {
$mail->to(new Address(trim($recipient)));
} else {
$mail->setTo(trim($recipient));
}
$mail->send(); $mail->send();
} }
} }
} }
/**
* Debug print
*/
public static function printMaildata($maildata)
{
foreach ($maildata as $row) {
if (!is_array($row['data'])) {
print($row['data']);
} else {
print($row['data'][0]);
print(PHP_EOL);
print($row['data'][1]);
}
print(PHP_EOL);
}
print(PHP_EOL);
}
} }

View File

@ -136,4 +136,31 @@ class ObjectUtility
} }
} }
} }
/**
* Clears all object fields
*
* @return void
*/
public static function clearData(
&$object
) {
foreach ($object->_getProperties() as $property => $value) {
if ($property == 'uid' || $property == 'pid') {
continue;
}
switch (getType($value)) {
case 'string':
$object->_setProperty($property, '');
break;
case 'boolean':
$object->_setProperty($property, false);
break;
case 'integer':
$object->_setProperty($property, 0);
break;
}
}
}
} }

View File

@ -15,6 +15,7 @@ namespace Cjel\TemplatesAide\Utility;
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\Core\TypoScript\Parser\TypoScriptParser;
/** /**
* Utility to work with site config * Utility to work with site config
@ -35,20 +36,33 @@ class SiteConfigUtility
$objectManager = GeneralUtility::makeInstance( $objectManager = GeneralUtility::makeInstance(
ObjectManager::class ObjectManager::class
); );
$typoScriptParser = GeneralUtility::makeInstance(
TypoScriptParser::class
);
$configurationManager = $objectManager->get( $configurationManager = $objectManager->get(
ConfigurationManagerInterface::class ConfigurationManagerInterface::class
); );
$typoscript = $configurationManager->getConfiguration( $typoscript = $configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT
); );
$typoscript = GeneralUtility::removeDotsFromTS($typoscript);
$siteConfig = $typoscript; $siteConfig = $typoscript;
if ($limitToSiteConfig) { if ($limitToSiteConfig) {
$siteConfig = $typoscript['config']['site']; $siteConfig = $typoscript['config.']['site.'];
} }
$current = &$siteConfig; $current = &$siteConfig;
foreach ($pathParts as $key) { foreach ($pathParts as $key) {
if ($current[$key . '.']) {
$key .= '.';
}
$current = &$current[$key]; $current = &$current[$key];
if (isset($current[0]) && $current[0] === '<') {
$searchkey = trim(substr($current, 1));
list($name, $conf) = $typoScriptParser->getVal(
$searchkey,
$typoscript
);
$current = $conf;
}
} }
if (is_array($current) if (is_array($current)
&& array_key_exists('value', $current) && array_key_exists('value', $current)

View File

@ -45,7 +45,7 @@ class StringUtility
return $string; return $string;
} }
function getRandomString( public static function getRandomString(
int $length = 64, int $length = 64,
string $keyspace = null string $keyspace = null
): string { ): string {

View File

@ -142,6 +142,26 @@ class TcaUtility
return implode(', ', $fieldlist); return implode(', ', $fieldlist);
} }
/**
* @return string
*/
public static function listMoveFieldBeforeField(
$fieldlist, $field, $fieldBefore
) {
$fieldlist = GeneralUtility::trimExplode(
',',
$fieldlist
);
unset($fieldlist[(array_search($field, $fieldlist))]);
array_splice(
$fieldlist,
array_search($fieldBefore, $fieldlist),
0,
$field
);
return implode(', ', $fieldlist);
}
/** /**
* remove element from fieldlist * remove element from fieldlist
* *

View File

@ -0,0 +1,94 @@
<?php
namespace Cjel\TemplatesAide\Utility;
/***
*
* 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 <philipp.dieter@attic-media.net>
*
***/
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
*
*/
class TranslationUtility
{
/**
* Get all interface constants per prefix
*/
public static function buildSelectOptionsFromOptions(
$options,
$column,
$element,
$extensionKey = null
) {
$items = [];
if ($addEmpty) {
$items[] = ['-', ''];
}
foreach ($options as $option) {
$translationKey = "option.$element.$column.$option";
$translation = self::getTranslation(
$translationKey,
$extensionKey
);
if ($translation) {
$items[] = [
'code' => $option,
'label' => $translation,
];
} else {
$items[] = [
'code' => $option,
'label' => $translationKey,
];
}
}
return $items;
}
/**
* shortcut to get translation
*
* @return void
*/
public static function getTranslation($key, $extensionKey)
{
if (version_compare(TYPO3_branch, '10.0', '>=')) {
if (!$extensionKey) {
$extensionKey = 'site_templates';
}
return implode([
'LLL:EXT:',
$extensionKey,
'/Resources/Private/Language/locallang_db.xlf:',
$key
]);
} else {
if ($extensionKey) {
$translation = LocalizationUtility::translate(
$key,
$extensionKey
);
if ($translation) {
return $translation;
}
}
$translation = LocalizationUtility::translate(
$key,
'site_templates'
);
if ($translation) {
return $translation;
}
return null;
}
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Cjel\TemplatesAide\ViewHelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class CamelcaseToKebabcaseViewHelper extends AbstractViewHelper
{
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$string = preg_replace('/[\s.]+/', '_', $renderChildrenClosure());
$string = preg_replace('/[^0-9a-zA-Z_\-]/', '-', $string);
$string = strtolower(preg_replace('/[A-Z]+/', '-\0', $string));
$string = trim($string, '-_');
return preg_replace('/[_\-][_\-]+/', '-', $string);
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace Cjel\TemplatesAide\ViewHelpers\Format;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic;
/**
* ### Wordwrap: Wrap a string at provided character count
*
* Wraps a string to $limit characters and at $break character
* while maintaining complete words. Concatenates the resulting
* strings with $glue. Code is heavily inspired
* by Codeigniter's word_wrap helper.
*/
class WordWrapViewHelper extends AbstractViewHelper
{
use CompileWithContentArgumentAndRenderStatic;
/**
* @return void
*/
public function initializeArguments()
{
$this->registerArgument('subject', 'string', 'Text to wrap');
$this->registerArgument('limit', 'integer', 'Maximum length of resulting parts after wrapping', false, 80);
$this->registerArgument('break', 'string', 'Character to wrap text at', false, PHP_EOL);
$this->registerArgument('glue', 'string', 'Character to concatenate parts with after wrapping', false, PHP_EOL);
}
/**
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return mixed
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$subject = $renderChildrenClosure();
$limit = (integer) $arguments['limit'];
$break = $arguments['break'];
$glue = $arguments['glue'];
$subject = preg_replace('/ +/', ' ', $subject);
$subject = str_replace(["\r\n", "\r"], PHP_EOL, $subject);
$subject = wordwrap($subject, $limit, $break, false);
$output = '';
foreach (explode($break, $subject) as $line) {
if (mb_strlen($line) <= $limit) {
$output .= $line . $glue;
continue;
}
$temp = '';
//while (mb_strlen($line) > $limit) {
// $temp .= mb_substr($line, 0, $limit - 1);
// $line = mb_substr($line, $limit - 1);
//}
if (false === empty($temp)) {
$output .= $temp . $glue . $line . $glue;
} else {
$output .= $line . $glue;
}
}
return $output;
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Cjel\TemplatesAide\ViewHelpers;
/***
*
* 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 TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
use TYPO3\CMS\Extbase\Service\ImageService;
use TYPO3\CMS\Core\Imaging\ImageMagickFile;
/**
*
*/
class ImageAppendViewHelper extends AbstractTagBasedViewHelper
{
/**
* ImageService
*
* @var ImageService
*/
protected $imageService;
/**
* @param
*/
public function injectImageService(
ImageService $imageService
) {
$this->imageService = $imageService;
}
/**
* Initialize arguments.
*/
public function initializeArguments()
{
parent::initializeArguments();
$this->registerUniversalTagAttributes();
$this->registerArgument('images', 'array', '');
}
/**
* Resizes a given image (if required) and renders the respective img tag
*
* @see https://docs.typo3.org/typo3cms/TyposcriptReference/ContentObjects/Image/
*
* @throws Exception
* @return string Rendered tag
*/
public function render()
{
foreach ($this->arguments['images'] as $image) {
$imagePath = $image->getForLocalProcessing(false);
//$image = $this->imageService->getImage('', $imageArgument, true);
//$image = $this->imageService->getImageUri($image);
$imageMagickFile = ImageMagickFile::fromFilePath($imagePath, 0);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
$imageMagickFile, null, 3
);
}
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Cjel\TemplatesAide\ViewHelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class IsEmptyViewHelper extends AbstractViewHelper
{
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
if (empty($renderChildrenClosure())) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace Cjel\TemplatesAide\ViewHelpers;
/***
*
* 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) 2022 Philipp Dieter <philipp.dieter@attic-media.net>
*
***/
use Cjel\TemplatesAide\Utility\SiteConfigUtility;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
class SiteConfigViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* Initialize arguements
*
* @return void
*/
public function initializeArguments()
{
$this->registerArgument(
'key',
'string',
'The config key to get',
true
);
$this->registerArgument(
'siteConfig',
'bool',
'Limit the typoscript to the config.site part',
false,
true
);
}
/**
* Render tranlation
*
* @param $arguments array arguments
* @param $renderChildrenClosure Closure
* @param $renderingContext $renderChildrenClosure
* @return string
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
return SiteConfigUtility::getByPath(
$arguments['key'],
$arguments['siteConfig']
);
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Cjel\TemplatesAide\ViewHelpers;
/***
*
* 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) 2022 Philipp Dieter <philipp.dieter@attic-media.net>
*
***/
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
class TranslationViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* Initialize arguements
*
* @return void
*/
public function initializeArguments()
{
$this->registerArgument(
'key',
'string',
'The translation key to render',
true
);
$this->registerArgument(
'extensionKey',
'string',
'The extension key to search in',
false,
'site_templates'
);
$this->registerArgument(
'arguments',
'array',
'The arguments',
false,
false
);
}
/**
* Render tranlation
*
* @param $arguments array arguments
* @param $renderChildrenClosure Closure
* @param $renderingContext $renderChildrenClosure
* @return string
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$translation = LocalizationUtility::translate(
$arguments['key'],
$arguments['extensionKey'],
(array) $arguments['arguments']
);
if ($translation) {
return $translation;
}
return $arguments['extensionKey'] . ': ' . $arguments['key'];
}
}

View File

@ -0,0 +1,28 @@
<T3DataStructure>
<sheets>
<sDEF>
<ROOT>
<TCEforms>
<sheetTitle>Function</sheetTitle>
</TCEforms>
<type>array</type>
<el>
<switchableControllerActions>
<TCEforms>
<label>Select function</label>
<config>
<type>select</type>
<items>
<numIndex index="0">
<numIndex index="0">Translation</numIndex>
<numIndex index="1">Translation-&gt;translations</numIndex>
</numIndex>
</items>
</config>
</TCEforms>
</switchableControllerActions>
</el>
</ROOT>
</sDEF>
</sheets>
</T3DataStructure>

View File

@ -0,0 +1,14 @@
<?php
defined('TYPO3_MODE') || die();
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'TemplatesAide',
'Dummy',
'dummy'
);
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'TemplatesAide',
'Translationplugin',
'translation'
);

View File

@ -23,24 +23,14 @@ return [
'showRecordFieldList' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, ', 'showRecordFieldList' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, ',
], ],
'types' => [ 'types' => [
'1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, , --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], '1' => ['showitem' => ', --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent, l10n_diffsource, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden, starttime, endtime'],
], ],
'columns' => [ 'columns' => [
'sys_language_uid' => [ 'sys_language_uid' => [
'exclude' => true, 'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [ 'config' => [
'type' => 'select', 'type' => 'language',
'renderType' => 'selectSingle',
'special' => 'languages',
'items' => [
[
'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages',
-1,
'flags-multiple'
]
],
'default' => 0,
], ],
], ],
'l10n_parent' => [ 'l10n_parent' => [

View File

@ -0,0 +1,110 @@
<?php
return [
'ctrl' => [
'title' => 'LLL:EXT:templates_aide/Resources/Private/Language/locallang_db.xlf:tx_templatesaide_domain_model_translation',
'label' => 'uid',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
'transOrigDiffSourceField' => 'l10n_diffsource',
'delete' => 'deleted',
'enablecolumns' => [
'disabled' => 'hidden',
'starttime' => 'starttime',
'endtime' => 'endtime',
],
'searchFields' => '',
'iconfile' => 'EXT:templates_aide/Resources/Public/Icons/tx_templatesaide_domain_model_translation.gif'
],
'interface' => [
'showRecordFieldList' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, ',
],
'types' => [
'1' => ['showitem' => ', --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent, l10n_diffsource, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, hidden, starttime, endtime'],
],
'columns' => [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'language',
],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'default' => 0,
'items' => [
['', 0],
],
'foreign_table' => 'tx_templatesaide_domain_model_translation',
'foreign_table_where' => 'AND {#tx_templatesaide_domain_model_translation}.{#pid}=###CURRENT_PID### AND {#tx_templatesaide_domain_model_translation}.{#sys_language_uid} IN (-1,0)',
],
],
'l10n_diffsource' => [
'config' => [
'type' => 'passthrough',
],
],
't3ver_label' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.versionLabel',
'config' => [
'type' => 'input',
'size' => 30,
'max' => 255,
],
],
'hidden' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible',
'config' => [
'type' => 'check',
'renderType' => 'checkboxToggle',
'items' => [
[
0 => '',
1 => '',
'invertStateDisplay' => true
]
],
],
],
'starttime' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'behaviour' => [
'allowLanguageSynchronization' => true
]
],
],
'endtime' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime,int',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2038)
],
'behaviour' => [
'allowLanguageSynchronization' => true
]
],
],
],
];

View File

@ -14,6 +14,21 @@ plugin.tx_templatesaide_dummy {
} }
} }
plugin.tx_templatesaide_translationplugin {
view {
# cat=plugin.tx_templatesaide_translationplugin/file; type=string; label=Path to template root (FE)
templateRootPath = EXT:templates_aide/Resources/Private/Templates/
# cat=plugin.tx_templatesaide_translationplugin/file; type=string; label=Path to template partials (FE)
partialRootPath = EXT:templates_aide/Resources/Private/Partials/
# cat=plugin.tx_templatesaide_translationplugin/file; type=string; label=Path to template layouts (FE)
layoutRootPath = EXT:templates_aide/Resources/Private/Layouts/
}
persistence {
# cat=plugin.tx_templatesaide_translationplugin//a; type=string; label=Default storage PID
storagePid =
}
}
## EXTENSION BUILDER DEFAULTS END TOKEN - Everything BEFORE this line is overwritten with the defaults of the extension builder ## EXTENSION BUILDER DEFAULTS END TOKEN - Everything BEFORE this line is overwritten with the defaults of the extension builder
<INCLUDE_TYPOSCRIPT: source="FILE:EXT:templates_aide/Resources/Private/TypoScript/constants.ts"> <INCLUDE_TYPOSCRIPT: source="FILE:EXT:templates_aide/Resources/Private/TypoScript/constants.ts">

View File

@ -1,11 +1,11 @@
plugin.tx_templatesaide_dummy { plugin.tx_templatesaide_dummy {
view { view {
templateRootPaths.0 = EXT:{extension.shortExtensionKey}/Resources/Private/Templates/ templateRootPaths.0 = EXT:templates_aide/Resources/Private/Templates/
templateRootPaths.1 = {$plugin.tx_templatesaide_dummy.view.templateRootPath} templateRootPaths.1 = {$plugin.tx_templatesaide_dummy.view.templateRootPath}
partialRootPaths.0 = EXT:templates_aide/Resources/Private/Partials/ partialRootPaths.0 = EXT:templates_aide/Resources/Private/Partials/
partialRootPaths.1 = {$plugin.tx_templatesaide_dummy.view.partialRootPath} partialRootPaths.1 = {$plugin.tx_templatesaide_dummy.view.partialRootPath}
layoutRootPaths.0 = EXT:tx_templatesaide/Resources/Private/Layouts/ layoutRootPaths.0 = EXT:templates_aide/Resources/Private/Layouts/
layoutRootPaths.1 = {$plugin.tx_templatesaide_dummy.view.layoutRootPath} layoutRootPaths.1 = {$plugin.tx_templatesaide_dummy.view.layoutRootPath}
} }
persistence { persistence {
@ -24,6 +24,31 @@ plugin.tx_templatesaide_dummy {
} }
} }
plugin.tx_templatesaide_translationplugin {
view {
templateRootPaths.0 = EXT:templates_aide/Resources/Private/Templates/
templateRootPaths.1 = {$plugin.tx_templatesaide_translationplugin.view.templateRootPath}
partialRootPaths.0 = EXT:templates_aide/Resources/Private/Partials/
partialRootPaths.1 = {$plugin.tx_templatesaide_translationplugin.view.partialRootPath}
layoutRootPaths.0 = EXT:templates_aide/Resources/Private/Layouts/
layoutRootPaths.1 = {$plugin.tx_templatesaide_translationplugin.view.layoutRootPath}
}
persistence {
storagePid = {$plugin.tx_templatesaide_translationplugin.persistence.storagePid}
#recursive = 1
}
features {
#skipDefaultArguments = 1
# if set to 1, the enable fields are ignored in BE context
ignoreAllEnableFieldsInBe = 0
# Should be on by default, but can be disabled if all action in the plugin are uncached
requireCHashArgumentForActionArguments = 1
}
mvc {
#callDefaultActionIfActionCantBeResolved = 1
}
}
# these classes are only used in auto-generated templates # these classes are only used in auto-generated templates
plugin.tx_templatesaide._CSS_DEFAULT_STYLE ( plugin.tx_templatesaide._CSS_DEFAULT_STYLE (
textarea.f3-form-error { textarea.f3-form-error {

View File

@ -1,5 +1,4 @@
.. include:: ../Includes.txt .. include:: ../Includes.txt
.. _configuration: .. _configuration:
@ -7,20 +6,17 @@
Configuration Configuration
============= =============
Target group: **Developers, Integrators** How is the extension configured?
Aim to provide simple instructions detailing how the extension is configured.
How is the extension configured? Aim to provide simple instructions detailing Always assume that the user has no prior experience of using the extension.
how the extension is configured. Always assume that the user has no prior experience
of using your extension.
Try and provide a typical use case for your extension and detail each of the
steps required to get the extension running.
Try and provide a typical use case for your extension
and detail each of the steps required to get the extension running.
Typical Example Typical Example
=============== ===============
- Do we need to include a static template? - Does the integrator need to include a static template?
- For example add a code snippet with comments - For example add a code snippet with comments
Minimal example of TypoScript: Minimal example of TypoScript:
@ -43,12 +39,12 @@ Minimal example of TypoScript:
TypoScript Reference TypoScript Reference
==================== ====================
When detailing data types or standard TypoScript Possible subsections: Reference of TypoScript options.
features, don't hesitate to cross-link to the TypoScript The construct below show the recommended structure for TypoScript properties listing and description.
Reference.
Information about how to use cross-references: When detailing data types or standard TypoScript features,
https://docs.typo3.org/typo3cms/HowToDocument/WritingReST/Hyperlinks.html don't hesitate to cross-link to the TypoScript Reference as shown below.
See :ref:`h2document:how-to-document-hyperlinks` for information about how to use cross-references.
See the :file:`Settings.cfg` file for the declaration of cross-linking keys. See the :file:`Settings.cfg` file for the declaration of cross-linking keys.
You can add more keys besides tsref.

View File

@ -38,6 +38,47 @@
"relations": [] "relations": []
} }
} }
},
{
"config": {
"position": [
398,
234
]
},
"name": "New Model Object",
"value": {
"actionGroup": {
"_default0_list": false,
"_default1_show": false,
"_default2_new_create": false,
"_default3_edit_update": false,
"_default4_delete": false,
"customActions": [
"translations"
]
},
"name": "Translation",
"objectsettings": {
"addDeletedField": true,
"addHiddenField": true,
"addStarttimeEndtimeFields": true,
"aggregateRoot": false,
"categorizable": false,
"description": "",
"mapToTable": "",
"parentClass": "",
"sorting": false,
"type": "Entity",
"uid": "291507465262"
},
"propertyGroup": {
"properties": []
},
"relationGroup": {
"relations": []
}
}
} }
], ],
"properties": { "properties": {
@ -77,14 +118,25 @@
"description": "", "description": "",
"key": "dummy", "key": "dummy",
"name": "dummy" "name": "dummy"
},
{
"actions": {
"controllerActionCombinations": "Translation => translations",
"noncacheableActions": "",
"switchableActions": ""
},
"description": "",
"key": "translationplugin",
"name": "translation"
} }
], ],
"vendorName": "Cjel" "vendorName": "Cjel"
}, },
"wires": [], "wires": [],
"storagePath": "\/var\/www\/html\/webroot\/typo3conf\/ext\/",
"log": { "log": {
"last_modified": "2020-04-26 10:03", "last_modified": "2024-02-07 06:12",
"extension_builder_version": "9.10.2", "extension_builder_version": "9.10.6",
"be_user": " (1)" "be_user": " (68)"
} }
} }

3
Makefile Normal file
View File

@ -0,0 +1,3 @@
add_upstreams:
git remote add upstream-dt git@git.datentonne.net:typo3/template_aide.git
git remote add upstream-gs ssh://vcs@phabricator.glanzstueck.agency/source/typo3-template_aide.git

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0"> <xliff version="1.0">
<file source-language="en" target-language="de" datatype="plaintext" original="messages" date="2020-07-16T21:32:04Z"> <file source-language="en" target-language="de" datatype="plaintext" original="messages" date="2022-04-28T10:23:09Z">
<header> <header>
<generator>LFEditor</generator> <generator>LFEditor</generator>
</header> </header>
@ -9,6 +9,10 @@
<source><![CDATA[Default]]></source> <source><![CDATA[Default]]></source>
<target><![CDATA[Standard]]></target> <target><![CDATA[Standard]]></target>
</trans-unit> </trans-unit>
<trans-unit id="disableDragModal" approved="yes">
<source><![CDATA[Disable drag and drop confirmation in page tree]]></source>
<target><![CDATA[Drag & Drop-Bestätigung im Seitenbaum deaktivieren]]></target>
</trans-unit>
<trans-unit id="homepage" approved="yes"> <trans-unit id="homepage" approved="yes">
<source><![CDATA[Homepage]]></source> <source><![CDATA[Homepage]]></source>
<target><![CDATA[Startseite]]></target> <target><![CDATA[Startseite]]></target>

View File

@ -1,22 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0"> <xliff version="1.0">
<file source-language="en" datatype="plaintext" original="messages" date="2020-07-16T21:32:04Z"> <file source-language="en" datatype="plaintext" original="EXT:templates_aide/Resources/Private/Language/locallang" date="2024-02-07T18:12:19Z" product-name="templates_aide">
<header> <header/>
<generator>LFEditor</generator>
</header>
<body> <body>
<trans-unit id="default"> <trans-unit id="tx_templatesaide_domain_model_dummy" resname="tx_templatesaide_domain_model_dummy">
<source><![CDATA[Default]]></source> <source>Dummy</source>
</trans-unit> </trans-unit>
<trans-unit id="homepage"> <trans-unit id="tx_templatesaide_domain_model_translation" resname="tx_templatesaide_domain_model_translation">
<source><![CDATA[Homepage]]></source> <source>Translation</source>
</trans-unit> </trans-unit>
<trans-unit id="subpage"> <trans-unit id="default" resname="default">
<source><![CDATA[Subpage]]></source> <source>Default</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_templatesaide_domain_model_dummy"> <trans-unit id="disableDragModal" resname="disableDragModal">
<source><![CDATA[Dummy]]></source> <source>Disable drag and drop confirmation in page tree</source>
</trans-unit>
<trans-unit id="homepage" resname="homepage">
<source>Homepage</source>
</trans-unit>
<trans-unit id="subpage" resname="subpage">
<source>Subpage</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -1,17 +1,32 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0"> <xliff version="1.0">
<file source-language="en" datatype="plaintext" original="messages" date="2020-04-26T22:03:44Z" product-name="templates_aide"> <file source-language="en" datatype="plaintext" original="EXT:templates_aide/Resources/Private/Language/locallang_db" date="2024-02-07T18:12:19Z" product-name="templates_aide">
<header/> <header/>
<body> <body>
<trans-unit id="tx_templatesaide_domain_model_dummy"> <trans-unit id="tx_templatesaide_domain_model_dummy" resname="tx_templatesaide_domain_model_dummy">
<source>Dummy</source> <source>Dummy</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_templates_aide_dummy.name"> <trans-unit id="tx_templatesaide_domain_model_translation" resname="tx_templatesaide_domain_model_translation">
<source>Translation</source>
</trans-unit>
<trans-unit id="tx_templates_aide_dummy.name" resname="tx_templates_aide_dummy.name">
<source>dummy</source> <source>dummy</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_templates_aide_dummy.description"> <trans-unit id="tx_templates_aide_dummy.description" resname="tx_templates_aide_dummy.description">
<source></source>
</trans-unit>
<trans-unit id="tx_templates_aide_translationplugin.name" resname="tx_templates_aide_translationplugin.name">
<source>translation</source>
</trans-unit>
<trans-unit id="tx_templates_aide_translationplugin.description" resname="tx_templates_aide_translationplugin.description">
<source></source>
</trans-unit>
<trans-unit id="tx_templates_aide_translation.name" resname="tx_templates_aide_translation.name">
<source>translation</source>
</trans-unit>
<trans-unit id="tx_templates_aide_translation.description" resname="tx_templates_aide_translation.description">
<source></source> <source></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -8,18 +8,43 @@
<f:variable name="padding" value="20" /> <f:variable name="padding" value="20" />
</f:else> </f:else>
</f:if> </f:if>
<f:if condition="{buttonColor}">
<f:else>
<f:variable name="buttonColor" value="#ffffff" />
</f:else>
</f:if>
<f:if condition="{buttonBackgroundcolor}">
<f:else>
<f:variable name="buttonBackgroundcolor" value="#8ABF6F" />
</f:else>
</f:if>
<f:if condition="{styleH1}">
<f:else>
<f:variable name="styleH1" value="" />
</f:else>
</f:if>
<f:if condition="{styleButton}">
<f:else>
<f:variable name="styleButton" value="padding: 10px 15px; border-radius: 3px;" />
</f:else>
</f:if>
<f:variable name="widthPadded" value="{width - padding - padding}" /> <f:variable name="widthPadded" value="{width - padding - padding}" />
<f:variable name="widthTableColumn" value="{widthPadded / 2}" /> <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:else> <f:else>
<f:if condition="{row.type} == 'contentBlockHtml'">
{row.data -> f:format.raw()}
</f:if>
<f:if condition="{v:condition.string.contains(haystack: '{row.type}', needle: 'headline', then: '1')} <f:if condition="{v:condition.string.contains(haystack: '{row.type}', needle: 'headline', then: '1')}
|| {row.type} == 'text' || {row.type} == 'text'
|| {row.type} == 'button' || {row.type} == 'button'
|| {row.type} == 'buttonleft' || {row.type} == 'buttonleft'
|| {row.type} == 'buttoncenter' || {row.type} == 'buttoncenter'
|| {row.type} == 'buttonright' || {row.type} == 'buttonright'
|| {row.type} == 'divider'
|| {row.type} == 'hr'
"> ">
<!--[if mso | IE]> <!--[if mso | IE]>
<table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:{width}px;" width="{width}" > <table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:{width}px;" width="{width}" >
@ -40,6 +65,14 @@
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
<tbody> <tbody>
<tr> <tr>
<f:switch expression="{row.type}">
<f:case value="divider">
<f:variable name='paddingTd' value='20px 0' />
</f:case>
<f:defaultCase>
<f:variable name='paddingTd' value='0' />
</f:defaultCase>
</f:switch>
<td style="vertical-align:top;padding:0;"> <td style="vertical-align:top;padding:0;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
<tr> <tr>
@ -54,11 +87,11 @@
<f:variable name='align' value='left' /> <f:variable name='align' value='left' />
</f:defaultCase> </f:defaultCase>
</f:switch> </f:switch>
<td align="{align}" style="font-size:0px;padding:0;word-break:break-word;"> <td align="{align}" style="font-size:0px;padding:{paddingTd};word-break:break-word;">
<div style="font-family:Arial, sans-serif;font-size:16px;line-height:1.4;text-align:{align};color:#000000;"> <div style="font-family:Arial, sans-serif;font-size:16px;line-height:1.4;text-align:{align};color:#000000;">
<f:switch expression="{row.type}"> <f:switch expression="{row.type}">
<f:case value="headline"> <f:case value="headline">
<h1>{row.data -> f:format.nl2br() -> f:format.raw()}</h1> <h1 style="{styleH1}">{row.data -> f:format.nl2br() -> f:format.raw()}</h1>
</f:case> </f:case>
<f:case value="headline2"> <f:case value="headline2">
<h2>{row.data -> f:format.nl2br() -> f:format.raw()}</h2> <h2>{row.data -> f:format.nl2br() -> f:format.raw()}</h2>
@ -78,7 +111,12 @@
</f:case> </f:case>
<f:case value="buttoncenter"> <f:case value="buttoncenter">
<span style="display: inline-block;" class="buttonwrapper"> <span style="display: inline-block;" class="buttonwrapper">
{row.data -> f:format.nl2br() -> f:format.raw()} <f:variable name="rowData">{row.data -> v:format.json.decode()}</f:variable>
<a style="display: inline-block; color: {buttonColor}" target="_blank" href="{rowData.0}">
<span style="display: inline-block; background-color: {buttonBackgroundcolor}; {styleButton}">
{rowData.1}
</span>
</a>
</span> </span>
</f:case> </f:case>
<f:case value="buttonright"> <f:case value="buttonright">
@ -86,6 +124,38 @@
{row.data -> f:format.nl2br() -> f:format.raw()} {row.data -> f:format.nl2br() -> f:format.raw()}
</span> </span>
</f:case> </f:case>
<f:case value="hr">
<p style="border-top:solid 1px #bababa;font-size:1px;margin:13px auto;width:100%;">
</p>
<!--[if mso | IE]>
&nbsp;
<table
align="center"
border="0"
cellpadding="0"
cellspacing="0"
style="border-top:solid 1px #bababa;font-size:1px;margin:13px auto;width:100%;"
role="presentation"
width="550px"
>
<tr>
<td style="height:0;line-height:0;">
&nbsp;
</td>
</tr>
</table>
&nbsp;
<![endif]-->
</f:case>
<f:case value="divider">
<p style="border-top:solid 2px #025093;font-size:1px;margin:0px auto;width:100%;">
</p>
<!--[if mso | IE]>
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 2px #025093;font-size:1px;margin:0px auto;width:550px;" role="presentation" width="550px" >
<tr><td style="height:0;line-height:0;"> &nbsp; </td></tr>
</table>
<![endif]-->
</f:case>
<f:defaultCase> <f:defaultCase>
<p>{row.data -> f:format.nl2br() -> f:format.raw()}</p> <p>{row.data -> f:format.nl2br() -> f:format.raw()}</p>
</f:defaultCase> </f:defaultCase>
@ -122,6 +192,9 @@
<f:case value="table"> <f:case value="table">
<f:variable name="type" value="table" /> <f:variable name="type" value="table" />
</f:case> </f:case>
<f:case value="tablelr">
<f:variable name="type" value="table" />
</f:case>
<f:case value="tableLayout"> <f:case value="tableLayout">
<f:variable name="type" value="table" /> <f:variable name="type" value="table" />
</f:case> </f:case>
@ -163,11 +236,19 @@
</td> </td>
<td class="" style="vertical-align:top;width:{widthTableColumn}px;"> <td class="" style="vertical-align:top;width:{widthTableColumn}px;">
<![endif]--> <![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%;"> <f:switch expression="{row.type}">
<f:case value="tablelr">
<f:variable name="align" value="right" />
</f:case>
<f:defaultCase>
<f:variable name="align" value="left" />
</f:defaultCase>
</f:switch>
<div class="mj-column-per-50 outlook-group-fix" style="font-size:13px;text-align:{align};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%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr> <tr>
<td align="left" style="font-size:0px;padding:0px 4px;word-break:break-word;"> <td align="{align}" 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 style="font-family:Arial, sans-serif;font-size:16px;line-height:1.4;text-align:{align};color:#000000;">
<div>{row.data.1 -> f:format.nl2br() -> f:format.raw()}</div> <div>{row.data.1 -> f:format.nl2br() -> f:format.raw()}</div>
</div> </div>
</td> </td>

View File

@ -20,9 +20,9 @@
### {row.data -> f:format.nl2br() -> f:format.raw()} ### {row.data -> f:format.nl2br() -> f:format.raw()}
</f:case> </f:case>
<f:defaultCase> <f:defaultCase>
<f:spaceless><v:format.wordWrap limit="76" glue="{br}"> <f:spaceless><c:format.wordWrap limit="76" glue="{br}">
{row.data -> f:format.raw()} {row.data -> f:format.raw()}
</v:format.wordWrap> </c:format.wordWrap>
</f:spaceless>{br}{br} </f:spaceless>{br}{br}
</f:defaultCase> </f:defaultCase>
</f:switch> </f:switch>

View File

@ -55,3 +55,19 @@ pageContentelement {
no_cache = 1 no_cache = 1
} }
} }
pageTranslation = PAGE
pageTranslation {
typeNum = 6001
10 = USER_INT
10 {
userFunc = Cjel\TemplatesAide\UserFunc\Translation->render
}
config {
disableAllHeaderCode = 1
xhtml_cleaning = 0
admPanel = 0
debug = 0
no_cache = 1
}
}

View File

@ -0,0 +1,12 @@
page.10.stdWrap.parseFunc {
htmlSanitize = 0
externalBlocks = a
externalBlocks {
a.stdWrap.postUserFunc = Cjel\TemplatesAide\UserFunc\ParseExternalLinks->render
a.stdWrap.postUserFunc {
iconFile = EXT:site_templates/Resources/Private/Partials/Atoms/IconExternalLinkFill.html
iconPosistion = end
linkText = Externer Link zu
}
}
}

View File

@ -1,6 +1,3 @@
#options.pageTree.showPageIdWithTitle = 1
options.pageTree.showNavTitle = 1
options { options {
folderTree { folderTree {
uploadFieldsInLinkBrowser = 0 uploadFieldsInLinkBrowser = 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

View File

@ -1 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#666" d="M12.053 11.026c-.238.07-.427.095-.674.095-2.033 0-5.017-7.1-5.017-9.462 0-.87.207-1.16.497-1.41C4.373.54 1.39 1.452.435 2.613c-.207.29-.332.746-.332 1.326C.103 7.628 4.04 16 6.82 16c1.283 0 3.45-2.114 5.233-4.974M10.756 0c2.57 0 5.14.415 5.14 1.865 0 2.943-1.865 6.508-2.818 6.508-1.7 0-3.814-4.725-3.814-7.088C9.264.207 9.68 0 10.756 0"/></svg> <?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="#666" d="M12.053 11.026c-.238.07-.427.095-.674.095-2.033 0-5.017-7.1-5.017-9.462 0-.87.207-1.16.497-1.41C4.373.54 1.39 1.452.435 2.613c-.207.29-.332.746-.332 1.326C.103 7.628 4.04 16 6.82 16c1.283 0 3.45-2.114 5.233-4.974M10.756 0c2.57 0 5.14.415 5.14 1.865 0 2.943-1.865 6.508-2.818 6.508-1.7 0-3.814-4.725-3.814-7.088C9.264.207 9.68 0 10.756 0"></path>
</svg>

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 476 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="#666" d="M12.053 11.026c-.238.07-.427.095-.674.095-2.033 0-5.017-7.1-5.017-9.462 0-.87.207-1.16.497-1.41C4.373.54 1.39 1.452.435 2.613c-.207.29-.332.746-.332 1.326C.103 7.628 4.04 16 6.82 16c1.283 0 3.45-2.114 5.233-4.974M10.756 0c2.57 0 5.14.415 5.14 1.865 0 2.943-1.865 6.508-2.818 6.508-1.7 0-3.814-4.725-3.814-7.088C9.264.207 9.68 0 10.756 0"></path>
</svg>

After

Width:  |  Height:  |  Size: 476 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="#666" d="M12.053 11.026c-.238.07-.427.095-.674.095-2.033 0-5.017-7.1-5.017-9.462 0-.87.207-1.16.497-1.41C4.373.54 1.39 1.452.435 2.613c-.207.29-.332.746-.332 1.326C.103 7.628 4.04 16 6.82 16c1.283 0 3.45-2.114 5.233-4.974M10.756 0c2.57 0 5.14.415 5.14 1.865 0 2.943-1.865 6.508-2.818 6.508-1.7 0-3.814-4.725-3.814-7.088C9.264.207 9.68 0 10.756 0"></path>
</svg>

After

Width:  |  Height:  |  Size: 476 B

View File

@ -0,0 +1,30 @@
<?php
namespace Cjel\TemplatesAide\Tests\Unit\Controller;
/**
* Test case.
*
* @author Philipp Dieter <philippdieter@attic-media.net>
*/
class TranslationControllerTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
{
/**
* @var \Cjel\TemplatesAide\Controller\TranslationController
*/
protected $subject = null;
protected function setUp()
{
parent::setUp();
$this->subject = $this->getMockBuilder(\Cjel\TemplatesAide\Controller\TranslationController::class)
->setMethods(['redirect', 'forward', 'addFlashMessage'])
->disableOriginalConstructor()
->getMock();
}
protected function tearDown()
{
parent::tearDown();
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Cjel\TemplatesAide\Tests\Unit\Domain\Model;
/**
* Test case.
*
* @author Philipp Dieter <philippdieter@attic-media.net>
*/
class TranslationTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
{
/**
* @var \Cjel\TemplatesAide\Domain\Model\Translation
*/
protected $subject = null;
protected function setUp()
{
parent::setUp();
$this->subject = new \Cjel\TemplatesAide\Domain\Model\Translation();
}
protected function tearDown()
{
parent::tearDown();
}
/**
* @test
*/
public function dummyTestToNotLeaveThisFileEmpty()
{
self::markTestIncomplete();
}
}

View File

@ -0,0 +1,37 @@
*** webroot/typo3/sysext/core/Classes/DataHandling/DataHandler.php.orig 2022-04-22 13:15:26.314780488 +0200
--- webroot/typo3/sysext/core/Classes/DataHandling/DataHandler.php 2022-04-22 13:15:39.018129312 +0200
*************** class DataHandler implements LoggerAware
*** 7431,7446 ****
}
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
$insertErrorMessage = '';
! try {
// Execute the INSERT query:
$connection->insert(
$table,
$fieldArray,
$typeArray
);
! } catch (DBALException $e) {
! $insertErrorMessage = $e->getPrevious()->getMessage();
! }
// If succees, do...:
if ($insertErrorMessage === '') {
// Set mapping for NEW... -> real uid:
--- 7431,7446 ----
}
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
$insertErrorMessage = '';
! //try {
// Execute the INSERT query:
$connection->insert(
$table,
$fieldArray,
$typeArray
);
! //} catch (DBALException $e) {
! // $insertErrorMessage = $e->getPrevious()->getMessage();
! //}
// If succees, do...:
if ($insertErrorMessage === '') {
// Set mapping for NEW... -> real uid:

View File

@ -0,0 +1,12 @@
--- webroot/typo3/sysext/impexp/Classes/Import.php 2022-04-22 12:43:09.439221153 +0200
+++ webroot/typo3/sysext/impexp/Classes/Import.php 2022-04-22 12:43:27.169242298 +0200
@@ -446,7 +446,8 @@
}
if ($newFile->getSha1() !== $fileRecord['sha1']) {
- $this->error('Error: The hash of the written file is not identical to the import data! File could be corrupted! File: "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
+ print('Error: The hash of the written file is not identical to the import data! File could be corrupted! File: "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
+ print(PHP_EOL);
}
}

View File

@ -0,0 +1,41 @@
--- a/Resources/Public/JavaScript/SvgTree.js 2022-04-28 12:32:01.961189044 +0200
+++ b/Resources/Public/JavaScript/SvgTree.js 2022-04-28 12:32:06.047858227 +0200
@@ -37,6 +37,7 @@
showCheckboxes: false,
showIcons: false,
allowRecursiveDelete: false,
+ disableDragModal: false,
marginTop: 15,
nodeHeight: 20,
indentWidth: 16,
--- a/Resources/Public/JavaScript/PageTree/PageTreeDragDrop.js 2022-04-28 11:43:41.046705421 +0200
+++ b/Resources/Public/JavaScript/PageTree/PageTreeDragDrop.js 2022-04-28 12:30:40.741138721 +0200
@@ -275,6 +275,10 @@
var modalText = options.position === 'in' ? TYPO3.lang['mess.move_into'] : TYPO3.lang['mess.move_after'];
modalText = modalText.replace('%s', options.node.name).replace('%s', options.target.name);
+ if (tree.settings.disableDragModal) {
+ options.command = 'move';
+ tree.sendChangeCommand(options);
+ } else {
Modal.confirm(
TYPO3.lang.move_page,
modalText,
@@ -307,6 +311,7 @@
Modal.dismiss();
});
+ }
} else if (tree.nodeIsOverDelete) {
var options = _this.changeNodePosition({droppedNode: droppedNode, command: 'delete'});
if (tree.settings.displayDeleteConfirmation) {
--- a/Classes/Controller/Page/TreeController.php 2022-04-28 13:00:20.025466105 +0200
+++ b/Classes/Controller/Page/TreeController.php 2022-04-28 13:00:22.312133921 +0200
@@ -155,6 +155,7 @@
'doktypes' => $this->getDokTypes(),
'displayDeleteConfirmation' => $this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE),
'temporaryMountPoint' => $this->getMountPointPath((int)($this->getBackendUser()->uc['pageTree_temporaryMountPoint'] ?? 0)),
+ 'disableDragModal' => !empty($this->getBackendUser()->uc['disableDragModal'])
];
return new JsonResponse($configuration);

View File

@ -9,7 +9,7 @@
} }
], ],
"require": { "require": {
"typo3/cms-core": "8.7.0 - 10.99.99", "typo3/cms-core": "8.7.0 - 11.99.99",
"sarhan/php-flatten": "^4.0" "sarhan/php-flatten": "^4.0"
}, },
"autoload": { "autoload": {

View File

@ -23,7 +23,6 @@ $EM_CONF[$_EXTKEY] = [
'version' => '0.0.1', 'version' => '0.0.1',
'constraints' => [ 'constraints' => [
'depends' => [ 'depends' => [
'typo3' => '8.7.0-10.99.99',
], ],
'conflicts' => [], 'conflicts' => [],
'suggests' => [], 'suggests' => [],

View File

@ -1,41 +1,88 @@
<?php <?php
defined('TYPO3_MODE') || die('Access denied.'); defined('TYPO3_MODE') || die('Access denied.');
(static function() {
})();
call_user_func( call_user_func(
function() function()
{ {
if (version_compare(TYPO3_branch, '10.0', '>=')) {
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Cjel.TemplatesAide', 'TemplatesAide',
'Dummy', 'Translationplugin',
[ [
'Dummy' => 'list' \Cjel\TemplatesAide\Controller\TranslationController::class => 'translations'
], ],
// non-cacheable actions // non-cacheable actions
[ [
'Dummy' => '' \Cjel\TemplatesAide\Controller\TranslationController::class => ''
] ]
); );
// wizards } else {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
'mod { \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
wizards.newContentElement.wizardItems.plugins { 'Cjel.TemplatesAide',
elements { 'Dummy',
dummy { [
iconIdentifier = templates_aide-plugin-dummy 'Dummy' => 'list',
title = LLL:EXT:templates_aide/Resources/Private/Language/locallang_db.xlf:tx_templates_aide_dummy.name 'Translation' => 'translations'
description = LLL:EXT:templates_aide/Resources/Private/Language/locallang_db.xlf:tx_templates_aide_dummy.description ],
tt_content_defValues { // non-cacheable actions
CType = list [
list_type = templatesaide_dummy 'Dummy' => '',
'Translation' => ''
]
);
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Cjel.TemplatesAide',
'Translationplugin',
[
'Translation' => 'translations'
],
// non-cacheable actions
[
'Dummy' => '',
'Translation' => ''
]
);
}
// wizards
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
'mod {
wizards.newContentElement.wizardItems.plugins {
elements {
dummy {
iconIdentifier = templates_aide-plugin-dummy
title = LLL:EXT:templates_aide/Resources/Private/Language/locallang_db.xlf:tx_templates_aide_dummy.name
description = LLL:EXT:templates_aide/Resources/Private/Language/locallang_db.xlf:tx_templates_aide_dummy.description
tt_content_defValues {
CType = list
list_type = templatesaide_dummy
}
}
translationplugin {
iconIdentifier = templates_aide-plugin-translationplugin
title = LLL:EXT:templates_aide/Resources/Private/Language/locallang_db.xlf:tx_templates_aide_translationplugin.name
description = LLL:EXT:templates_aide/Resources/Private/Language/locallang_db.xlf:tx_templates_aide_translationplugin.description
tt_content_defValues {
CType = list
list_type = templatesaide_translationplugin
}
} }
} }
show = *
} }
show = * }'
} );
}'
);
$iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
$iconRegistry->registerIcon( $iconRegistry->registerIcon(
@ -44,6 +91,12 @@ call_user_func(
['source' => 'EXT:templates_aide/Resources/Public/Icons/user_plugin_dummy.svg'] ['source' => 'EXT:templates_aide/Resources/Public/Icons/user_plugin_dummy.svg']
); );
$iconRegistry->registerIcon(
'templates_aide-plugin-translationplugin',
\TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
['source' => 'EXT:templates_aide/Resources/Public/Icons/user_plugin_translationplugin.svg']
);
} }
); );
## EXTENSION BUILDER DEFAULTS END TOKEN - Everything BEFORE this line is overwritten with the defaults of the extension builder ## EXTENSION BUILDER DEFAULTS END TOKEN - Everything BEFORE this line is overwritten with the defaults of the extension builder

View File

@ -11,11 +11,20 @@ call_user_func(
'dummy' 'dummy'
); );
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'Cjel.TemplatesAide',
'Translationplugin',
'translation'
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('templates_aide', 'Configuration/TypoScript', 'Templates Aide'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('templates_aide', 'Configuration/TypoScript', 'Templates Aide');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('tx_templatesaide_domain_model_dummy', 'EXT:templates_aide/Resources/Private/Language/locallang_csh_tx_templatesaide_domain_model_dummy.xlf'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('tx_templatesaide_domain_model_dummy', 'EXT:templates_aide/Resources/Private/Language/locallang_csh_tx_templatesaide_domain_model_dummy.xlf');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_templatesaide_domain_model_dummy'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_templatesaide_domain_model_dummy');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('tx_templatesaide_domain_model_translation', 'EXT:templates_aide/Resources/Private/Language/locallang_csh_tx_templatesaide_domain_model_translation.xlf');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_templatesaide_domain_model_translation');
} }
); );
## EXTENSION BUILDER DEFAULTS END TOKEN - Everything BEFORE this line is overwritten with the defaults of the extension builder ## EXTENSION BUILDER DEFAULTS END TOKEN - Everything BEFORE this line is overwritten with the defaults of the extension builder
@ -30,17 +39,28 @@ call_user_func(
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook'][] = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook'][] =
\Cjel\TemplatesAide\Hooks\WizardItems::class; \Cjel\TemplatesAide\Hooks\WizardItems::class;
if(\TYPO3\CMS\Core\Utility\GeneralUtility::getApplicationContext()->isDevelopment()) {
$GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['dev'] = if (version_compare(TYPO3_branch, '10.0', '>=')) {
'EXT:templates_aide/Resources/Public/Css/backend/dev'; if (\TYPO3\CMS\Core\Core\Environment::getContext()->isDevelopment()) {
$GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['dev'] =
'EXT:templates_aide/Resources/Public/Css/backend/dev';
}
if(\TYPO3\CMS\Core\Core\Environment::getContext()->__toString() === 'Production/Stage') {
$GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['dev'] =
'EXT:templates_aide/Resources/Public/Css/backend/production-stage';
}
} else {
if (\TYPO3\CMS\Core\Utility\GeneralUtility::getApplicationContext()->isDevelopment()) {
$GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['dev'] =
'EXT:templates_aide/Resources/Public/Css/backend/dev';
}
if(\TYPO3\CMS\Core\Utility\GeneralUtility::getApplicationContext()->__toString() === 'Production/Stage') {
$GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['dev'] =
'EXT:templates_aide/Resources/Public/Css/backend/production-stage';
}
} }
if(\TYPO3\CMS\Core\Utility\GeneralUtility::getApplicationContext()->__toString() === 'Production/Stage') { $GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['templates_aide_default'] =
$GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['dev'] =
'EXT:templates_aide/Resources/Public/Css/backend/production-stage';
}
$GLOBALS['TBE_STYLES']['skins']['backend']['stylesheetDirectories']['default'] =
'EXT:templates_aide/Resources/Public/Css/backend/default'; 'EXT:templates_aide/Resources/Public/Css/backend/default';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile( \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
@ -65,3 +85,13 @@ call_user_func(
} }
); );
$GLOBALS['TYPO3_USER_SETTINGS']['columns']['disableDragModal'] = [
'type' => 'check',
'label' => 'LLL:EXT:templates_aide/Resources/Private/Language/locallang.xlf:disableDragModal',
];
$GLOBALS['TYPO3_USER_SETTINGS']['showitem'] = str_replace(
'recursiveDelete',
'recursiveDelete,disableDragModal',
$GLOBALS['TYPO3_USER_SETTINGS']['showitem'],
);

View File

@ -0,0 +1,77 @@
#
# Table structure for table 'tx_templatesaide_domain_model_dummy'
#
CREATE TABLE tx_templatesaide_domain_model_dummy (
uid int(11) NOT NULL auto_increment,
pid int(11) DEFAULT '0' NOT NULL,
tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL,
cruser_id int(11) unsigned DEFAULT '0' NOT NULL,
deleted smallint(5) unsigned DEFAULT '0' NOT NULL,
hidden smallint(5) unsigned DEFAULT '0' NOT NULL,
starttime int(11) unsigned DEFAULT '0' NOT NULL,
endtime int(11) unsigned DEFAULT '0' NOT NULL,
t3ver_oid int(11) DEFAULT '0' NOT NULL,
t3ver_id int(11) DEFAULT '0' NOT NULL,
t3ver_wsid int(11) DEFAULT '0' NOT NULL,
t3ver_label varchar(255) DEFAULT '' NOT NULL,
t3ver_state smallint(6) DEFAULT '0' NOT NULL,
t3ver_stage int(11) DEFAULT '0' NOT NULL,
t3ver_count int(11) DEFAULT '0' NOT NULL,
t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
t3ver_move_id int(11) DEFAULT '0' NOT NULL,
sys_language_uid int(11) DEFAULT '0' NOT NULL,
l10n_parent int(11) DEFAULT '0' NOT NULL,
l10n_diffsource mediumblob,
l10n_state text,
PRIMARY KEY (uid),
KEY parent (pid),
KEY t3ver_oid (t3ver_oid,t3ver_wsid),
KEY language (l10n_parent,sys_language_uid)
);
#
# Table structure for table 'tx_templatesaide_domain_model_translation'
#
CREATE TABLE tx_templatesaide_domain_model_translation (
uid int(11) NOT NULL auto_increment,
pid int(11) DEFAULT '0' NOT NULL,
tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL,
cruser_id int(11) unsigned DEFAULT '0' NOT NULL,
deleted smallint(5) unsigned DEFAULT '0' NOT NULL,
hidden smallint(5) unsigned DEFAULT '0' NOT NULL,
starttime int(11) unsigned DEFAULT '0' NOT NULL,
endtime int(11) unsigned DEFAULT '0' NOT NULL,
t3ver_oid int(11) DEFAULT '0' NOT NULL,
t3ver_id int(11) DEFAULT '0' NOT NULL,
t3ver_wsid int(11) DEFAULT '0' NOT NULL,
t3ver_label varchar(255) DEFAULT '' NOT NULL,
t3ver_state smallint(6) DEFAULT '0' NOT NULL,
t3ver_stage int(11) DEFAULT '0' NOT NULL,
t3ver_count int(11) DEFAULT '0' NOT NULL,
t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
t3ver_move_id int(11) DEFAULT '0' NOT NULL,
sys_language_uid int(11) DEFAULT '0' NOT NULL,
l10n_parent int(11) DEFAULT '0' NOT NULL,
l10n_diffsource mediumblob,
l10n_state text,
PRIMARY KEY (uid),
KEY parent (pid),
KEY t3ver_oid (t3ver_oid,t3ver_wsid),
KEY language (l10n_parent,sys_language_uid)
);
## EXTENSION BUILDER DEFAULTS END TOKEN - Everything BEFORE this line is overwritten with the defaults of the extension builder

View File

@ -0,0 +1,34 @@
.link-external
.link-external-inner
position: relative
.icon-circle-right
display: none
.icon-link-external
display: inline-block
position: relative
top: 2px
margin-left: 4px
//right: 2px
width: 16px
line-height: 1
div
display: inline-block
.svg-icon-element,
.svg-icon
display: block
width: 16px
height: 16px
.link-external-sr-only
position: absolute !important
margin: 0
border: 0
padding: 0
width: 1px
height: 1px
overflow: hidden
white-space: nowrap
clip: rect(1px 1px 1px 1px)
clip: rect(1px, 1px, 1px, 1px)
clip-path: inset(50%)
&.imagelink
padding-left: 0