First commit
This commit is contained in:
commit
5319bd35a5
26
.gitlab-ci.yml
Executable file
26
.gitlab-ci.yml
Executable file
@ -0,0 +1,26 @@
|
||||
# To contribute improvements to CI/CD templates, please follow the Development guide at:
|
||||
# https://docs.gitlab.com/ee/development/cicd/templates.html
|
||||
# This specific template is located at:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Composer.gitlab-ci.yml
|
||||
|
||||
# Publishes a tag/branch to Composer Packages of the current project
|
||||
publish:
|
||||
image: curlimages/curl:latest
|
||||
stage: build
|
||||
rules:
|
||||
- if: '$CI_COMMIT_REF_NAME == "develop" || $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_TAG =~ /^\d+.\d+.\d+/'
|
||||
variables:
|
||||
URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN"
|
||||
script:
|
||||
- version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG")
|
||||
- insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "")
|
||||
- response=$(curl -s -w "\n%{http_code}" $insecure --data $version $URL)
|
||||
- code=$(echo "$response" | tail -n 1)
|
||||
- body=$(echo "$response" | head -n 1)
|
||||
# Output state information
|
||||
- if [ $code -eq 201 ]; then
|
||||
echo "Package created - Code $code - $body";
|
||||
else
|
||||
echo "Could not create package - Code $code - $body";
|
||||
exit 1;
|
||||
fi
|
||||
148
Classes/Command/ContentElementCommand.php
Executable file
148
Classes/Command/ContentElementCommand.php
Executable file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\Command;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class ContentElementCommand extends Command
|
||||
{
|
||||
protected ConnectionPool $connectionPool;
|
||||
|
||||
public function __construct(ConnectionPool $connectionPool)
|
||||
{
|
||||
$this->connectionPool = $connectionPool;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setAliases(['kc-sitepackage'])
|
||||
->addOption(
|
||||
'pageId',
|
||||
'-p',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Page id to start query'
|
||||
);
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$pageIds = $input->getOption('pageId');
|
||||
$pageIds = GeneralUtility::intExplode(',', $pageIds, true);
|
||||
|
||||
foreach ($pageIds as $pageId) {
|
||||
$treeList = $this->getLocalTreeList($pageId, 999999, 0, '1=1');
|
||||
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tt_content');
|
||||
$queryBuilder
|
||||
->getRestrictions()
|
||||
->removeByType(HiddenRestriction::class)
|
||||
->removeByType(StartTimeRestriction::class)
|
||||
->removeByType(EndTimeRestriction::class);
|
||||
|
||||
$result = $queryBuilder
|
||||
->select('CType', 'list_type')
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->expr()->in('pid', explode(',', $treeList))
|
||||
)
|
||||
->groupBy('CType', 'list_type')
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
(new Table($output))
|
||||
->setHeaderTitle('Content in tree ' . $pageId)
|
||||
->setHeaders(array_keys($result[0]))
|
||||
->setRows($result)
|
||||
->render();
|
||||
|
||||
$output->writeln($treeList);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively fetch all descendants of a given page
|
||||
*/
|
||||
public function getLocalTreeList(int $id, int $depth, int $begin = 0, string $permClause = ''): string
|
||||
{
|
||||
if ($id < 0) {
|
||||
$id = abs($id);
|
||||
}
|
||||
if ($begin == 0) {
|
||||
$theList = (string)$id;
|
||||
} else {
|
||||
$theList = '';
|
||||
}
|
||||
if ($id && $depth > 0) {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
|
||||
$queryBuilder
|
||||
->getRestrictions()
|
||||
->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
|
||||
$queryBuilder
|
||||
->select('uid')
|
||||
->from('pages')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, Connection::PARAM_INT)),
|
||||
$queryBuilder->expr()->eq('sys_language_uid', 0)
|
||||
)
|
||||
->orderBy('uid');
|
||||
if ($permClause !== '') {
|
||||
$queryBuilder->andWhere($this->stripLogicalOperatorPrefix($permClause));
|
||||
}
|
||||
$statement = $queryBuilder->executeQuery();
|
||||
while ($row = $statement->fetchAssociative()) {
|
||||
if ($begin <= 0) {
|
||||
$theList .= ',' . $row['uid'];
|
||||
}
|
||||
if ($depth > 1) {
|
||||
$theSubList = $this->getLocalTreeList($row['uid'], $depth - 1, $begin - 1, $permClause);
|
||||
if (!empty($theList) && !empty($theSubList) && ($theSubList[0] !== ',')) {
|
||||
$theList .= ',';
|
||||
}
|
||||
$theList .= $theSubList;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $theList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the prefixes AND/OR from the input string.
|
||||
*
|
||||
* This function should be used when you can't guarantee that the string
|
||||
* that you want to use as a WHERE fragment is not prefixed.
|
||||
*
|
||||
* @param string $constraint The where part fragment with a possible leading AND / OR operator
|
||||
* @return string The modified where part without leading operator
|
||||
*/
|
||||
public function stripLogicalOperatorPrefix(string $constraint): string
|
||||
{
|
||||
return preg_replace('/^(?:(AND|OR)[[:space:]]*)+/i', '', trim($constraint)) ?: '';
|
||||
}
|
||||
}
|
||||
203
Classes/Configuration/AdditionalConfiguration.php
Executable file
203
Classes/Configuration/AdditionalConfiguration.php
Executable file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\Configuration;
|
||||
|
||||
/*
|
||||
* This file is part of TYPO3 CMS-based extension "container" by b13.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*/
|
||||
|
||||
use Mfc\OAuth2\ResourceServer\GitLab;
|
||||
use Mfc\OAuth2\ResourceServer\Registry;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class AdditionalConfiguration
|
||||
{
|
||||
protected string $extensionKey = 'ew_base';
|
||||
|
||||
protected array $oauthOptions = [
|
||||
'enabled' => true, // Enable/Disable the provider
|
||||
'arguments' => [
|
||||
'appId' => '',
|
||||
'appSecret' => '',
|
||||
'projectName' => '',
|
||||
'gitlabServer' => 'https://github.com',
|
||||
// User level at which the user will be given admin permissions
|
||||
'gitlabAdminUserLevel' => 30,
|
||||
// Groups to assign to the User (comma separated list possible)
|
||||
'gitlabDefaultGroups' => 1,
|
||||
// UserConfig db and/or file mount from groups
|
||||
'gitlabUserOption' => 3,
|
||||
// Blocks users with flag external from access the backend
|
||||
'blockExternalUser' => false,
|
||||
],
|
||||
];
|
||||
|
||||
protected array $developConfig = [
|
||||
'BE' => [
|
||||
'debug' => true,
|
||||
'loginRateLimit' => 10000,
|
||||
],
|
||||
'FE' => [
|
||||
'debug' => true,
|
||||
'loginRateLimit' => 10000,
|
||||
],
|
||||
'GFX' => [
|
||||
'processor' => 'GraphicsMagick',
|
||||
'processor_colorspace' => 'RGB',
|
||||
'processor_path' => '/usr/bin/',
|
||||
'processor_path_lzw' => '/usr/bin/',
|
||||
],
|
||||
'SYS' => [
|
||||
'devIPmask' => '*',
|
||||
'displayErrors' => 1,
|
||||
'systemLogLevel' => 0,
|
||||
'exceptionalErrors' => 12290,
|
||||
'errorHandlerErrors' => E_ALL & ~(
|
||||
E_STRICT | E_NOTICE | E_WARNING | E_COMPILE_WARNING | E_COMPILE_ERROR
|
||||
| E_CORE_WARNING | E_CORE_ERROR | E_PARSE | E_ERROR
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* This is needed to override all mail settings instead of merging them.
|
||||
*
|
||||
* @var array|string[]
|
||||
*/
|
||||
protected array $mailConfig = [
|
||||
'transport' => 'smtp',
|
||||
'transport_smtp_server' => '127.0.0.1:1025',
|
||||
'defaultMailFromAddress' => 'test@dev.arpa',
|
||||
];
|
||||
|
||||
public function initialize(array $configuration = []): void
|
||||
{
|
||||
$this->addContextToSitename();
|
||||
$this->addContextConfiguration($configuration);
|
||||
if (Environment::getContext() == 'Development') {
|
||||
$this->addBaseUrl();
|
||||
$this->addDebugConfiguration();
|
||||
}
|
||||
$this->addFurtherConfigurationFiles();
|
||||
}
|
||||
|
||||
protected function addContextToSitename(): void
|
||||
{
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] .= ' - ' . Environment::getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the baseurl on local environments automatically
|
||||
*/
|
||||
protected function addBaseUrl(): void
|
||||
{
|
||||
if (Environment::isCli()) {
|
||||
return;
|
||||
}
|
||||
$remoteHost = GeneralUtility::getIndpEnv('HTTP_HOST');
|
||||
ExtensionManagementUtility::addTypoScript(
|
||||
$this->extensionKey,
|
||||
'constants',
|
||||
'
|
||||
// condition should trigger different cache hashes
|
||||
[request.getNormalizedParams().getHttpHost() == \'' . $remoteHost . '\']
|
||||
config.baseURL = ' . $remoteHost . '
|
||||
[end]
|
||||
',
|
||||
'defaultContentRendering'
|
||||
);
|
||||
}
|
||||
|
||||
protected function addDebugConfiguration(): void
|
||||
{
|
||||
$GLOBALS['TYPO3_CONF_VARS'] = $this->arrayMergeRecursive(
|
||||
$GLOBALS['TYPO3_CONF_VARS'],
|
||||
$this->developConfig
|
||||
);
|
||||
$layoutRootPaths = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'] ?: [];
|
||||
$partialRootPaths = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'] ?: [];
|
||||
$templateRootPaths = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'] ?: [];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['MAIL'] = $this->mailConfig;
|
||||
|
||||
if (!empty($layoutRootPaths)) {
|
||||
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'] = $layoutRootPaths;
|
||||
}
|
||||
if (!empty($partialRootPaths)) {
|
||||
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'] = $partialRootPaths;
|
||||
}
|
||||
if (!empty($templateRootPaths)) {
|
||||
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'] = $templateRootPaths;
|
||||
}
|
||||
}
|
||||
|
||||
protected function addContextConfiguration(array $configuration): void
|
||||
{
|
||||
$context = (string)Environment::getContext();
|
||||
if (isset($configuration[$context]) && is_array($configuration[$context])) {
|
||||
$GLOBALS['TYPO3_CONF_VARS'] = $this->arrayMergeRecursive(
|
||||
$GLOBALS['TYPO3_CONF_VARS'],
|
||||
$configuration[$context]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads additional configuration two levels up relative to instance
|
||||
* or relative to ADDITIONAL_CONFIG_FILE configuration
|
||||
*/
|
||||
protected function addFurtherConfigurationFiles(): void
|
||||
{
|
||||
$paths = [
|
||||
Environment::getPublicPath() . '/../../../AdditionalConfiguration.php',
|
||||
Environment::getPublicPath() . '/' . ($_SERVER['ADDITIONAL_CONFIG_FILE'] ?? time() . '.php'),
|
||||
];
|
||||
foreach ($paths as $path) {
|
||||
$path = realpath($path);
|
||||
if ($path && @file_exists($path)) {
|
||||
/** @noinspection */
|
||||
require_once $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addGitlabLogin(array $options = []): void
|
||||
{
|
||||
if (!empty($options)) {
|
||||
$this->oauthOptions['arguments']['gitlabAdminUserLevel'] = GitLab::USER_LEVEL_DEVELOPER;
|
||||
Registry::addServer(
|
||||
'gitlab',
|
||||
'Login mit GitLab',
|
||||
GitLab::class,
|
||||
$this->arrayMergeRecursive($this->oauthOptions, $options)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function arrayMergeRecursive(array $array1, array $array2): array
|
||||
{
|
||||
$merged = $array1;
|
||||
|
||||
foreach ($array2 as $key => $value) {
|
||||
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
|
||||
$merged[$key] = $this->arrayMergeRecursive($merged[$key], $value);
|
||||
} elseif (is_numeric($key)) {
|
||||
if (!in_array($value, $merged)) {
|
||||
$merged[] = $value;
|
||||
}
|
||||
} else {
|
||||
$merged[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $merged;
|
||||
}
|
||||
}
|
||||
58
Classes/DataProcessing/ContainerProcessor.php
Executable file
58
Classes/DataProcessing/ContainerProcessor.php
Executable file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\DataProcessing;
|
||||
|
||||
/*
|
||||
* This file is part of TYPO3 CMS-based extension "container" by b13.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*/
|
||||
|
||||
use B13\Container\DataProcessing\ContainerProcessor as BaseContainerProcessor;
|
||||
use B13\Container\Domain\Model\Container;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
use TYPO3\CMS\Frontend\ContentObject\RecordsContentObject;
|
||||
|
||||
class ContainerProcessor extends BaseContainerProcessor
|
||||
{
|
||||
protected function processColPos(
|
||||
ContentObjectRenderer $cObj,
|
||||
Container $container,
|
||||
int $colPos,
|
||||
string $as,
|
||||
array $processedData,
|
||||
array $processorConfiguration
|
||||
): array {
|
||||
$children = $container->getChildrenByColPos($colPos);
|
||||
|
||||
if (!$processorConfiguration['doNotProcessChildren']) {
|
||||
$contentRecordRenderer = new RecordsContentObject();
|
||||
$conf = [
|
||||
'tables' => 'tt_content'
|
||||
];
|
||||
foreach ($children as &$child) {
|
||||
if ($child['l18n_parent'] > 0) {
|
||||
$conf['source'] = $child['l18n_parent'];
|
||||
} else {
|
||||
$conf['source'] = $child['uid'];
|
||||
}
|
||||
if ($child['t3ver_oid'] > 0) {
|
||||
$conf['source'] = $child['t3ver_oid'];
|
||||
}
|
||||
$child['renderedContent'] = $cObj->render($contentRecordRenderer, $conf);
|
||||
/** @var ContentObjectRenderer $recordContentObjectRenderer */
|
||||
$recordContentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
||||
$recordContentObjectRenderer->start($child, 'tt_content');
|
||||
$child = $this->contentDataProcessor->process($recordContentObjectRenderer, $processorConfiguration, $child);
|
||||
}
|
||||
}
|
||||
|
||||
$processedData[$as] = $children;
|
||||
return $processedData;
|
||||
}
|
||||
}
|
||||
99
Classes/EventListener/CssMerger.php
Executable file
99
Classes/EventListener/CssMerger.php
Executable file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\EventListener;
|
||||
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Page\AssetCollector;
|
||||
use TYPO3\CMS\Core\Page\Event\BeforeStylesheetsRenderingEvent;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
class CssMerger
|
||||
{
|
||||
public function __construct(protected ExtensionConfiguration $extensionConfiguration)
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke(BeforeStylesheetsRenderingEvent $event): void
|
||||
{
|
||||
if ($event->isInline() && $event->isPriority()) {
|
||||
$assetCollector = $event->getAssetCollector();
|
||||
|
||||
$styles = [];
|
||||
$styles = $this->getStylesheetFileContent($assetCollector, $styles);
|
||||
$styles = $this->getStylesheetInlineContent($assetCollector, $styles);
|
||||
|
||||
$styles = array_unique($styles);
|
||||
$styles = trim(implode(LF, $styles));
|
||||
if (empty($styles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$inlineCssStyles = $this->extensionConfiguration->get('ew_base', 'inlineCssStyles');
|
||||
if ($inlineCssStyles) {
|
||||
$assetCollector->addInlineStyleSheet('ew_base', $styles, [], ['priority' => true]);
|
||||
} else {
|
||||
$temporaryFile = GeneralUtility::writeStyleSheetContentToTemporaryFile($styles);
|
||||
$assetCollector->addStyleSheet('combined_styles', $temporaryFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getStylesheetFileContent(AssetCollector $assetCollector, array $styles): array
|
||||
{
|
||||
$styleSheetsFiles = $assetCollector->getStyleSheets(true);
|
||||
foreach ($styleSheetsFiles as $identifier => $asset) {
|
||||
if (!str_contains($asset['source'], '//') && $content = $this->getFileContent($asset['source'])) {
|
||||
$styles[] = $content;
|
||||
$assetCollector->removeStyleSheet($identifier);
|
||||
}
|
||||
}
|
||||
|
||||
$styleSheetsFiles = $assetCollector->getStyleSheets(false);
|
||||
foreach ($styleSheetsFiles as $identifier => $asset) {
|
||||
if (!str_contains($asset['source'], '//') && $content = $this->getFileContent($asset['source'])) {
|
||||
$styles[] = $content;
|
||||
$assetCollector->removeStyleSheet($identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return $styles;
|
||||
}
|
||||
|
||||
protected function getStylesheetInlineContent(AssetCollector $assetCollector, array $styles): array
|
||||
{
|
||||
$styleSheetsInline = $assetCollector->getInlineStyleSheets(false);
|
||||
foreach ($styleSheetsInline as $identifier => $asset) {
|
||||
$styles[] = $asset['source'];
|
||||
$assetCollector->removeInlineStyleSheet($identifier);
|
||||
}
|
||||
return $styles;
|
||||
}
|
||||
|
||||
protected function getFileContent(string $filePath): string
|
||||
{
|
||||
$absoluteFilePath = GeneralUtility::getFileAbsFileName($filePath);
|
||||
if (!$absoluteFilePath || !@file_exists($absoluteFilePath)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$content = (string)file_get_contents($absoluteFilePath);
|
||||
$content = preg_replace('@# sourceMappingURL=.*.css.map@', '', $content);
|
||||
|
||||
$relativeFilePath = dirname(PathUtility::getAbsoluteWebPath($absoluteFilePath));
|
||||
|
||||
return str_replace(
|
||||
[
|
||||
'url(..',
|
||||
'url("..',
|
||||
'url(\'..',
|
||||
],
|
||||
[
|
||||
'url(' . $relativeFilePath . '/..',
|
||||
'url("' . $relativeFilePath . '/..',
|
||||
'url(\'' . $relativeFilePath . '/..',
|
||||
],
|
||||
$content
|
||||
);
|
||||
}
|
||||
}
|
||||
25
Classes/EventListener/IsContentUsedOnPageLayout.php
Executable file
25
Classes/EventListener/IsContentUsedOnPageLayout.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\EventListener;
|
||||
|
||||
use TYPO3\CMS\Backend\ViEvoweb\Event\IsContentUsedOnPageLayoutEvent;
|
||||
|
||||
class IsContentUsedOnPageLayout
|
||||
{
|
||||
public function __invoke(IsContentUsedOnPageLayoutEvent $event): void
|
||||
{
|
||||
$event->setUsed($event->isRecordUsed() || $this->findCTypeBegin($event->getRecord()['CType']));
|
||||
}
|
||||
|
||||
public function findCTypeBegin($cType): bool
|
||||
{
|
||||
$found = false;
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['ContentUsedStrings'] ?? [] as $search) {
|
||||
if (strpos($cType, $search) !== false) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
96
Classes/EventListener/JsMerger.php
Executable file
96
Classes/EventListener/JsMerger.php
Executable file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\EventListener;
|
||||
|
||||
use TYPO3\CMS\Core\Page\AssetCollector;
|
||||
use TYPO3\CMS\Core\Page\Event\BeforeJavaScriptsRenderingEvent;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
class JsMerger
|
||||
{
|
||||
public function __invoke(BeforeJavaScriptsRenderingEvent $event): void
|
||||
{
|
||||
if ($event->isInline() && $event->isPriority()) {
|
||||
$assetCollector = $event->getAssetCollector();
|
||||
|
||||
$scripts = [];
|
||||
$scripts = $this->getJavaScriptFileContent($assetCollector, $scripts);
|
||||
$scripts = $this->getJavaScriptInlineContent($assetCollector, $scripts);
|
||||
|
||||
$scripts = array_unique($scripts);
|
||||
$scripts = trim(implode(LF, $scripts));
|
||||
if (!empty($scripts)) {
|
||||
$temporaryFile = GeneralUtility::writeJavaScriptContentToTemporaryFile($scripts);
|
||||
$assetCollector->addJavaScript('combined_scripts', $temporaryFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getJavaScriptFileContent(AssetCollector $assetCollector, array $scripts): array
|
||||
{
|
||||
$javaScriptFiles = $assetCollector->getJavaScripts(true);
|
||||
foreach ($javaScriptFiles as $identifier => $asset) {
|
||||
if ($asset['options']['useNonce'] ?? false) {
|
||||
continue;
|
||||
}
|
||||
if (!str_contains($asset['source'], '//') && $content = $this->getFileContent($asset['source'])) {
|
||||
$scripts[] = rtrim($content, ';') . ';';
|
||||
$assetCollector->removeJavaScript($identifier);
|
||||
}
|
||||
}
|
||||
|
||||
$javaScriptFiles = $assetCollector->getJavaScripts(false);
|
||||
foreach ($javaScriptFiles as $identifier => $asset) {
|
||||
if ($asset['options']['useNonce'] ?? false) {
|
||||
continue;
|
||||
}
|
||||
if (!str_contains($asset['source'], '//') && $content = $this->getFileContent($asset['source'])) {
|
||||
$scripts[] = rtrim($content, ';') . ';';
|
||||
$assetCollector->removeJavaScript($identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return $scripts;
|
||||
}
|
||||
|
||||
protected function getJavaScriptInlineContent(AssetCollector $assetCollector, array $scripts): array
|
||||
{
|
||||
$javaScriptInline = $assetCollector->getInlineJavaScripts(false);
|
||||
foreach ($javaScriptInline as $identifier => $asset) {
|
||||
if ($asset['options']['useNonce'] ?? false) {
|
||||
continue;
|
||||
}
|
||||
$scripts[] = $asset['source'];
|
||||
$assetCollector->removeInlineJavaScript($identifier);
|
||||
}
|
||||
return $scripts;
|
||||
}
|
||||
|
||||
protected function getFileContent(string $filePath): string
|
||||
{
|
||||
$absoluteFilePath = GeneralUtility::getFileAbsFileName($filePath);
|
||||
if (!$absoluteFilePath || !@file_exists($absoluteFilePath)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$content = (string)file_get_contents($absoluteFilePath);
|
||||
$content = preg_replace('@# sourceMappingURL=.*.js.map@', '', $content);
|
||||
|
||||
$relativeFilePath = dirname(PathUtility::getAbsoluteWebPath($absoluteFilePath));
|
||||
|
||||
return str_replace(
|
||||
[
|
||||
'url(..',
|
||||
'url("..',
|
||||
'url(\'..',
|
||||
],
|
||||
[
|
||||
'url(' . $relativeFilePath . '/..',
|
||||
'url("' . $relativeFilePath . '/..',
|
||||
'url(\'' . $relativeFilePath . '/..',
|
||||
],
|
||||
$content
|
||||
);
|
||||
}
|
||||
}
|
||||
304
Classes/Form/Element/PickColorFromImage.php
Executable file
304
Classes/Form/Element/PickColorFromImage.php
Executable file
@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\Form\Element;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
|
||||
use TYPO3\CMS\Backend\Form\NodeFactory;
|
||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\Area;
|
||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\InvalidConfigurationException;
|
||||
use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction;
|
||||
use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
use TYPO3\CMS\Core\Utility\StringUtility;
|
||||
use TYPO3Fluid\Fluid\ViEvoweb\TemplateView;
|
||||
use TYPO3Fluid\Fluid\ViEvoweb\ViewInterface;
|
||||
|
||||
class PickColorFromImage extends AbstractFormElement
|
||||
{
|
||||
/**
|
||||
* Default element configuration
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static array $defaultConfig = [
|
||||
'imageField' => 'image',
|
||||
'cropVariants' => [
|
||||
'default' => [
|
||||
'title' =>
|
||||
'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.crop_variant.default',
|
||||
'allowedAspectRatios' => [
|
||||
'16:9' => [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.16_9',
|
||||
'value' => 16 / 9,
|
||||
],
|
||||
'3:2' => [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.3_2',
|
||||
'value' => 3 / 2,
|
||||
],
|
||||
'4:3' => [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.4_3',
|
||||
'value' => 4 / 3,
|
||||
],
|
||||
'1:1' => [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.1_1',
|
||||
'value' => 1.0,
|
||||
],
|
||||
'NaN' => [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.free',
|
||||
'value' => 0.0,
|
||||
],
|
||||
],
|
||||
'selectedRatio' => 'NaN',
|
||||
'cropArea' => [
|
||||
'x' => 0.0,
|
||||
'y' => 0.0,
|
||||
'width' => 1.0,
|
||||
'height' => 1.0,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Default field information enabled for this element.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultFieldInformation = [
|
||||
'tcaDescription' => [
|
||||
'renderType' => 'tcaDescription',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Default field wizards enabled for this element.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultFieldWizard = [
|
||||
'localizationStateSelector' => [
|
||||
'renderType' => 'localizationStateSelector',
|
||||
],
|
||||
'otherLanguageContent' => [
|
||||
'renderType' => 'otherLanguageContent',
|
||||
'after' => [
|
||||
'localizationStateSelector',
|
||||
],
|
||||
],
|
||||
'defaultLanguageDifferences' => [
|
||||
'renderType' => 'defaultLanguageDifferences',
|
||||
'after' => [
|
||||
'otherLanguageContent',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
protected ViewInterface $templateView;
|
||||
|
||||
public function __construct(NodeFactory $nodeFactory, array $data)
|
||||
{
|
||||
parent::__construct($nodeFactory, $data);
|
||||
// Would be great, if we could inject the view here, but since the constructor is in the interface, we can't
|
||||
// @todo: It's unfortunate we're using Typo3Fluid TemplateView directly here. We can't
|
||||
// inject BackendViewFactory here since __construct() is polluted by NodeInterface.
|
||||
// Remove __construct() from NodeInterface to have DI, then use BackendViewFactory here.
|
||||
$view = GeneralUtility::makeInstance(TemplateView::class);
|
||||
$templatePaths = $view->getRenderingContext()->getTemplatePaths();
|
||||
$templatePaths
|
||||
->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:ew_base/Resources/Private/Templates')]);
|
||||
$templatePaths
|
||||
->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:ew_base/Resources/Private/Partials')]);
|
||||
$this->templateView = $view;
|
||||
}
|
||||
|
||||
public function render(): array
|
||||
{
|
||||
$resultArray = $this->initializeResultArray();
|
||||
$parameterArray = $this->data['parameterArray'];
|
||||
$config = $this->populateConfiguration($parameterArray['fieldConf']['config']);
|
||||
$fieldId = StringUtility::getUniqueId('formengine-color-');
|
||||
|
||||
$file = $this->getFileObject($this->data['databaseRow'], $config['imageField']);
|
||||
if (!$file) {
|
||||
$languageService = $this->getLanguageService();
|
||||
$label = $languageService->sL(
|
||||
'LLL:EXT:ew_base/Resources/Private/Language/locallang_db.xlf:imageField.empty'
|
||||
);
|
||||
$fieldLabel = $this->data['processedTca']['columns'][$config['imageField']]['label'];
|
||||
$resultArray['html'] = '
|
||||
<div class="form-control-wrap">
|
||||
<div class="form-wizards-wrap">
|
||||
<div class="form-wizards-element">
|
||||
<typo3-formengine-element-pick-color recordFieldId="' . htmlspecialchars($fieldId) . '">
|
||||
' . sprintf($label, '<strong>' . $fieldLabel . '</strong>') . '
|
||||
</typo3-formengine-element-pick-color>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
// Early return in case we do not find a file
|
||||
return $resultArray;
|
||||
}
|
||||
|
||||
$fieldInformationResult = $this->renderFieldInformation();
|
||||
$fieldInformationHtml = $fieldInformationResult['html'];
|
||||
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
|
||||
|
||||
$fieldControlResult = $this->renderFieldControl();
|
||||
$fieldControlHtml = $fieldControlResult['html'];
|
||||
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
|
||||
|
||||
$fieldWizardResult = $this->renderFieldWizard();
|
||||
$fieldWizardHtml = $fieldWizardResult['html'];
|
||||
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
|
||||
|
||||
$width = $this->formMaxWidth(
|
||||
MathUtility::forceIntegerInRange(
|
||||
$config['size'] ?? $this->defaultInputWidth,
|
||||
$this->minimumInputWidth,
|
||||
$this->maxInputWidth
|
||||
)
|
||||
);
|
||||
|
||||
$arguments = [
|
||||
'fieldInformation' => $fieldInformationHtml,
|
||||
'fieldControl' => $fieldControlHtml,
|
||||
'fieldWizard' => $fieldWizardHtml,
|
||||
'isAllowedFileExtension' => in_array(
|
||||
strtolower($file->getExtension()),
|
||||
GeneralUtility::trimExplode(',', strtolower($config['allowedExtensions'])),
|
||||
true
|
||||
),
|
||||
'image' => $file,
|
||||
'formEngine' => [
|
||||
'field' => [
|
||||
'value' => $parameterArray['itemFormElValue'],
|
||||
'name' => $parameterArray['itemFormElName'],
|
||||
],
|
||||
'validation' => '[]',
|
||||
],
|
||||
'config' => $config,
|
||||
'width' => $width,
|
||||
];
|
||||
|
||||
if ($arguments['isAllowedFileExtension']) {
|
||||
$resultArray['stylesheetFiles'][] =
|
||||
'EXT:ew_base/Resources/Public/JavaScript/form-engine/element/pick-color-from-image.css';
|
||||
$resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::create(
|
||||
'@evoweb/ew-base/form-engine/element/pick-color-from-image.js',
|
||||
'PickColorFromImage'
|
||||
)->instance(
|
||||
$fieldId,
|
||||
$parameterArray['itemFormElValue'],
|
||||
($parameterArray['fieldConf']['config']['readOnly'] ?? false)
|
||||
);
|
||||
$arguments['formEngine']['field']['id'] = $fieldId;
|
||||
if ($config['required'] ?? false) {
|
||||
$arguments['formEngine']['validation'] = $this->getValidationDataAsJsonString(['required' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->templateView->assignMultiple($arguments);
|
||||
$resultArray['html'] = $this->templateView->render('Form/ImageManipulationElement');
|
||||
|
||||
return $resultArray;
|
||||
}
|
||||
|
||||
protected function getFileObject(array $row, string $fieldName): ?File
|
||||
{
|
||||
$file = null;
|
||||
$fileUid = !empty($row[$fieldName]) ? $row[$fieldName] : null;
|
||||
if (is_array($fileUid) && isset($fileUid[0]['uid'])) {
|
||||
$fileUid = $fileUid[0]['uid'];
|
||||
}
|
||||
if (MathUtility::canBeInterpretedAsInteger($fileUid)) {
|
||||
try {
|
||||
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||
$fileReference = $resourceFactory->getFileReferenceObject($fileUid);
|
||||
$file = $fileReference->getOriginalFile();
|
||||
} catch (FileDoesNotExistException | \InvalidArgumentException) {
|
||||
}
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
protected function populateConfiguration(array $baseConfiguration): array
|
||||
{
|
||||
$defaultConfig = self::$defaultConfig;
|
||||
$config = array_replace_recursive($defaultConfig, $baseConfiguration);
|
||||
$imageConfig = $this->data['processedTca']['columns'][$config['imageField']];
|
||||
$config['cropVariants'] = $imageConfig['config']['cropVariants'] ?? $defaultConfig['cropVariants'];
|
||||
|
||||
if (!is_array($config['cropVariants'])) {
|
||||
throw new InvalidConfigurationException('Crop variants configuration must be an array', 1485377267);
|
||||
}
|
||||
|
||||
$cropVariants = [];
|
||||
foreach ($config['cropVariants'] as $id => $cropVariant) {
|
||||
// Filter allowed aspect ratios
|
||||
$cropVariant['allowedAspectRatios'] = array_filter(
|
||||
$cropVariant['allowedAspectRatios'] ?? [],
|
||||
static function ($aspectRatio) {
|
||||
return !(bool)($aspectRatio['disabled'] ?? false);
|
||||
}
|
||||
);
|
||||
|
||||
// Ignore disabled crop variants
|
||||
if (!empty($cropVariant['disabled'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($cropVariant['allowedAspectRatios'])) {
|
||||
throw new InvalidConfigurationException(
|
||||
'Crop variants configuration ' . $id . ' contains no allowed aspect ratios',
|
||||
1620147893
|
||||
);
|
||||
}
|
||||
|
||||
// Enforce a crop area (default is full image)
|
||||
if (empty($cropVariant['cropArea'])) {
|
||||
$cropVariant['cropArea'] = Area::createEmpty()->asArray();
|
||||
}
|
||||
|
||||
$cropVariants[$id] = $cropVariant;
|
||||
}
|
||||
|
||||
$config['cropVariants'] = $cropVariants;
|
||||
|
||||
$config['allowedExtensions'] ??= $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
protected function processConfiguration(array $config, string &$elementValue, File $file): array
|
||||
{
|
||||
$cropVariantCollection = CropVariantCollection::create($elementValue, $config['cropVariants']);
|
||||
if (empty($config['readOnly']) && !empty($file->getProperty('width'))) {
|
||||
$cropVariantCollection = $cropVariantCollection->applyRatioRestrictionToSelectedCropArea($file);
|
||||
$elementValue = (string)$cropVariantCollection;
|
||||
}
|
||||
$config['cropVariants'] = $cropVariantCollection->asArray();
|
||||
$config['allowedExtensions'] = implode(
|
||||
', ',
|
||||
GeneralUtility::trimExplode(',', $config['allowedExtensions'], true)
|
||||
);
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
56
Classes/Form/FormDataProvider/UsercentricsDatabaseEditRow.php
Executable file
56
Classes/Form/FormDataProvider/UsercentricsDatabaseEditRow.php
Executable file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\Form\FormDataProvider;
|
||||
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\SiteDatabaseEditRow;
|
||||
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
|
||||
use TYPO3\CMS\Core\Site\SiteFinder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class UsercentricsDatabaseEditRow extends SiteDatabaseEditRow
|
||||
{
|
||||
/**
|
||||
* First level of ['customData']['siteData'] to ['databaseRow']
|
||||
*
|
||||
* @param array $result
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function addData(array $result): array
|
||||
{
|
||||
if ($result['command'] !== 'edit' || $result['tableName'] !== 'site_usercentrics') {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$tableName = $result['tableName'];
|
||||
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class, $this->siteConfiguration);
|
||||
if (in_array($tableName, ['site_usercentrics'], true)) {
|
||||
$rootPageId = (int)($result['inlineTopMostParentUid'] ?? $result['inlineParentUid']);
|
||||
try {
|
||||
$rowData = $this->getRawConfigurationForSiteWithRootPageId($siteFinder, $rootPageId);
|
||||
$parentFieldName = $result['inlineParentFieldName'];
|
||||
if (!isset($rowData[$parentFieldName])) {
|
||||
throw new \RuntimeException('Field "' . $parentFieldName . '" not found', 1520886092);
|
||||
}
|
||||
$rowData = $rowData[$parentFieldName][$result['vanillaUid']];
|
||||
$result['databaseRow']['uid'] = $result['vanillaUid'];
|
||||
} catch (SiteNotFoundException $e) {
|
||||
$rowData = [];
|
||||
}
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($rowData as $fieldName => $value) {
|
||||
// Flat values only - databaseRow has no "tree"
|
||||
if (!is_array($value)) {
|
||||
$result['databaseRow'][$fieldName] = $value;
|
||||
}
|
||||
}
|
||||
// All "records" are always on pid 0
|
||||
$result['databaseRow']['pid'] = 0;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
55
Classes/Form/FormDataProvider/UsercentricsTcaInline.php
Executable file
55
Classes/Form/FormDataProvider/UsercentricsTcaInline.php
Executable file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace Evoweb\EwBase\Form\FormDataProvider;
|
||||
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline;
|
||||
|
||||
/**
|
||||
* Special data provider for the sites configuration module.
|
||||
*
|
||||
* Handle inline children of 'site'
|
||||
*/
|
||||
class UsercentricsTcaInline extends SiteTcaInline
|
||||
{
|
||||
/**
|
||||
* Resolve inline fields
|
||||
*
|
||||
* @param array $result
|
||||
* @return array
|
||||
*/
|
||||
public function addData(array $result): array
|
||||
{
|
||||
$result = $this->addInlineFirstPid($result);
|
||||
foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
|
||||
if (!$this->isInlineField($fieldConfig)) {
|
||||
continue;
|
||||
}
|
||||
$childTableName = $fieldConfig['config']['foreign_table'] ?? '';
|
||||
if (!in_array($childTableName, ['site_usercentrics'], true)) {
|
||||
continue;
|
||||
}
|
||||
$result['processedTca']['columns'][$fieldName]['children'] = [];
|
||||
$result = $this->resolveSiteRelatedChildren($result, $fieldName);
|
||||
if (!empty($result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'])) {
|
||||
throw new \RuntimeException('selectorOrUniqueConfiguration not implemented in sites module', 1624313533);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
34
Classes/Hooks/PageLayoutView.php
Executable file
34
Classes/Hooks/PageLayoutView.php
Executable file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\Hooks;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class PageLayoutView
|
||||
{
|
||||
public function contentIsUsed(array $params): bool
|
||||
{
|
||||
return $params['used'] || $this->findCTypeBegin($params['record']['CType']);
|
||||
}
|
||||
|
||||
public function findCTypeBegin($cType): bool
|
||||
{
|
||||
$found = false;
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['ContentUsedStrings'] ?? [] as $search) {
|
||||
if (str_contains($cType, $search)) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
102
Classes/Hooks/UsercentricsPostRenderHook.php
Executable file
102
Classes/Hooks/UsercentricsPostRenderHook.php
Executable file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\Hooks;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Exception;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Site\SiteFinder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class UsercentricsPostRenderHook
|
||||
{
|
||||
private array $siteArguments = [
|
||||
'id' => '',
|
||||
'version' => 'loader',
|
||||
'useBlocker' => false,
|
||||
];
|
||||
|
||||
public function executePostRenderHook(array $params): void
|
||||
{
|
||||
$pageUid = $this->getRequest()->getAttribute('frontend.controller')->page['uid'] ?? 0;
|
||||
if ($pageUid < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$siteArguments = $this->getCurrentSiteArguments($pageUid);
|
||||
$id = $siteArguments['id'] ?? '';
|
||||
if ($id !== '') {
|
||||
$extensionConfig = $this->getExtensionConfiguration();
|
||||
|
||||
$preload = [];
|
||||
$usercentrics = [];
|
||||
|
||||
// CMP 1, 2, ...
|
||||
$version = $siteArguments['version'] ?? '';
|
||||
if ($config = $extensionConfig[$version] ?? false) {
|
||||
$preload[] = $config['preload'] ?? '';
|
||||
$usercentrics[] = $config['template'] ?? '';
|
||||
}
|
||||
|
||||
// Blocker
|
||||
if (
|
||||
($siteArguments['useBlocker'] ?? false)
|
||||
&& $config = $extensionConfig['block'] ?? false
|
||||
) {
|
||||
$preload[] = $config['preload'] ?? '';
|
||||
$usercentrics[] = $config['template'] ?? '';
|
||||
}
|
||||
|
||||
$params['titleTag'] .= str_replace('###ID###', $id, implode(LF, array_merge($preload, $usercentrics)));
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCurrentSiteArguments(int $pageUid): array
|
||||
{
|
||||
$siteArguments = $this->siteArguments;
|
||||
|
||||
try {
|
||||
/** @var SiteFinder $siteFinder */
|
||||
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
|
||||
$site = $siteFinder->getSiteByPageId($pageUid);
|
||||
foreach ($site->getAttribute('usercentrics') as $usercentrics) {
|
||||
if (str_contains($usercentrics['applicationContext'] ?? '', (string)Environment::getContext())) {
|
||||
$siteArguments = $usercentrics;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception) {
|
||||
}
|
||||
|
||||
return is_array($siteArguments) ? $siteArguments : [];
|
||||
}
|
||||
|
||||
protected function getExtensionConfiguration(): array
|
||||
{
|
||||
/** @var ExtensionConfiguration $extensionConfiguration */
|
||||
$extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
|
||||
try {
|
||||
$configuration = $extensionConfiguration->get('ew_base', 'userCentrics');
|
||||
} catch (Exception) {
|
||||
$configuration = [];
|
||||
}
|
||||
return is_array($configuration) ? $configuration : [];
|
||||
}
|
||||
|
||||
protected function getRequest(): ServerRequestInterface
|
||||
{
|
||||
return $GLOBALS['TYPO3_REQUEST'];
|
||||
}
|
||||
}
|
||||
98
Classes/ToolbarItems/ReleaseToolbarItem.php
Executable file
98
Classes/ToolbarItems/ReleaseToolbarItem.php
Executable file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ToolbarItems;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Toolbar\RequestAwareToolbarItemInterface;
|
||||
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
|
||||
use TYPO3\CMS\Backend\View\BackendViewFactory;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class ReleaseToolbarItem implements ToolbarItemInterface, RequestAwareToolbarItemInterface
|
||||
{
|
||||
private ServerRequestInterface $request;
|
||||
|
||||
public function __construct(
|
||||
private readonly BackendViewFactory $backendViewFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
public function setRequest(ServerRequestInterface $request): void
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
public function checkAccess(): bool
|
||||
{
|
||||
$result = false;
|
||||
$backendUser = $this->getBackendUser();
|
||||
if ($backendUser->isAdmin()) {
|
||||
$result = true;
|
||||
}
|
||||
if ($backendUser->getTSConfig()['options.']['showSystemInformation'] ?? false) {
|
||||
$result = true;
|
||||
}
|
||||
$release = $this->getRelease();
|
||||
if (empty($release)) {
|
||||
$result = false;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getItem(): string
|
||||
{
|
||||
$view = $this->backendViewFactory->create($this->request, ['typo3/cms-backend', 'evoweb/ew-base']);
|
||||
return $view->render('ToolbarItems/ShowReleaseToolbarItem');
|
||||
}
|
||||
|
||||
public function hasDropDown(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDropDown(): string
|
||||
{
|
||||
$view = $this->backendViewFactory->create($this->request, ['typo3/cms-backend', 'evoweb/ew-base']);
|
||||
$view->assignMultiple([
|
||||
'release' => $this->getRelease(),
|
||||
]);
|
||||
return $view->render('ToolbarItems/ShowReleaseDropDown');
|
||||
}
|
||||
|
||||
public function getAdditionalAttributes(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getIndex(): int
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
protected function getRelease(): array
|
||||
{
|
||||
$release = GeneralUtility::getUrl(Environment::getProjectPath() . '/release');
|
||||
return $release ? [
|
||||
'release' => trim($release),
|
||||
'isTag' => str_contains($release, '.'),
|
||||
] : [];
|
||||
}
|
||||
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
}
|
||||
101
Classes/Updates/GridelementsToContainerMigration.php
Executable file
101
Classes/Updates/GridelementsToContainerMigration.php
Executable file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\Updates;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
|
||||
use TYPO3\CMS\Core\Log\LogManager;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Install\Attribute\UpgradeWizard;
|
||||
use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite;
|
||||
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
|
||||
|
||||
/**
|
||||
* Migrate gridelements elements to container elements
|
||||
*/
|
||||
#[UpgradeWizard('gridelementsToContainer')]
|
||||
class GridelementsToContainerMigration implements UpgradeWizardInterface
|
||||
{
|
||||
private const TABLE_NAME = 'tt_content';
|
||||
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
public function __construct(
|
||||
protected GridelementsToContainerService $service,
|
||||
protected LogManager $logManager,
|
||||
) {
|
||||
$this->logger = $logManager->getLogger(self::class);
|
||||
}
|
||||
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'gridelementsToContainer';
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Migrate gridelements to container';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Migrates content elements that are type gridelements to corresponding container elements';
|
||||
}
|
||||
|
||||
public function getPrerequisites(): array
|
||||
{
|
||||
return [
|
||||
DatabaseUpdatedPrerequisite::class
|
||||
];
|
||||
}
|
||||
|
||||
public function updateNecessary(): bool
|
||||
{
|
||||
return $this->hasRecordsToUpdate();
|
||||
}
|
||||
|
||||
public function executeUpdate(): bool
|
||||
{
|
||||
$updateSuccessful = true;
|
||||
try {
|
||||
$this->service->migrate();
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->log(LogLevel::ERROR, $exception->getMessage());
|
||||
$updateSuccessful = false;
|
||||
}
|
||||
|
||||
return $updateSuccessful;
|
||||
}
|
||||
|
||||
protected function hasRecordsToUpdate(): bool
|
||||
{
|
||||
return (bool)$this->getPreparedQueryBuilder()->count('uid')->executeQuery()->fetchOne();
|
||||
}
|
||||
|
||||
protected function getPreparedQueryBuilder(): QueryBuilder
|
||||
{
|
||||
$queryBuilder = $this->getConnectionPool()->getQueryBuilderForTable(self::TABLE_NAME);
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeByType(HiddenRestriction::class)
|
||||
->removeByType(StartTimeRestriction::class)
|
||||
->removeByType(EndTimeRestriction::class);
|
||||
$queryBuilder
|
||||
->from(self::TABLE_NAME)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('gridelements_pi1'))
|
||||
);
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
protected function getConnectionPool(): ConnectionPool
|
||||
{
|
||||
return GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
}
|
||||
}
|
||||
268
Classes/Updates/GridelementsToContainerService.php
Executable file
268
Classes/Updates/GridelementsToContainerService.php
Executable file
@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\Updates;
|
||||
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
|
||||
use TYPO3\CMS\Core\DataHandling\DataHandler;
|
||||
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['migrationResolveContainer'] = [];
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['migrationColPosOffset'] = 0;
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['migrationMapping'] = [
|
||||
'130' => [
|
||||
'CType' => 'three-col-columns',
|
||||
],
|
||||
'140' => [
|
||||
'CType' => [
|
||||
'search' => 'pi_flexform/type',
|
||||
'matches' => [
|
||||
0 => 'two-col-columns-11',
|
||||
1 => 'two-col-columns-12',
|
||||
2 => 'two-col-columns-21',
|
||||
],
|
||||
],
|
||||
'map' => [
|
||||
'pi_flexform/row_class' => 'frame_class',
|
||||
]
|
||||
],
|
||||
];
|
||||
*/
|
||||
|
||||
class GridelementsToContainerService
|
||||
{
|
||||
private const TABLE_NAME = 'tt_content';
|
||||
|
||||
protected array $resolveContainer = [];
|
||||
|
||||
protected int $colPosOffset = 0;
|
||||
|
||||
protected array $configuration = [];
|
||||
|
||||
public function __construct(
|
||||
protected ConnectionPool $connectionPool,
|
||||
protected DataHandler $dataHandler,
|
||||
protected FlexFormService $flexFormService,
|
||||
) {
|
||||
$config =& $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base'];
|
||||
$this->resolveContainer = $config['migrationResolveContainer'] ?? [];
|
||||
$this->colPosOffset = $config['migrationColPosOffset'] ?? 0;
|
||||
$this->configuration = $config['migrationMapping'] ?? [];
|
||||
}
|
||||
|
||||
public function migrate(): void
|
||||
{
|
||||
$this->initializeDataHandler();
|
||||
|
||||
// Move children out of container and remove container
|
||||
foreach ($this->resolveContainer as $containerId) {
|
||||
$this->resolveContainers((string)$containerId);
|
||||
}
|
||||
|
||||
$this->migrateConfiguredContainer();
|
||||
}
|
||||
|
||||
protected function initializeDataHandler(): void
|
||||
{
|
||||
$backendUser = GeneralUtility::makeInstance(BackendUserAuthentication::class);
|
||||
$backendUser->user = [
|
||||
'uid' => 0,
|
||||
'admin' => 1,
|
||||
];
|
||||
$this->dataHandler->start([], [], $backendUser);
|
||||
}
|
||||
|
||||
|
||||
protected function resolveContainers(string $layout): void
|
||||
{
|
||||
$containers = $this->getGridElementsByLayout($layout);
|
||||
foreach ($containers as $container) {
|
||||
$this->processContainerResolve($container);
|
||||
}
|
||||
}
|
||||
|
||||
protected function processContainerResolve(array $container): void
|
||||
{
|
||||
$children = $this->getGridContainerChildren($container['uid']);
|
||||
// move first child after container
|
||||
$moveAfterThis = $container;
|
||||
foreach ($children as $child) {
|
||||
[$moveAfterThis, $container] = $this->processContainerResolveChild($child, $moveAfterThis, $container);
|
||||
}
|
||||
|
||||
$this->deleteElement($container['uid']);
|
||||
}
|
||||
|
||||
protected function processContainerResolveChild(array $child, array $moveAfterThis, array $container): array
|
||||
{
|
||||
$this->updateElement(
|
||||
$child['uid'],
|
||||
[
|
||||
'tx_gridelements_container' => 0,
|
||||
'colPos' => $container['colPos'],
|
||||
'header' => $child['header'] ?: $container['header']
|
||||
]
|
||||
);
|
||||
$this->moveElementAfterElement($child['uid'], $moveAfterThis['uid']);
|
||||
// use this child to move the next child after
|
||||
$moveAfterThis = $child;
|
||||
// empty container header so only the first child gets the header
|
||||
$container['header'] = '';
|
||||
|
||||
return [$moveAfterThis, $container];
|
||||
}
|
||||
|
||||
protected function deleteElement(int $uid): void
|
||||
{
|
||||
$this->connectionPool
|
||||
->getConnectionForTable(self::TABLE_NAME)
|
||||
->update(self::TABLE_NAME, ['delete' => 1], ['uid' => $uid]);
|
||||
}
|
||||
|
||||
protected function moveElementAfterElement(int $elementToMove, int $elementToMoveAfter): void
|
||||
{
|
||||
$this->dataHandler->moveRecord(self::TABLE_NAME, $elementToMove, $elementToMoveAfter * -1);
|
||||
}
|
||||
|
||||
|
||||
protected function migrateConfiguredContainer(): void
|
||||
{
|
||||
array_walk($this->configuration, function($config, $key) {
|
||||
$containers = $this->getGridElementsByLayout((string)$key);
|
||||
foreach ($containers as $container) {
|
||||
$container['pi_flexform'] = $this->flexFormService->convertFlexFormContentToArray(
|
||||
$container['pi_flexform']
|
||||
);
|
||||
$this->processContainerMigration($container, $config);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function processContainerMigration(array $container, array $config): void
|
||||
{
|
||||
$children = $this->getGridContainerChildren($container['uid']);
|
||||
foreach ($children as $child) {
|
||||
$this->processContainerMigrationChild($child, $container);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'CType' => $this->getCType($container, $config),
|
||||
'tx_gridelements_backend_layout' => ''
|
||||
];
|
||||
|
||||
if (isset($config['map']) && is_array($config['map']) && !empty($container['pi_flexform'])) {
|
||||
$data = $this->addMappedValues($data, $container, $config['map']);
|
||||
}
|
||||
|
||||
$this->updateElement($container['uid'], $data);
|
||||
}
|
||||
|
||||
protected function processContainerMigrationChild(array $child, array $container): void
|
||||
{
|
||||
$this->updateElement(
|
||||
$child['uid'],
|
||||
[
|
||||
'hidden' => $child['hidden'] ?: $container['hidden'],
|
||||
'colPos' => $child['tx_gridelements_columns'] + $this->colPosOffset,
|
||||
'tx_container_parent' => $child['tx_gridelements_container'],
|
||||
'tx_gridelements_columns' => 0,
|
||||
'tx_gridelements_container' => 0,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function getCType(array $container, array $config): string
|
||||
{
|
||||
if (is_array($config['CType'])) {
|
||||
$value = ArrayUtility::getValueByPath($container, $config['CType']['search']);
|
||||
$result = $config['CType']['matches'][$value] ?? null;
|
||||
} else {
|
||||
$result = $config['CType'] ?? null;
|
||||
}
|
||||
|
||||
if (empty($result)) {
|
||||
throw new \Exception('CType must always be set');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function addMappedValues(array $data, array $container, array $config): array
|
||||
{
|
||||
foreach ($config as $from => $to) {
|
||||
try {
|
||||
$value = ArrayUtility::getValueByPath($container, $from);
|
||||
if (empty($container[$to]) && !empty($value)) {
|
||||
$data[$to] = $value;
|
||||
}
|
||||
} catch (\throwable) {}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
protected function updateElement(int $uid, array $changes): void
|
||||
{
|
||||
$this->connectionPool
|
||||
->getConnectionForTable(self::TABLE_NAME)
|
||||
->update(self::TABLE_NAME, $changes, ['uid' => $uid]);
|
||||
}
|
||||
|
||||
protected function getGridContainerChildren(int $containerUid): array
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilderForTable();
|
||||
|
||||
return $queryBuilder
|
||||
->select('*')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'tx_gridelements_container',
|
||||
$queryBuilder->createNamedParameter($containerUid, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->orderBy('sorting')
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
}
|
||||
|
||||
protected function getGridElementsByLayout(string $layout): array
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilderForTable();
|
||||
$expr = $queryBuilder->expr();
|
||||
|
||||
return $queryBuilder
|
||||
->select('*')
|
||||
->where(
|
||||
$expr->eq('CType', $queryBuilder->createNamedParameter('gridelements_pi1')),
|
||||
$expr->eq('tx_gridelements_backend_layout', $queryBuilder->createNamedParameter($layout))
|
||||
)
|
||||
->orderBy('sorting')
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
}
|
||||
|
||||
protected function getQueryBuilderForTable(string $table = 'tt_content'): QueryBuilder
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable($table);
|
||||
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeByType(HiddenRestriction::class)
|
||||
->removeByType(StartTimeRestriction::class)
|
||||
->removeByType(EndTimeRestriction::class);
|
||||
|
||||
$queryBuilder->from($table);
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
}
|
||||
111
Classes/Updates/ParentChildToContainerMigration.php
Executable file
111
Classes/Updates/ParentChildToContainerMigration.php
Executable file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\Updates;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
|
||||
use TYPO3\CMS\Core\Log\LogManager;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Install\Attribute\UpgradeWizard;
|
||||
use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite;
|
||||
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
|
||||
|
||||
/**
|
||||
* Migrate parent child elements to container elements
|
||||
*/
|
||||
#[UpgradeWizard('parentChildToContainer')]
|
||||
class ParentChildToContainerMigration implements UpgradeWizardInterface
|
||||
{
|
||||
private const TABLE_NAME = 'tt_content';
|
||||
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
public function __construct(
|
||||
protected ParentChildToContainerService $service,
|
||||
protected LogManager $logManager,
|
||||
) {
|
||||
$this->logger = $logManager->getLogger(self::class);
|
||||
}
|
||||
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'parentChildToContainer';
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Migrate parent/child to container';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Migrates content elements that are type parent/child to corresponding container elements';
|
||||
}
|
||||
|
||||
public function getPrerequisites(): array
|
||||
{
|
||||
return [
|
||||
DatabaseUpdatedPrerequisite::class
|
||||
];
|
||||
}
|
||||
|
||||
public function updateNecessary(): bool
|
||||
{
|
||||
return $this->hasRecordsToUpdate();
|
||||
}
|
||||
|
||||
public function executeUpdate(): bool
|
||||
{
|
||||
$updateSuccessful = true;
|
||||
try {
|
||||
$this->service->migrate();
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->log(LogLevel::ERROR, $exception->getMessage());
|
||||
$updateSuccessful = false;
|
||||
}
|
||||
|
||||
return $updateSuccessful;
|
||||
}
|
||||
|
||||
protected function hasRecordsToUpdate(): bool
|
||||
{
|
||||
$queryBuilder = $this->getPreparedQueryBuilder();
|
||||
$tableColumns = $queryBuilder
|
||||
->getConnection()
|
||||
->createSchemaManager()
|
||||
->listTableColumns(self::TABLE_NAME);
|
||||
return isset($tableColumns['parent'])
|
||||
&& $queryBuilder
|
||||
->count('uid')
|
||||
->executeQuery()
|
||||
->fetchOne() > 0;
|
||||
}
|
||||
|
||||
protected function getPreparedQueryBuilder(): QueryBuilder
|
||||
{
|
||||
$queryBuilder = $this->getConnectionPool()->getQueryBuilderForTable(self::TABLE_NAME);
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeByType(HiddenRestriction::class)
|
||||
->removeByType(StartTimeRestriction::class)
|
||||
->removeByType(EndTimeRestriction::class);
|
||||
$queryBuilder
|
||||
->from(self::TABLE_NAME)
|
||||
->where(
|
||||
// check if there are still records that have parent instead of tx_container_parent
|
||||
$queryBuilder->expr()->gt('parent', 0)
|
||||
);
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
protected function getConnectionPool(): ConnectionPool
|
||||
{
|
||||
return GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
}
|
||||
}
|
||||
168
Classes/Updates/ParentChildToContainerService.php
Executable file
168
Classes/Updates/ParentChildToContainerService.php
Executable file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\Updates;
|
||||
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
|
||||
use TYPO3\CMS\Core\DataHandling\DataHandler;
|
||||
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['childParentColPosOffset'] = 0;
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['childParentMigrationMapping'] = [
|
||||
'downloads' => [ 'CType' => 'container-downloads' ],
|
||||
];
|
||||
*/
|
||||
|
||||
class ParentChildToContainerService
|
||||
{
|
||||
private const TABLE_NAME = 'tt_content';
|
||||
|
||||
protected int $colPosOffset = 0;
|
||||
|
||||
protected array $configuration = [];
|
||||
|
||||
public function __construct(
|
||||
protected ConnectionPool $connectionPool,
|
||||
protected DataHandler $dataHandler,
|
||||
protected FlexFormService $flexFormService,
|
||||
) {
|
||||
$config =& $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base'];
|
||||
$this->colPosOffset = $config['childParentColPosOffset'] ?? 0;
|
||||
$this->configuration = $config['childParentMigrationMapping'] ?? [];
|
||||
}
|
||||
|
||||
public function migrate(): void
|
||||
{
|
||||
$this->initializeDataHandler();
|
||||
$this->migrateConfiguredContainer();
|
||||
}
|
||||
|
||||
protected function initializeDataHandler(): void
|
||||
{
|
||||
$backendUser = GeneralUtility::makeInstance(BackendUserAuthentication::class);
|
||||
$backendUser->user = [
|
||||
'uid' => 0,
|
||||
'admin' => 1,
|
||||
];
|
||||
$this->dataHandler->start([], [], $backendUser);
|
||||
}
|
||||
|
||||
|
||||
protected function migrateConfiguredContainer(): void
|
||||
{
|
||||
array_walk($this->configuration, function($config, $key) {
|
||||
$parents = $this->getParentsByCType((string)$key);
|
||||
foreach ($parents as $parent) {
|
||||
$this->processParentMigration($parent, $config);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function processParentMigration(array $parent, array $config): void
|
||||
{
|
||||
$children = $this->getChildren($parent['uid']);
|
||||
foreach ($children as $child) {
|
||||
$this->processChildMigration($child, $parent);
|
||||
}
|
||||
|
||||
$this->updateElement(
|
||||
$parent['uid'],
|
||||
[
|
||||
'CType' => $this->getCType($parent, $config),
|
||||
'children' => 0,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function processChildMigration(array $child, array $parent): void
|
||||
{
|
||||
$this->updateElement(
|
||||
$child['uid'],
|
||||
[
|
||||
'tx_container_parent' => $parent['uid'],
|
||||
'colPos' => $child['colPos'] + $this->colPosOffset,
|
||||
'parent' => 0,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function getCType(array $container, array $config): string
|
||||
{
|
||||
if (is_array($config['CType'])) {
|
||||
$value = ArrayUtility::getValueByPath($container, $config['CType']['search']);
|
||||
$result = $config['CType']['matches'][$value] ?? null;
|
||||
} else {
|
||||
$result = $config['CType'] ?? null;
|
||||
}
|
||||
|
||||
if (empty($result)) {
|
||||
throw new \Exception('CType must always be set');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
protected function updateElement(int $uid, array $changes): void
|
||||
{
|
||||
$this->connectionPool
|
||||
->getConnectionForTable(self::TABLE_NAME)
|
||||
->update(self::TABLE_NAME, $changes, ['uid' => $uid]);
|
||||
}
|
||||
|
||||
protected function getChildren(int $parentUid): array
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilderForTable();
|
||||
|
||||
return $queryBuilder
|
||||
->select('*')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'parent',
|
||||
$queryBuilder->createNamedParameter($parentUid, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->orderBy('sorting')
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
}
|
||||
|
||||
protected function getParentsByCType(string $cType): array
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilderForTable();
|
||||
$expr = $queryBuilder->expr();
|
||||
|
||||
return $queryBuilder
|
||||
->select('*')
|
||||
->where(
|
||||
$expr->eq('CType', $queryBuilder->createNamedParameter($cType))
|
||||
)
|
||||
->orderBy('sorting')
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
}
|
||||
|
||||
protected function getQueryBuilderForTable(string $table = 'tt_content'): QueryBuilder
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable($table);
|
||||
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeByType(HiddenRestriction::class)
|
||||
->removeByType(StartTimeRestriction::class)
|
||||
->removeByType(EndTimeRestriction::class);
|
||||
|
||||
$queryBuilder->from($table);
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
}
|
||||
25
Classes/User/AssetPath.php
Executable file
25
Classes/User/AssetPath.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\User;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* EXAMPLE:
|
||||
* page.headerData.10 = USER
|
||||
* page.headerData.10.userFunc = Evoweb\EwBase\User\AssetPath->getAbsolutePublicPath
|
||||
* page.headerData.10.file = EXT:site_package/Resources/Public/manifest.json
|
||||
* page.headerData.10.stdWrap.wrap = <link rel="manifest" href="|"/>
|
||||
*/
|
||||
class AssetPath
|
||||
{
|
||||
public function getAbsolutePublicPath(string $content, array $conf): string
|
||||
{
|
||||
return $content
|
||||
. GeneralUtility::getIndpEnv('TYPO3_SITE_URL')
|
||||
. ltrim(PathUtility::getPublicResourceWebPath($conf['file']), '/');
|
||||
}
|
||||
}
|
||||
55
Classes/ViewHelpers/Array/AddViewHelper.php
Executable file
55
Classes/ViewHelpers/Array/AddViewHelper.php
Executable file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Array;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt 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\CompileWithRenderStatic;
|
||||
|
||||
class AddViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('array', 'array', 'Array to add value to');
|
||||
$this->registerArgument('key', 'string', 'Key to add value by', true);
|
||||
$this->registerArgument('value', 'mixed', 'Value to add');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$array = $arguments['array'] ?: [];
|
||||
$key = $arguments['key'];
|
||||
$value = !is_null($arguments['value']) ? $arguments['value'] : $renderChildrenClosure();
|
||||
|
||||
return array_merge($array, [$key => $value]);
|
||||
}
|
||||
}
|
||||
119
Classes/ViewHelpers/Be/ThumbnailViewHelper.php
Executable file
119
Classes/ViewHelpers/Be/ThumbnailViewHelper.php
Executable file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Be;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Type\Bitmask\Permission;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
class ThumbnailViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Initializes the arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('row', 'array', 'content data', true);
|
||||
$this->registerArgument('tableName', 'string', 'table name', true);
|
||||
$this->registerArgument('fieldName', 'string', 'field name', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a constant
|
||||
*
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return string Value of constant
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$row = $arguments['row'];
|
||||
$tableName = $arguments['tableName'];
|
||||
$fieldName = $arguments['fieldName'];
|
||||
|
||||
return self::linkEditContent(
|
||||
BackendUtility::thumbCode(row: $row, table: $tableName, field: $fieldName, linkInfoPopup: false),
|
||||
$row
|
||||
);
|
||||
}
|
||||
|
||||
protected static function linkEditContent(string $linkText, $row): string
|
||||
{
|
||||
if (empty($linkText)) {
|
||||
return $linkText;
|
||||
}
|
||||
|
||||
$backendUser = self::getBackendUser();
|
||||
if (
|
||||
$backendUser->check('tables_modify', 'tt_content')
|
||||
&& $backendUser->recordEditAccessInternals('tt_content', $row)
|
||||
&& (
|
||||
new Permission(
|
||||
$backendUser->calcPerms(BackendUtility::getRecord('pages', $row['pid']) ?? [])
|
||||
)
|
||||
)->editContentPermissionIsGranted()
|
||||
) {
|
||||
$urlParameters = [
|
||||
'edit' => [
|
||||
'tt_content' => [
|
||||
$row['uid'] => 'edit',
|
||||
],
|
||||
],
|
||||
'returnUrl' => self::getRequest()->getAttribute('normalizedParams')->getRequestUri()
|
||||
. '#element-tt_content-' . $row['uid'],
|
||||
];
|
||||
/** @var UriBuilder $uriBuilder */
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$url = (string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters);
|
||||
return '<a href="' . htmlspecialchars($url) . '" title="'
|
||||
. htmlspecialchars(self::getLanguageService()->sL(
|
||||
'LLL:EXT:typo3/sysext/backend/Resources/Private/Language/locallang_layout.xlf:edit'
|
||||
))
|
||||
. '">' . $linkText . '</a>';
|
||||
}
|
||||
return $linkText;
|
||||
}
|
||||
|
||||
protected static function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
protected static function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
protected static function getRequest(): ServerRequestInterface
|
||||
{
|
||||
return $GLOBALS['TYPO3_REQUEST'];
|
||||
}
|
||||
}
|
||||
41
Classes/ViewHelpers/Condition/InArrayViewHelper.php
Executable file
41
Classes/ViewHelpers/Condition/InArrayViewHelper.php
Executable file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Condition;
|
||||
|
||||
/*
|
||||
* 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\ViewHelper\AbstractConditionViewHelper;
|
||||
|
||||
/**
|
||||
* ### Condition: Array contains element
|
||||
*
|
||||
* Condition ViewHelper which renders the `then` child if provided
|
||||
* string $haystack contains provided string $needle.
|
||||
*/
|
||||
class InArrayViewHelper extends AbstractConditionViewHelper
|
||||
{
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('haystack', 'array', 'haystack', true);
|
||||
$this->registerArgument('needle', 'mixed', 'needle', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null)
|
||||
{
|
||||
$array = $arguments['haystack']->toArray();
|
||||
return in_array($arguments['needle'], $array);
|
||||
}
|
||||
}
|
||||
40
Classes/ViewHelpers/Condition/StringContainsViewHelper.php
Executable file
40
Classes/ViewHelpers/Condition/StringContainsViewHelper.php
Executable file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Condition;
|
||||
|
||||
/*
|
||||
* 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\ViewHelper\AbstractConditionViewHelper;
|
||||
|
||||
/**
|
||||
* ### Condition: String contains substring
|
||||
*
|
||||
* Condition ViewHelper which renders the `then` child if provided
|
||||
* string $haystack contains provided string $needle.
|
||||
*/
|
||||
class StringContainsViewHelper extends AbstractConditionViewHelper
|
||||
{
|
||||
/**
|
||||
* Initialize arguments
|
||||
*/
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('haystack', 'string', 'haystack', true);
|
||||
$this->registerArgument('needle', 'string', 'need', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null)
|
||||
{
|
||||
return false !== strpos($arguments['haystack'], $arguments['needle']);
|
||||
}
|
||||
}
|
||||
25
Classes/ViewHelpers/Context/DevelopmentViewHelper.php
Executable file
25
Classes/ViewHelpers/Context/DevelopmentViewHelper.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Context;
|
||||
|
||||
/*
|
||||
* 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 TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
|
||||
|
||||
class DevelopmentViewHelper extends AbstractConditionViewHelper
|
||||
{
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null)
|
||||
{
|
||||
return Environment::getContext()->isDevelopment();
|
||||
}
|
||||
}
|
||||
25
Classes/ViewHelpers/Context/ProductionViewHelper.php
Executable file
25
Classes/ViewHelpers/Context/ProductionViewHelper.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Context;
|
||||
|
||||
/*
|
||||
* 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 TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
|
||||
|
||||
class ProductionViewHelper extends AbstractConditionViewHelper
|
||||
{
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null)
|
||||
{
|
||||
return Environment::getContext()->isProduction();
|
||||
}
|
||||
}
|
||||
25
Classes/ViewHelpers/Context/StagingViewHelper.php
Executable file
25
Classes/ViewHelpers/Context/StagingViewHelper.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Context;
|
||||
|
||||
/*
|
||||
* 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 TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
|
||||
|
||||
class StagingViewHelper extends AbstractConditionViewHelper
|
||||
{
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected static function evaluateCondition($arguments = null)
|
||||
{
|
||||
return 'Production/Staging' === (string)Environment::getContext();
|
||||
}
|
||||
}
|
||||
77
Classes/ViewHelpers/FixFlexformForExtbaseViewHelper.php
Executable file
77
Classes/ViewHelpers/FixFlexformForExtbaseViewHelper.php
Executable file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
/**
|
||||
* = Examples =
|
||||
*
|
||||
* <code title="Simple Loop">
|
||||
* <ewb:fixFlexformForExtbase data="{data}">....</ewb:fixFlexformForExtbase>
|
||||
* </code>
|
||||
* <output>
|
||||
* fixed flexform data for extbase controller
|
||||
* </output>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class FixFlexformForExtbaseViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments(): void
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('data', 'array', 'The data array of content element', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$templateVariableContainer = $renderingContext->getVariableProvider();
|
||||
|
||||
/** @var FlexFormTools $flexFormTools */
|
||||
$flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
|
||||
|
||||
$data = $arguments['data'];
|
||||
if (is_array($data['pi_flexform'])) {
|
||||
$data['pi_flexform'] = $flexFormTools->flexArray2Xml($data['pi_flexform']);
|
||||
}
|
||||
|
||||
$templateVariableContainer->add('data', $data);
|
||||
$output = $renderChildrenClosure();
|
||||
$templateVariableContainer->remove('data');
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
80
Classes/ViewHelpers/FlexFormViewHelper.php
Executable file
80
Classes/ViewHelpers/FlexFormViewHelper.php
Executable file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* = Examples =
|
||||
*
|
||||
* <code title="Simple Loop">
|
||||
* <ewb:flexForm data="{data}">....</ewb:flexForm>
|
||||
* </code>
|
||||
* <output>
|
||||
* fixed flexform data for extbase controller
|
||||
* </output>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class FlexFormViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('data', 'array', 'Array to get flex form data from', true);
|
||||
$this->registerArgument('fieldName', 'string', 'Field name', false, 'pi_flexform');
|
||||
$this->registerArgument('as', 'string', 'Name of the variable to assign', false, 'flexFormData');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$data = [];
|
||||
|
||||
if (is_array($arguments['data'])) {
|
||||
if (isset($arguments['data'][$arguments['fieldName']])) {
|
||||
$data = is_array($arguments['data'][$arguments['fieldName']]) ?
|
||||
$arguments['data'][$arguments['fieldName']] :
|
||||
GeneralUtility::xml2array($arguments['data'][$arguments['fieldName']]);
|
||||
$data = $data['data'] ?? $data;
|
||||
}
|
||||
}
|
||||
|
||||
$templateVariableContainer = $renderingContext->getVariableProvider();
|
||||
$templateVariableContainer->add($arguments['as'], $data);
|
||||
$content = $renderChildrenClosure();
|
||||
$templateVariableContainer->remove($arguments['as']);
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
60
Classes/ViewHelpers/HashViewHelper.php
Executable file
60
Classes/ViewHelpers/HashViewHelper.php
Executable file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt 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\CompileWithRenderStatic;
|
||||
|
||||
class HashViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('action', 'string', 'Target action');
|
||||
$this->registerArgument('arguments', 'array', 'Arguments for the controller action, associative array');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$result = '';
|
||||
if (
|
||||
$arguments['action'] !== null
|
||||
&& $arguments['arguments'] !== null
|
||||
&& isset($arguments['arguments']['user'])
|
||||
) {
|
||||
$result = \TYPO3\CMS\Core\Utility\GeneralUtility::hmac(
|
||||
$arguments['action'] . '::' . $arguments['arguments']['user']
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
56
Classes/ViewHelpers/Iterator/AddViewHelper.php
Executable file
56
Classes/ViewHelpers/Iterator/AddViewHelper.php
Executable file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Iterator;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
class AddViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('array', 'array', 'Array to add value to');
|
||||
$this->registerArgument('key', 'string', 'Key to add value by', true);
|
||||
$this->registerArgument('value', 'mixed', 'Value to add');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$array = $arguments['array'] ?: [];
|
||||
$key = $arguments['key'];
|
||||
$value = $arguments['value'] ?: $renderChildrenClosure();
|
||||
|
||||
return array_merge($array, [$key => $value]);
|
||||
}
|
||||
}
|
||||
93
Classes/ViewHelpers/Iterator/ExplodeViewHelper.php
Executable file
93
Classes/ViewHelpers/Iterator/ExplodeViewHelper.php
Executable file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers\Iterator;
|
||||
|
||||
/*
|
||||
* 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\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Explode ViewHelper
|
||||
*
|
||||
* Explodes a string by $glue.
|
||||
*
|
||||
* {data.header -> ewb:iterator.explode(glue: 'constant:LF')}
|
||||
*
|
||||
* <ewb:iterator.explode content="{data.header}" as="as" glue="constant:LF">
|
||||
* <span>{as}</span>
|
||||
* </ewb:iterator.explode>
|
||||
*/
|
||||
class ExplodeViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
protected static string $method = 'explode';
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument(
|
||||
'as',
|
||||
'string',
|
||||
'Template variable name to assign; if not specified the ViewHelper returns the variable instead.'
|
||||
);
|
||||
$this->registerArgument('content', 'string', 'String to be exploded by glue');
|
||||
$this->registerArgument(
|
||||
'glue',
|
||||
'string',
|
||||
'String used as glue in the string to be exploded. Use glue value of "constant:NAMEOFCONSTANT" ' .
|
||||
'(fx "constant:LF" for linefeed as glue)',
|
||||
false,
|
||||
','
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render method
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$content = $arguments['content'] ?? $renderChildrenClosure();
|
||||
$glue = static::resolveGlue($arguments);
|
||||
$content = call_user_func_array(static::$method, [$glue, $content]);
|
||||
|
||||
$as = $arguments['as'];
|
||||
if (true === empty($as)) {
|
||||
$output = $content;
|
||||
} else {
|
||||
$templateVariableContainer = $renderingContext->getVariableProvider();
|
||||
$templateVariableContainer->add($as, $content);
|
||||
$output = $renderChildrenClosure();
|
||||
$templateVariableContainer->remove($as);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected static function resolveGlue(array $arguments): string
|
||||
{
|
||||
$glue = $arguments['glue'];
|
||||
if (false !== strpos($glue, ':') && 1 < strlen($glue)) {
|
||||
// glue contains a special type identifier, resolve the actual glue
|
||||
list ($type, $value) = explode(':', $glue);
|
||||
switch ($type) {
|
||||
case 'constant':
|
||||
$glue = constant($value);
|
||||
break;
|
||||
default:
|
||||
$glue = $value;
|
||||
}
|
||||
}
|
||||
return $glue;
|
||||
}
|
||||
}
|
||||
67
Classes/ViewHelpers/PublicPathViewHelper.php
Executable file
67
Classes/ViewHelpers/PublicPathViewHelper.php
Executable file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* = Examples =
|
||||
*
|
||||
* <code title="Simple Loop">
|
||||
* <ewb:publicPath path="{data}">....</ewb:publicPath>
|
||||
* </code>
|
||||
* <output>
|
||||
* fixed flexform data for extbase controller
|
||||
* </output>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class PublicPathViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
protected static ?array $frontendGroupIds = null;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('path', 'string', 'Extension resource path', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$path = (string)$arguments['path'];
|
||||
return PathUtility::getPublicResourceWebPath($path);
|
||||
}
|
||||
}
|
||||
72
Classes/ViewHelpers/ReplaceViewHelper.php
Executable file
72
Classes/ViewHelpers/ReplaceViewHelper.php
Executable file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt 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;
|
||||
|
||||
/**
|
||||
* Variable assigning ViewHelper
|
||||
*
|
||||
* Assigns one template variable which will exist also
|
||||
* after the ViewHelper is done rendering, i.e. adds
|
||||
* template variables.
|
||||
*
|
||||
* If you require a variable assignment which does not
|
||||
* exist in the template after a piece of Fluid code
|
||||
* is rendered, consider using ``f:alias`` ViewHelper instead.
|
||||
*
|
||||
* Usages:
|
||||
*
|
||||
* ::
|
||||
*
|
||||
* {f:variable(name: 'myvariable', value: 'some value')}
|
||||
* <f:variable name="myvariable">some value</f:variable>
|
||||
* {oldvariable -> f:format.htmlspecialchars() -> f:variable(name: 'newvariable')}
|
||||
* <f:variable name="myvariable"><f:format.htmlspecialchars>{oldvariable}</f:format.htmlspecialchars></f:variable>
|
||||
*
|
||||
* @see \TYPO3Fluid\Fluid\ViewHelpers\IfViewHelper
|
||||
* @api
|
||||
*/
|
||||
class ReplaceViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithContentArgumentAndRenderStatic;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('value', 'string', 'String to replace in');
|
||||
$this->registerArgument('search', 'string', 'Search string');
|
||||
$this->registerArgument('replace', 'string', 'Replace value');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return null
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$content = $arguments['value'];
|
||||
if ($content === null) {
|
||||
$content = $renderChildrenClosure();
|
||||
}
|
||||
|
||||
return str_replace($arguments['search'], $arguments['replace'], $content);
|
||||
}
|
||||
}
|
||||
105
Classes/ViewHelpers/SvgViewHelper.php
Executable file
105
Classes/ViewHelpers/SvgViewHelper.php
Executable file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Imaging\IconFactory;
|
||||
use TYPO3\CMS\Core\Type\Icon\IconState;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Displays icon identified by icon identifier.
|
||||
*
|
||||
* Examples
|
||||
* ========
|
||||
*
|
||||
* Default::
|
||||
*
|
||||
* <core:icon identifier="actions-menu" />
|
||||
*
|
||||
* Output::
|
||||
*
|
||||
* <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-menu" data-identifier="actions-menu">
|
||||
* <span class="icon-markup">
|
||||
* <img src="/typo3/sysext/core/Resources/Public/Icons/T3Icons/actions/actions-menu.svg"
|
||||
* width="16" height="16">
|
||||
* </span>
|
||||
* </span>
|
||||
*
|
||||
* Inline::
|
||||
*
|
||||
* <core:icon identifier="actions-menu" alternativeMarkupIdentifier="inline" />
|
||||
*
|
||||
* Output::
|
||||
*
|
||||
* <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-menu" data-identifier="actions-menu">
|
||||
* <span class="icon-markup">
|
||||
* <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g class="icon-color"><path
|
||||
* d="M9 12v2H7v-2h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM9
|
||||
* 7v2H7V7h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM9
|
||||
* 2v2H7V2h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM4
|
||||
* 7v2H2V7h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM4
|
||||
* 2v2H2V2h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM4
|
||||
* 12v2H2v-2h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM14
|
||||
* 7v2h-2V7h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM14
|
||||
* 2v2h-2V2h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5zM14
|
||||
* 12v2h-2v-2h2m.5-1h-3c-.3 0-.5.2-.5.5v3c0 .3.2.5.5.5h3c.3 0 .5-.2.5-.5v-3c0-.3-.2-.5-.5-.5z"/>
|
||||
* </g></svg>
|
||||
* </span>
|
||||
* </span>
|
||||
*/
|
||||
class SvgViewHelper extends \TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* ViewHelper returns HTML, thus we need to disable output escaping
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments(): void
|
||||
{
|
||||
$this->registerArgument('identifier', 'string', 'Identifier of the icon as registered in the Icon Registry.', true);
|
||||
$this->registerArgument('size', 'string', 'Desired size of the icon. All values of the Icons.sizes enum are allowed, these are: "small", "default", "large" and "overlay".', false, Icon::SIZE_SMALL);
|
||||
$this->registerArgument('overlay', 'string', 'Identifier of an overlay icon as registered in the Icon Registry.', false);
|
||||
$this->registerArgument('state', 'string', 'Sets the state of the icon. All values of the Icons.states enum are allowed, these are: "default" and "disabled".', false, IconState::STATE_DEFAULT);
|
||||
$this->registerArgument('alternativeMarkupIdentifier', 'string', 'Alternative icon identifier. Takes precedence over the identifier if supported by the IconProvider.', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints icon html for $identifier key
|
||||
*
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$identifier = $arguments['identifier'];
|
||||
$size = $arguments['size'];
|
||||
$overlay = $arguments['overlay'];
|
||||
$state = IconState::cast($arguments['state']);
|
||||
$alternativeMarkupIdentifier = $arguments['alternativeMarkupIdentifier'];
|
||||
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
|
||||
return $iconFactory->getIcon($identifier, $size, $overlay, $state)->getMarkup($alternativeMarkupIdentifier);
|
||||
}
|
||||
}
|
||||
58
Classes/ViewHelpers/TrimViewHelper.php
Executable file
58
Classes/ViewHelpers/TrimViewHelper.php
Executable file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt 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\CompileWithRenderStatic;
|
||||
|
||||
class TrimViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $escapeOutput = false;
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('content', 'string', 'Content to be trimmed');
|
||||
$this->registerArgument('characters', 'string', 'Characters to be removed', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
) {
|
||||
$content = $arguments['content'] ? $arguments['content'] : $renderChildrenClosure();
|
||||
$characters = $arguments['characters'] ? $arguments['characters'] : null;
|
||||
|
||||
if ($characters !== null) {
|
||||
$content = trim($content, $characters);
|
||||
} else {
|
||||
$content = trim($content);
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
59
Classes/Xclass/SiteDatabaseEditRow.php
Executable file
59
Classes/Xclass/SiteDatabaseEditRow.php
Executable file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\Xclass;
|
||||
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\SiteDatabaseEditRow as BaseSiteDatabaseEditRow;
|
||||
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
|
||||
use TYPO3\CMS\Core\Site\SiteFinder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class SiteDatabaseEditRow extends BaseSiteDatabaseEditRow
|
||||
{
|
||||
/**
|
||||
* First level of ['customData']['siteData'] to ['databaseRow']
|
||||
*
|
||||
* @param array $result
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function addData(array $result): array
|
||||
{
|
||||
if ($result['command'] !== 'edit' || !empty($result['databaseRow'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$tableName = $result['tableName'];
|
||||
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class, $this->siteConfiguration);
|
||||
if ($tableName === 'site') {
|
||||
$rootPageId = (int)$result['vanillaUid'];
|
||||
$rowData = $this->getRawConfigurationForSiteWithRootPageId($siteFinder, $rootPageId);
|
||||
$result['databaseRow']['uid'] = $rowData['rootPageId'];
|
||||
$result['databaseRow']['identifier'] = $result['customData']['siteIdentifier'];
|
||||
} elseif (in_array($tableName, ['site_errorhandling', 'site_language', 'site_route', 'site_base_variant'], true)) {
|
||||
$rootPageId = (int)($result['inlineTopMostParentUid'] ?? $result['inlineParentUid']);
|
||||
try {
|
||||
$rowData = $this->getRawConfigurationForSiteWithRootPageId($siteFinder, $rootPageId);
|
||||
$parentFieldName = $result['inlineParentFieldName'];
|
||||
if (!isset($rowData[$parentFieldName])) {
|
||||
throw new \RuntimeException('Field "' . $parentFieldName . '" not found', 1520886092);
|
||||
}
|
||||
$rowData = $rowData[$parentFieldName][$result['vanillaUid']];
|
||||
$result['databaseRow']['uid'] = $result['vanillaUid'];
|
||||
} catch (SiteNotFoundException $e) {
|
||||
$rowData = [];
|
||||
}
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($rowData as $fieldName => $value) {
|
||||
// Flat values only - databaseRow has no "tree"
|
||||
if (!is_array($value)) {
|
||||
$result['databaseRow'][$fieldName] = $value;
|
||||
}
|
||||
}
|
||||
// All "records" are always on pid 0
|
||||
$result['databaseRow']['pid'] = 0;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
35
Classes/Xclass/SiteTcaInline.php
Executable file
35
Classes/Xclass/SiteTcaInline.php
Executable file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Evoweb\EwBase\Xclass;
|
||||
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline as BaseSiteTcaInline;
|
||||
|
||||
class SiteTcaInline extends BaseSiteTcaInline
|
||||
{
|
||||
/**
|
||||
* Resolve inline fields
|
||||
*
|
||||
* @param array $result
|
||||
* @return array
|
||||
*/
|
||||
public function addData(array $result): array
|
||||
{
|
||||
$result = $this->addInlineFirstPid($result);
|
||||
foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
|
||||
if (!$this->isInlineField($fieldConfig)) {
|
||||
continue;
|
||||
}
|
||||
$childTableName = $fieldConfig['config']['foreign_table'] ?? '';
|
||||
if (!in_array($childTableName, ['site_errorhandling', 'site_route', 'site_base_variant'], true)) {
|
||||
return $result;
|
||||
}
|
||||
$result['processedTca']['columns'][$fieldName]['children'] = [];
|
||||
$result = $this->resolveSiteRelatedChildren($result, $fieldName);
|
||||
if (!empty($result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'])) {
|
||||
throw new \RuntimeException('selectorOrUniqueConfiguration not implemented in sites module', 1624313533);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
19
Configuration/Icons.php
Executable file
19
Configuration/Icons.php
Executable file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
use TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider;
|
||||
use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
|
||||
|
||||
return [
|
||||
'ew-base-extension' => [
|
||||
'provider' => SvgIconProvider::class,
|
||||
'source' => 'EXT:ew_base/Resources/Public/Icons/Extension.svg',
|
||||
],
|
||||
'ew-base-extension-small' => [
|
||||
'provider' => SvgIconProvider::class,
|
||||
'source' => 'EXT:ew_base/Resources/Public/Icons/Extension_16.svg',
|
||||
],
|
||||
'ew-usercentrics' => [
|
||||
'provider' => BitmapIconProvider::class,
|
||||
'source' => 'EXT:ew_base/Resources/Public/Icons/usercentrics.svg',
|
||||
],
|
||||
];
|
||||
16
Configuration/JavaScriptModules.php
Executable file
16
Configuration/JavaScriptModules.php
Executable file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'dependencies' => [
|
||||
'backend',
|
||||
'core',
|
||||
],
|
||||
'tags' => [
|
||||
'backend.form',
|
||||
],
|
||||
'imports' => [
|
||||
'@evoweb/ew-base/' => [
|
||||
'path' => 'EXT:ew_base/Resources/Public/JavaScript/',
|
||||
],
|
||||
],
|
||||
];
|
||||
45
Configuration/Services.yaml
Executable file
45
Configuration/Services.yaml
Executable file
@ -0,0 +1,45 @@
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
public: false
|
||||
|
||||
Evoweb\EwBase\:
|
||||
resource: '../Classes/*'
|
||||
|
||||
Evoweb\EwBase\Command\ContentElementCommand:
|
||||
tags:
|
||||
- name: 'console.command'
|
||||
command: 'ew-base:contentelement'
|
||||
description: 'Command to list all content elements for a given subtree'
|
||||
schedulable: false
|
||||
|
||||
Evoweb\EwBase\EventListener\CssMerger:
|
||||
tags: ['event.listener']
|
||||
|
||||
Evoweb\EwBase\EventListener\JsMerger:
|
||||
tags: ['event.listener']
|
||||
|
||||
Evoweb\EwBase\EventListener\IsContentUsedOnPageLayout:
|
||||
tags: ['event.listener']
|
||||
|
||||
Evoweb\EwBase\ToolbarItems\ReleaseToolbarItem:
|
||||
tags: ['backend.toolbar.item']
|
||||
|
||||
Evoweb\EwBase\Hooks\UsercentricsPostRenderHook:
|
||||
public: true
|
||||
|
||||
Evoweb\EwBase\Updates\GridelementsToContainerMigration:
|
||||
public: true
|
||||
|
||||
Evoweb\EwBase\Updates\GridelementsToContainerService:
|
||||
public: true
|
||||
|
||||
Evoweb\EwBase\Updates\ParentChildToContainerMigration:
|
||||
public: true
|
||||
|
||||
Evoweb\EwBase\Updates\ParentChildToContainerService:
|
||||
public: true
|
||||
|
||||
Evoweb\EwBase\Form\FormDataProvider\UsercentricsDatabaseEditRow:
|
||||
public: true
|
||||
22
Configuration/SiteConfiguration/Overrides/sites.php
Executable file
22
Configuration/SiteConfiguration/Overrides/sites.php
Executable file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
$GLOBALS['SiteConfiguration']['site']['columns']['usercentrics'] = [
|
||||
'label' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_siteconfiguration.xlf:site.usercentrics',
|
||||
'description' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_siteconfiguration.xlf:site.usercentrics.description',
|
||||
'config' => [
|
||||
'type' => 'inline',
|
||||
'foreign_table' => 'site_usercentrics',
|
||||
'maxitems' => 1,
|
||||
'appearance' => [
|
||||
'enabledControls' => [
|
||||
'info' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$GLOBALS['SiteConfiguration']['site']['types']['0']['showitem'] = str_replace(
|
||||
' routes',
|
||||
' routes, usercentrics,',
|
||||
$GLOBALS['SiteConfiguration']['site']['types']['0']['showitem']
|
||||
);
|
||||
78
Configuration/SiteConfiguration/site_usercentrics.php
Executable file
78
Configuration/SiteConfiguration/site_usercentrics.php
Executable file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'ctrl' => [
|
||||
'label' => 'id',
|
||||
'title' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_siteconfiguration.xlf:site_usercentrics.ctrl.title',
|
||||
'typeicon_classes' => [
|
||||
'default' => 'ew-usercentrics',
|
||||
],
|
||||
],
|
||||
'columns' => [
|
||||
'id' => [
|
||||
'label' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_siteconfiguration.xlf:site_usercentrics.column.id',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'size' => 12,
|
||||
'max' => 12,
|
||||
],
|
||||
],
|
||||
'version' => [
|
||||
'label' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_siteconfiguration.xlf:site_usercentrics.column.version',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'minitems' => 0,
|
||||
'maxitems' => 1,
|
||||
'size' => 1,
|
||||
'items' => [
|
||||
[
|
||||
0 => 'CMP 2',
|
||||
1 => 'loader',
|
||||
],
|
||||
[
|
||||
0 => 'CMP 1',
|
||||
1 => 'main',
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
'applicationContext' => [
|
||||
'label' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_siteconfiguration.xlf:site_usercentrics.column.applicationContext',
|
||||
'description' => 'Values are separated by line breaks',
|
||||
'config' => [
|
||||
'type' => 'text',
|
||||
'eval' => 'trim',
|
||||
],
|
||||
],
|
||||
'useBlocker' => [
|
||||
'label' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_siteconfiguration.xlf:site_usercentrics.column.useBlocker',
|
||||
'config' => [
|
||||
'type' => 'check',
|
||||
'renderType' => 'checkboxToggle',
|
||||
'default' => false,
|
||||
'items' => [
|
||||
[
|
||||
0 => '',
|
||||
1 => true,
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
'types' => [
|
||||
'1' => [
|
||||
'showitem' => '
|
||||
--palette--;;usercentrics,
|
||||
',
|
||||
],
|
||||
],
|
||||
'palettes' => [
|
||||
'usercentrics' => [
|
||||
'showitem' => '
|
||||
id, version, --linebreak--,
|
||||
applicationContext, useBlocker,
|
||||
'
|
||||
]
|
||||
]
|
||||
];
|
||||
35
Configuration/TCA/Overrides/pages.php
Executable file
35
Configuration/TCA/Overrides/pages.php
Executable file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
|
||||
$newColumns = [
|
||||
'sectionIndex_uid' => [
|
||||
'displayCond' => 'FIELD:doktype:=:4',
|
||||
'label' => 'LLL:EXT:ew_base/Resources/Private/Language/locallang_db.xlf:pages.content_uid',
|
||||
'config' => [
|
||||
'type' => 'group',
|
||||
'allowed' => 'tt_content',
|
||||
'size' => 1,
|
||||
'maxitems' => 1,
|
||||
'minitems' => 0,
|
||||
'suggestOptions' => [
|
||||
'default' => [
|
||||
'additionalSearchFields' => 'header, bodytext',
|
||||
'searchWholePhrase' => false
|
||||
]
|
||||
],
|
||||
'default' => 0,
|
||||
'behaviour' => [
|
||||
'allowLanguageSynchronization' => true
|
||||
]
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
ExtensionManagementUtility::addTCAcolumns('pages', $newColumns);
|
||||
ExtensionManagementUtility::addFieldsToPalette(
|
||||
'pages',
|
||||
'shortcutpage',
|
||||
'--linebreak--, sectionIndex_uid',
|
||||
'after:shortcut'
|
||||
);
|
||||
26
Configuration/Yaml/Csp/Cookiebot.yaml
Executable file
26
Configuration/Yaml/Csp/Cookiebot.yaml
Executable file
@ -0,0 +1,26 @@
|
||||
mutations:
|
||||
connect:
|
||||
mode: extend
|
||||
directive: connect-src
|
||||
sources:
|
||||
- https://consentcdn.cookiebot.com/
|
||||
|
||||
frame:
|
||||
mode: extend
|
||||
directive: frame-src
|
||||
sources:
|
||||
- https://consentcdn.cookiebot.com/
|
||||
|
||||
script-src:
|
||||
mode: extend
|
||||
directive: script-src-elem
|
||||
sources:
|
||||
- https://consent.cookiebot.com/
|
||||
- https://consentcdn.cookiebot.com/
|
||||
|
||||
style-src:
|
||||
mode: extend
|
||||
directive: style-src-elem
|
||||
sources:
|
||||
- https://consent.cookiebot.com/
|
||||
- https://consentcdn.cookiebot.com/
|
||||
12
Configuration/Yaml/Csp/GoogleAdsConversions.yaml
Executable file
12
Configuration/Yaml/Csp/GoogleAdsConversions.yaml
Executable file
@ -0,0 +1,12 @@
|
||||
mutations:
|
||||
- mode: extend
|
||||
directive: script-src
|
||||
sources:
|
||||
- https://www.googleadservices.com
|
||||
- https://www.google.com
|
||||
|
||||
- mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://googleads.g.doubleclick.net
|
||||
- https://www.google.com
|
||||
17
Configuration/Yaml/Csp/GoogleAdsRemarketing.yaml
Executable file
17
Configuration/Yaml/Csp/GoogleAdsRemarketing.yaml
Executable file
@ -0,0 +1,17 @@
|
||||
mutations:
|
||||
- mode: extend
|
||||
directive: script-src
|
||||
sources:
|
||||
- https://www.googleadservices.com
|
||||
- https://googleads.g.doubleclick.net
|
||||
- https://www.google.com
|
||||
|
||||
- mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://www.google.com
|
||||
|
||||
- mode: extend
|
||||
directive: frame-src
|
||||
sources:
|
||||
- https://bid.g.doubleclick.net
|
||||
27
Configuration/Yaml/Csp/GoogleAnalytics4.yaml
Executable file
27
Configuration/Yaml/Csp/GoogleAnalytics4.yaml
Executable file
@ -0,0 +1,27 @@
|
||||
mutations:
|
||||
script:
|
||||
mode: extend
|
||||
directive: script-src
|
||||
sources:
|
||||
- https://*.googletagmanager.com
|
||||
|
||||
script-src:
|
||||
mode: extend
|
||||
directive: script-src-elem
|
||||
sources:
|
||||
- https://*.googletagmanager.com
|
||||
|
||||
img:
|
||||
mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://*.google-analytics.com
|
||||
- https://*.googletagmanager.com
|
||||
|
||||
connect:
|
||||
mode: extend
|
||||
directive: connect-src
|
||||
sources:
|
||||
- https://*.google-analytics.com
|
||||
- https://*.analytics.google.com
|
||||
- https://*.googletagmanager.com
|
||||
385
Configuration/Yaml/Csp/GoogleAnalytics4Signals.yaml
Executable file
385
Configuration/Yaml/Csp/GoogleAnalytics4Signals.yaml
Executable file
@ -0,0 +1,385 @@
|
||||
mutations:
|
||||
- mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://*.analytics.google.com
|
||||
- https://*.g.doubleclick.net
|
||||
- https://*.google.com
|
||||
- https://*.google.ad
|
||||
- https://*.google.ae
|
||||
- https://*.google.com.af
|
||||
- https://*.google.com.ag
|
||||
- https://*.google.al
|
||||
- https://*.google.am
|
||||
- https://*.google.co.ao
|
||||
- https://*.google.com.ar
|
||||
- https://*.google.as
|
||||
- https://*.google.at
|
||||
- https://*.google.com.au
|
||||
- https://*.google.az
|
||||
- https://*.google.ba
|
||||
- https://*.google.com.bd
|
||||
- https://*.google.be
|
||||
- https://*.google.bf
|
||||
- https://*.google.bg
|
||||
- https://*.google.com.bh
|
||||
- https://*.google.bi
|
||||
- https://*.google.bj
|
||||
- https://*.google.com.bn
|
||||
- https://*.google.com.bo
|
||||
- https://*.google.com.br
|
||||
- https://*.google.bs
|
||||
- https://*.google.bt
|
||||
- https://*.google.co.bw
|
||||
- https://*.google.by
|
||||
- https://*.google.com.bz
|
||||
- https://*.google.ca
|
||||
- https://*.google.cd
|
||||
- https://*.google.cf
|
||||
- https://*.google.cg
|
||||
- https://*.google.ch
|
||||
- https://*.google.ci
|
||||
- https://*.google.co.ck
|
||||
- https://*.google.cl
|
||||
- https://*.google.cm
|
||||
- https://*.google.cn
|
||||
- https://*.google.com.co
|
||||
- https://*.google.co.cr
|
||||
- https://*.google.com.cu
|
||||
- https://*.google.cv
|
||||
- https://*.google.com.cy
|
||||
- https://*.google.cz
|
||||
- https://*.google.de
|
||||
- https://*.google.dj
|
||||
- https://*.google.dk
|
||||
- https://*.google.dm
|
||||
- https://*.google.com.do
|
||||
- https://*.google.dz
|
||||
- https://*.google.com.ec
|
||||
- https://*.google.ee
|
||||
- https://*.google.com.eg
|
||||
- https://*.google.es
|
||||
- https://*.google.com.et
|
||||
- https://*.google.fi
|
||||
- https://*.google.com.fj
|
||||
- https://*.google.fm
|
||||
- https://*.google.fr
|
||||
- https://*.google.ga
|
||||
- https://*.google.ge
|
||||
- https://*.google.gg
|
||||
- https://*.google.com.gh
|
||||
- https://*.google.com.gi
|
||||
- https://*.google.gl
|
||||
- https://*.google.gm
|
||||
- https://*.google.gr
|
||||
- https://*.google.com.gt
|
||||
- https://*.google.gy
|
||||
- https://*.google.com.hk
|
||||
- https://*.google.hn
|
||||
- https://*.google.hr
|
||||
- https://*.google.ht
|
||||
- https://*.google.hu
|
||||
- https://*.google.co.id
|
||||
- https://*.google.ie
|
||||
- https://*.google.co.il
|
||||
- https://*.google.im
|
||||
- https://*.google.co.in
|
||||
- https://*.google.iq
|
||||
- https://*.google.is
|
||||
- https://*.google.it
|
||||
- https://*.google.je
|
||||
- https://*.google.com.jm
|
||||
- https://*.google.jo
|
||||
- https://*.google.co.jp
|
||||
- https://*.google.co.ke
|
||||
- https://*.google.com.kh
|
||||
- https://*.google.ki
|
||||
- https://*.google.kg
|
||||
- https://*.google.co.kr
|
||||
- https://*.google.com.kw
|
||||
- https://*.google.kz
|
||||
- https://*.google.la
|
||||
- https://*.google.com.lb
|
||||
- https://*.google.li
|
||||
- https://*.google.lk
|
||||
- https://*.google.co.ls
|
||||
- https://*.google.lt
|
||||
- https://*.google.lu
|
||||
- https://*.google.lv
|
||||
- https://*.google.com.ly
|
||||
- https://*.google.co.ma
|
||||
- https://*.google.md
|
||||
- https://*.google.me
|
||||
- https://*.google.mg
|
||||
- https://*.google.mk
|
||||
- https://*.google.ml
|
||||
- https://*.google.com.mm
|
||||
- https://*.google.mn
|
||||
- https://*.google.com.mt
|
||||
- https://*.google.mu
|
||||
- https://*.google.mv
|
||||
- https://*.google.mw
|
||||
- https://*.google.com.mx
|
||||
- https://*.google.com.my
|
||||
- https://*.google.co.mz
|
||||
- https://*.google.com.na
|
||||
- https://*.google.com.ng
|
||||
- https://*.google.com.ni
|
||||
- https://*.google.ne
|
||||
- https://*.google.nl
|
||||
- https://*.google.no
|
||||
- https://*.google.com.np
|
||||
- https://*.google.nr
|
||||
- https://*.google.nu
|
||||
- https://*.google.co.nz
|
||||
- https://*.google.com.om
|
||||
- https://*.google.com.pa
|
||||
- https://*.google.com.pe
|
||||
- https://*.google.com.pg
|
||||
- https://*.google.com.ph
|
||||
- https://*.google.com.pk
|
||||
- https://*.google.pl
|
||||
- https://*.google.pn
|
||||
- https://*.google.com.pr
|
||||
- https://*.google.ps
|
||||
- https://*.google.pt
|
||||
- https://*.google.com.py
|
||||
- https://*.google.com.qa
|
||||
- https://*.google.ro
|
||||
- https://*.google.ru
|
||||
- https://*.google.rw
|
||||
- https://*.google.com.sa
|
||||
- https://*.google.com.sb
|
||||
- https://*.google.sc
|
||||
- https://*.google.se
|
||||
- https://*.google.com.sg
|
||||
- https://*.google.sh
|
||||
- https://*.google.si
|
||||
- https://*.google.sk
|
||||
- https://*.google.com.sl
|
||||
- https://*.google.sn
|
||||
- https://*.google.so
|
||||
- https://*.google.sm
|
||||
- https://*.google.sr
|
||||
- https://*.google.st
|
||||
- https://*.google.com.sv
|
||||
- https://*.google.td
|
||||
- https://*.google.tg
|
||||
- https://*.google.co.th
|
||||
- https://*.google.com.tj
|
||||
- https://*.google.tl
|
||||
- https://*.google.tm
|
||||
- https://*.google.tn
|
||||
- https://*.google.to
|
||||
- https://*.google.com.tr
|
||||
- https://*.google.tt
|
||||
- https://*.google.com.tw
|
||||
- https://*.google.co.tz
|
||||
- https://*.google.com.ua
|
||||
- https://*.google.co.ug
|
||||
- https://*.google.co.uk
|
||||
- https://*.google.com.uy
|
||||
- https://*.google.co.uz
|
||||
- https://*.google.com.vc
|
||||
- https://*.google.co.ve
|
||||
- https://*.google.co.vi
|
||||
- https://*.google.com.vn
|
||||
- https://*.google.vu
|
||||
- https://*.google.ws
|
||||
- https://*.google.rs
|
||||
- https://*.google.co.za
|
||||
- https://*.google.co.zm
|
||||
- https://*.google.co.zw
|
||||
- https://*.google.cat
|
||||
|
||||
- mode: extend
|
||||
directive: connect-src
|
||||
sources:
|
||||
- https://*.g.doubleclick.net
|
||||
- https://*.google.com
|
||||
- https://*.google.ad
|
||||
- https://*.google.ae
|
||||
- https://*.google.com.af
|
||||
- https://*.google.com.ag
|
||||
- https://*.google.al
|
||||
- https://*.google.am
|
||||
- https://*.google.co.ao
|
||||
- https://*.google.com.ar
|
||||
- https://*.google.as
|
||||
- https://*.google.at
|
||||
- https://*.google.com.au
|
||||
- https://*.google.az
|
||||
- https://*.google.ba
|
||||
- https://*.google.com.bd
|
||||
- https://*.google.be
|
||||
- https://*.google.bf
|
||||
- https://*.google.bg
|
||||
- https://*.google.com.bh
|
||||
- https://*.google.bi
|
||||
- https://*.google.bj
|
||||
- https://*.google.com.bn
|
||||
- https://*.google.com.bo
|
||||
- https://*.google.com.br
|
||||
- https://*.google.bs
|
||||
- https://*.google.bt
|
||||
- https://*.google.co.bw
|
||||
- https://*.google.by
|
||||
- https://*.google.com.bz
|
||||
- https://*.google.ca
|
||||
- https://*.google.cd
|
||||
- https://*.google.cf
|
||||
- https://*.google.cg
|
||||
- https://*.google.ch
|
||||
- https://*.google.ci
|
||||
- https://*.google.co.ck
|
||||
- https://*.google.cl
|
||||
- https://*.google.cm
|
||||
- https://*.google.cn
|
||||
- https://*.google.com.co
|
||||
- https://*.google.co.cr
|
||||
- https://*.google.com.cu
|
||||
- https://*.google.cv
|
||||
- https://*.google.com.cy
|
||||
- https://*.google.cz
|
||||
- https://*.google.de
|
||||
- https://*.google.dj
|
||||
- https://*.google.dk
|
||||
- https://*.google.dm
|
||||
- https://*.google.com.do
|
||||
- https://*.google.dz
|
||||
- https://*.google.com.ec
|
||||
- https://*.google.ee
|
||||
- https://*.google.com.eg
|
||||
- https://*.google.es
|
||||
- https://*.google.com.et
|
||||
- https://*.google.fi
|
||||
- https://*.google.com.fj
|
||||
- https://*.google.fm
|
||||
- https://*.google.fr
|
||||
- https://*.google.ga
|
||||
- https://*.google.ge
|
||||
- https://*.google.gg
|
||||
- https://*.google.com.gh
|
||||
- https://*.google.com.gi
|
||||
- https://*.google.gl
|
||||
- https://*.google.gm
|
||||
- https://*.google.gr
|
||||
- https://*.google.com.gt
|
||||
- https://*.google.gy
|
||||
- https://*.google.com.hk
|
||||
- https://*.google.hn
|
||||
- https://*.google.hr
|
||||
- https://*.google.ht
|
||||
- https://*.google.hu
|
||||
- https://*.google.co.id
|
||||
- https://*.google.ie
|
||||
- https://*.google.co.il
|
||||
- https://*.google.im
|
||||
- https://*.google.co.in
|
||||
- https://*.google.iq
|
||||
- https://*.google.is
|
||||
- https://*.google.it
|
||||
- https://*.google.je
|
||||
- https://*.google.com.jm
|
||||
- https://*.google.jo
|
||||
- https://*.google.co.jp
|
||||
- https://*.google.co.ke
|
||||
- https://*.google.com.kh
|
||||
- https://*.google.ki
|
||||
- https://*.google.kg
|
||||
- https://*.google.co.kr
|
||||
- https://*.google.com.kw
|
||||
- https://*.google.kz
|
||||
- https://*.google.la
|
||||
- https://*.google.com.lb
|
||||
- https://*.google.li
|
||||
- https://*.google.lk
|
||||
- https://*.google.co.ls
|
||||
- https://*.google.lt
|
||||
- https://*.google.lu
|
||||
- https://*.google.lv
|
||||
- https://*.google.com.ly
|
||||
- https://*.google.co.ma
|
||||
- https://*.google.md
|
||||
- https://*.google.me
|
||||
- https://*.google.mg
|
||||
- https://*.google.mk
|
||||
- https://*.google.ml
|
||||
- https://*.google.com.mm
|
||||
- https://*.google.mn
|
||||
- https://*.google.com.mt
|
||||
- https://*.google.mu
|
||||
- https://*.google.mv
|
||||
- https://*.google.mw
|
||||
- https://*.google.com.mx
|
||||
- https://*.google.com.my
|
||||
- https://*.google.co.mz
|
||||
- https://*.google.com.na
|
||||
- https://*.google.com.ng
|
||||
- https://*.google.com.ni
|
||||
- https://*.google.ne
|
||||
- https://*.google.nl
|
||||
- https://*.google.no
|
||||
- https://*.google.com.np
|
||||
- https://*.google.nr
|
||||
- https://*.google.nu
|
||||
- https://*.google.co.nz
|
||||
- https://*.google.com.om
|
||||
- https://*.google.com.pa
|
||||
- https://*.google.com.pe
|
||||
- https://*.google.com.pg
|
||||
- https://*.google.com.ph
|
||||
- https://*.google.com.pk
|
||||
- https://*.google.pl
|
||||
- https://*.google.pn
|
||||
- https://*.google.com.pr
|
||||
- https://*.google.ps
|
||||
- https://*.google.pt
|
||||
- https://*.google.com.py
|
||||
- https://*.google.com.qa
|
||||
- https://*.google.ro
|
||||
- https://*.google.ru
|
||||
- https://*.google.rw
|
||||
- https://*.google.com.sa
|
||||
- https://*.google.com.sb
|
||||
- https://*.google.sc
|
||||
- https://*.google.se
|
||||
- https://*.google.com.sg
|
||||
- https://*.google.sh
|
||||
- https://*.google.si
|
||||
- https://*.google.sk
|
||||
- https://*.google.com.sl
|
||||
- https://*.google.sn
|
||||
- https://*.google.so
|
||||
- https://*.google.sm
|
||||
- https://*.google.sr
|
||||
- https://*.google.st
|
||||
- https://*.google.com.sv
|
||||
- https://*.google.td
|
||||
- https://*.google.tg
|
||||
- https://*.google.co.th
|
||||
- https://*.google.com.tj
|
||||
- https://*.google.tl
|
||||
- https://*.google.tm
|
||||
- https://*.google.tn
|
||||
- https://*.google.to
|
||||
- https://*.google.com.tr
|
||||
- https://*.google.tt
|
||||
- https://*.google.com.tw
|
||||
- https://*.google.co.tz
|
||||
- https://*.google.com.ua
|
||||
- https://*.google.co.ug
|
||||
- https://*.google.co.uk
|
||||
- https://*.google.com.uy
|
||||
- https://*.google.co.uz
|
||||
- https://*.google.com.vc
|
||||
- https://*.google.co.ve
|
||||
- https://*.google.co.vi
|
||||
- https://*.google.com.vn
|
||||
- https://*.google.vu
|
||||
- https://*.google.ws
|
||||
- https://*.google.rs
|
||||
- https://*.google.co.za
|
||||
- https://*.google.co.zm
|
||||
- https://*.google.co.zw
|
||||
- https://*.google.cat
|
||||
17
Configuration/Yaml/Csp/GoogleAnalytics4SignalsEu.yaml
Executable file
17
Configuration/Yaml/Csp/GoogleAnalytics4SignalsEu.yaml
Executable file
@ -0,0 +1,17 @@
|
||||
mutations:
|
||||
img:
|
||||
mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://*.analytics.google.com
|
||||
- https://*.g.doubleclick.net
|
||||
- https://*.google.com
|
||||
- https://*.google.ie
|
||||
|
||||
connect:
|
||||
mode: extend
|
||||
directive: connect-src
|
||||
sources:
|
||||
- https://*.g.doubleclick.net
|
||||
- https://*.google.com
|
||||
- https://*.google.ie
|
||||
5
Configuration/Yaml/Csp/GoogleOptimize.yaml
Executable file
5
Configuration/Yaml/Csp/GoogleOptimize.yaml
Executable file
@ -0,0 +1,5 @@
|
||||
mutations:
|
||||
- mode: extend
|
||||
directive: script-src
|
||||
sources:
|
||||
- https://www.google-analytics.com
|
||||
26
Configuration/Yaml/Csp/GoogleTagManagerPreview.yaml
Executable file
26
Configuration/Yaml/Csp/GoogleTagManagerPreview.yaml
Executable file
@ -0,0 +1,26 @@
|
||||
mutations:
|
||||
script:
|
||||
mode: extend
|
||||
directive: script-src
|
||||
sources:
|
||||
- https://tagmanager.google.com
|
||||
|
||||
style:
|
||||
mode: extend
|
||||
directive: style-src
|
||||
sources:
|
||||
- https://tagmanager.google.com
|
||||
- https://fonts.googleapis.com
|
||||
|
||||
img:
|
||||
mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://ssl.gstatic.com
|
||||
- https://www.gstatic.com
|
||||
|
||||
font:
|
||||
mode: extend
|
||||
directive: font-src
|
||||
sources:
|
||||
- https://fonts.gstatic.com
|
||||
6
Configuration/Yaml/Csp/MapBox.yaml
Executable file
6
Configuration/Yaml/Csp/MapBox.yaml
Executable file
@ -0,0 +1,6 @@
|
||||
mutations:
|
||||
img:
|
||||
mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://api.mapbox.com/
|
||||
16
Configuration/Yaml/Csp/UniversalAnalytics.yaml
Executable file
16
Configuration/Yaml/Csp/UniversalAnalytics.yaml
Executable file
@ -0,0 +1,16 @@
|
||||
mutations:
|
||||
- mode: extend
|
||||
directive: script-src
|
||||
sources:
|
||||
- https://www.google-analytics.com
|
||||
- https://ssl.google-analytics.com
|
||||
|
||||
- mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://www.google-analytics.com
|
||||
|
||||
- mode: extend
|
||||
directive: connect-src
|
||||
sources:
|
||||
- https://www.google-analytics.com
|
||||
12
Configuration/Yaml/Csp/Youtube.yaml
Executable file
12
Configuration/Yaml/Csp/Youtube.yaml
Executable file
@ -0,0 +1,12 @@
|
||||
mutations:
|
||||
frame:
|
||||
mode: extend
|
||||
directive: frame-src
|
||||
sources:
|
||||
- https://www.youtube-nocookie.com
|
||||
|
||||
img:
|
||||
mode: extend
|
||||
directive: img-src
|
||||
sources:
|
||||
- https://i.ytimg.com/
|
||||
19
README.md
Executable file
19
README.md
Executable file
@ -0,0 +1,19 @@
|
||||
# ew-base
|
||||
## Usercentrics Hook Guide
|
||||
|
||||
Add this snippet to your config/sites to enable the hook
|
||||
```yaml
|
||||
usercentrics:
|
||||
-
|
||||
id: LNxzTaK8j
|
||||
version: loader
|
||||
useBlocker: false
|
||||
applicationContext: "Production/Staging\r\nProduction\r\nDevelopment\r\n"
|
||||
```
|
||||
|
||||
```
|
||||
id - Usercentrics Id
|
||||
version (loader | main) - loader is the v2 and main is v1 in usercentrics context
|
||||
useBlocker - if the content blocker script should be rendered
|
||||
applicationContext - multiline string of application contexts that the snippets should be rendered in
|
||||
```
|
||||
17
Resources/Private/Language/locallang_core.xlf
Executable file
17
Resources/Private/Language/locallang_core.xlf
Executable file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" datatype="plaintext" original="messages" date="2023-02-07T14:19:01Z">
|
||||
<header/>
|
||||
<body>
|
||||
<trans-unit id="rm.release">
|
||||
<source>Release information</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="rm.release_label-tag">
|
||||
<source>Release tag</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="rm.release_label-branch">
|
||||
<source>Release branch</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
15
Resources/Private/Language/locallang_db.xlf
Executable file
15
Resources/Private/Language/locallang_db.xlf
Executable file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" datatype="plaintext" original="messages" date="2020-02-07T14:19:01Z">
|
||||
<header/>
|
||||
<body>
|
||||
<trans-unit id="pages.content_uid">
|
||||
<source>Content element to jump to</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="imageField.empty">
|
||||
<source>Please and an image in field '%1$s' and save the record before picking a color.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
33
Resources/Private/Language/locallang_siteconfiguration.xlf
Executable file
33
Resources/Private/Language/locallang_siteconfiguration.xlf
Executable file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" datatype="plaintext" original="messages" date="2020-02-07T14:19:01Z">
|
||||
<header/>
|
||||
<body>
|
||||
<trans-unit id="site.usercentrics">
|
||||
<source>UserCentrics</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="site.usercentrics.description">
|
||||
<source>Max one configuration per site</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="site_usercentrics.ctrl.title">
|
||||
<source>Usercentrics configuration</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="site_usercentrics.column.id">
|
||||
<source>ID</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="site_usercentrics.column.id.description">
|
||||
<source>ID defining what user centrics account to use</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="site_usercentrics.column.version">
|
||||
<source>Version</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="site_usercentrics.column.applicationContext">
|
||||
<source>Application Context</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="site_usercentrics.column.useBlocker">
|
||||
<source>use Blocker</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
49
Resources/Private/Templates/Form/ImageManipulationElement.html
Executable file
49
Resources/Private/Templates/Form/ImageManipulationElement.html
Executable file
@ -0,0 +1,49 @@
|
||||
<html
|
||||
xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
|
||||
data-namespace-typo3-fluid="true">
|
||||
|
||||
<div class="formengine-field-item t3js-formengine-field-item">
|
||||
|
||||
{fieldInformation -> f:format.raw()}
|
||||
|
||||
<div class="form-control-wrap">
|
||||
<div class="form-wizards-wrap">
|
||||
<div class="form-wizards-element">
|
||||
<typo3-formengine-element-pick-color recordFieldId="{formEngine.field.id}">
|
||||
<div class="form-control-wrap" style="max-width: {width}px">
|
||||
<input type="text" value="" id="{formEngine.field.id}" class="form-control t3js-clearable"
|
||||
data-formengine-validation-rules="[]"
|
||||
data-formengine-input-params="{f:format.json(value: {
|
||||
field: formEngine.field.name,
|
||||
evalList: 'trim'
|
||||
})}"
|
||||
data-formengine-input-name="{formEngine.field.name}"/>
|
||||
<input type="hidden" name="{formEngine.field.name}" value="{formEngine.field.value -> f:format.htmlspecialchars()}" />
|
||||
</div>
|
||||
|
||||
<div class="picker">
|
||||
<div class="preview"></div>
|
||||
|
||||
<img src="{f:uri.image(image: image, maxWidth: width, cropVariant: config.cropVariants.0.id)}" alt=""
|
||||
class="picker-thumbnail thumbnail"
|
||||
style="max-width: {width}px; {f:if(condition: formEngine.field.value, then: 'background: {formEngine.field.value -> f:format.htmlspecialchars()}')}"/>
|
||||
|
||||
<canvas id="{formEngine.field.id}-cs" class="pick-color-canvas"></canvas>
|
||||
</div>
|
||||
</typo3-formengine-element-pick-color>
|
||||
</div>
|
||||
|
||||
<div class="form-wizards-items-aside form-wizards-items-aside--field-control">
|
||||
<div class="btn-group">
|
||||
{fieldControl -> f:format.raw()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-wizards-items-bottom">
|
||||
{fieldWizard -> f:format.raw()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
||||
12
Resources/Private/Templates/ToolbarItems/ShowReleaseDropDown.html
Executable file
12
Resources/Private/Templates/ToolbarItems/ShowReleaseDropDown.html
Executable file
@ -0,0 +1,12 @@
|
||||
<html xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" data-namespace-typo3-fluid="true">
|
||||
|
||||
<h3 class="dropdown-headline"><f:translate id="LLL:EXT:ew_base/Resources/Private/Language/locallang_core.xlf:rm.release" /></h3>
|
||||
<table class="dropdown-table">
|
||||
<tr>
|
||||
<th data-type="icon"><core:icon identifier="information-git" size="small" /></th>
|
||||
<th data-type="title"><f:translate id="LLL:EXT:ew_base/Resources/Private/Language/locallang_core.xlf:rm.release_label-{f:if(condition: release.isTag, then: 'tag', else: 'branch')}" /></th>
|
||||
<td data-type="value" class="text-{f:if(condition: release.isTag, then: 'success', else: 'warning')}">{release.release -> f:format.htmlentities()}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</html>
|
||||
8
Resources/Private/Templates/ToolbarItems/ShowReleaseToolbarItem.html
Executable file
8
Resources/Private/Templates/ToolbarItems/ShowReleaseToolbarItem.html
Executable file
@ -0,0 +1,8 @@
|
||||
<html xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" data-namespace-typo3-fluid="true">
|
||||
|
||||
<f:render partial="ToolbarItems/ToolbarItem" arguments="{
|
||||
title: 'LLL:EXT:ew_base/Resources/Private/Language/locallang_core.xlf:rm.release',
|
||||
icon: '{core:icon(identifier: \'ew-base-extension-small\', size: \'small\', alternativeMarkupIdentifier: \'inline\')}'
|
||||
}" />
|
||||
|
||||
</html>
|
||||
6
Resources/Public/Icons/Extension.svg
Executable file
6
Resources/Public/Icons/Extension.svg
Executable file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg id="svg2" xmlns="http://www.w3.org/2000/svg" height="9in" width="9in" version="1.1" viewBox="0 0 640 640">
|
||||
|
||||
<path id="Auswahl1" d="m4.73 377l-4.73-45c-1.17-100.04 31.51-196.72 110-262.56 42.12-35.33 96.7-58.01 151-65.57l36-3.87h49s38 4.58 38 4.58c35.73 5.54 72.58 17.87 104 35.85 53.09 30.37 91.35 72.89 118.24 127.57 23.12 47.01 33.76 98.83 33.76 151h-555l1 18c0.07 13.74 5.29 37.39 8.88 51l3.12 11-81 29c-5.4-12.32-10.25-37.27-12.27-51zm489.43-221s-8.16-8.91-8.16-8.91c-34.3-32.33-78.39-52.53-125-58.81-9.87-1.33-20.05-2.26-30-2.28l-11-0.66s-17 0.66-17 0.66l-19 1.84c-35.79 3.82-69.99 15.91-100 35.83-30.13 20-55.03 47.97-71.25 80.33-4.56 9.1-12.24 25.24-13.75 35h443c-10.63-31.88-25.41-57.89-47.84-83z" fill="#87b200"/>
|
||||
<path id="Auswahl2" d="m143.72 481c12.28 14.12 25.74 25.64 41.28 36 3.08 2.05 12.54 8.89 16 8.28 2.62-0.46 6.12-4.4 8-6.28l15.09-16s56.91-57 56.91-57l29-29c2.36-2.36 7.37-8.57 11-7.66 2.27 0.56 6.26 4.92 8 6.66l18 18 64 64 21 21c2.17 2.17 5.77 7.05 9.17 6.3 1.5-0.33 7.18-3.9 8.83-4.9 8.04-4.85 15.75-10.51 23-16.48 30.57-25.21 51.43-56.38 66-92.92 4.35-10.9 8.34-24.51 10.79-36 0.59-2.78 1.84-12.51 3.8-13.96 2.4-1.78 13.18 0.83 16.41 1.37 0 0 47 8.18 47 8.18 3.47 0.58 16.03 1.63 17.36 4.72 1.15 2.68-2.21 17.15-3.01 20.69-4.17 18.44-9.52 36.44-16.55 54-27.05 67.63-74.22 122.45-139.8 155.25-10.16 5.07-28.35 13.19-39 16.4-7.8 2.36-9.68-1.34-15-6.65l-15-15s-63-64-63-64l-16-16c-1.63-1.6-4.58-4.96-7-4.96-2.73 0-7.1 5.06-9 6.96l-20 20s-16.01 17-16.01 17-37.99 38-37.99 38l-25 24.36c-4.38 2.57-10.64-0.84-15-2.36-10.8-3.75-27.07-10.98-37-16.58-39.58-22.32-67.36-44.68-94.87-81.42-6.36-8.48-21.15-29.57-24.13-39l49-28.42 25-13.58c8.24 15.58 17.18 27.74 28.72 41z" fill="#4f660b"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
6
Resources/Public/Icons/Extension_16.svg
Executable file
6
Resources/Public/Icons/Extension_16.svg
Executable file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
|
||||
<rect width="100%" height="100%" class="icon-color"/>
|
||||
<path fill="#2F2F2F" d="M 7.523438 1.125 L 9.050781 1.125 L 5.175781 14.875 L 3.675781 14.875 Z M 7.523438 1.125 "/>
|
||||
<path fill="#2F2F2F" d="M 10.550781 1.125 L 12.074219 1.125 L 8.199219 14.875 L 6.699219 14.875 Z M 10.550781 1.125 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 413 B |
15
Resources/Public/Icons/usercentrics.svg
Executable file
15
Resources/Public/Icons/usercentrics.svg
Executable file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="layer" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 176 176" style="enable-background:new 0 0 176 176;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#0095FF;}
|
||||
.st1{fill:#B8CEE1;}
|
||||
.st2{fill:#0D47A1;}
|
||||
.st3{fill:#F25900;}
|
||||
</style>
|
||||
<circle class="st0" cx="90.9" cy="88.7" r="26.4"/>
|
||||
<circle class="st1" cx="145.1" cy="35.4" r="10.2"/>
|
||||
<circle class="st2" cx="124.8" cy="132" r="18.3"/>
|
||||
<circle class="st3" cx="34.8" cy="110.9" r="14.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 677 B |
@ -0,0 +1,9 @@
|
||||
.pick-color-canvas {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.picker-thumbnail {
|
||||
cursor: crosshair;
|
||||
width: 100%;
|
||||
border-top: solid 20px transparent;
|
||||
}
|
||||
83
Resources/Public/JavaScript/form-engine/element/pick-color-from-image.js
Executable file
83
Resources/Public/JavaScript/form-engine/element/pick-color-from-image.js
Executable file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is developed by evoWeb.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
export class PickColorFromImage {
|
||||
constructor(fieldId, value, readOnly) {
|
||||
this.value = value;
|
||||
this.readOnly = readOnly;
|
||||
this.image = document.querySelector(`[recordFieldId="${fieldId}"] img`);
|
||||
this.canvas = document.querySelector(`#${fieldId}-cs`);
|
||||
this.result = document.querySelector(`#${fieldId}`);
|
||||
|
||||
this.initializeEvents();
|
||||
this.updateCanvas();
|
||||
}
|
||||
|
||||
initializeEvents() {
|
||||
if (!this.readOnly) {
|
||||
this.image.addEventListener('resize', event => this.imageResized(event));
|
||||
this.image.addEventListener('click', event => this.imageClicked(event));
|
||||
this.image.addEventListener('mousemove', event => this.imageMousemove(event));
|
||||
this.image.addEventListener('mouseout', event => this.imageMouseout(event));
|
||||
}
|
||||
}
|
||||
|
||||
imageResized() {
|
||||
this.updateCanvas();
|
||||
}
|
||||
|
||||
imageClicked(event) {
|
||||
this.value = this.getColorForCoordinates(this.getEventCoordinates(event));
|
||||
this.result.value = this.value;
|
||||
this.result.dispatchEvent(new Event('change', {bubbles: !0}));
|
||||
}
|
||||
|
||||
imageMousemove(event) {
|
||||
this.image.style.borderTopColor = this.getColorForCoordinates(this.getEventCoordinates(event));
|
||||
}
|
||||
|
||||
imageMouseout() {
|
||||
this.image.style.borderTopColor = this.value;
|
||||
}
|
||||
|
||||
getEventCoordinates(event) {
|
||||
let x, y;
|
||||
if (event.offsetX) {
|
||||
x = event.offsetX;
|
||||
y = event.offsetY;
|
||||
} else if (event.layerX) {
|
||||
x = event.layerX;
|
||||
y = event.layerY;
|
||||
}
|
||||
|
||||
return { x: x, y: y };
|
||||
}
|
||||
|
||||
getColorForCoordinates(coordinates) {
|
||||
let p = this.canvas.getContext('2d').getImageData(coordinates.x, coordinates.y, 1, 1).data;
|
||||
return this.rgbToHex(p[0], p[1], p[2]);
|
||||
}
|
||||
|
||||
updateCanvas() {
|
||||
this.canvas.width = this.image.width;
|
||||
this.canvas.height = this.image.height;
|
||||
this.canvas.getContext('2d').drawImage(this.image, 0, 0, this.image.width, this.image.height);
|
||||
}
|
||||
|
||||
rgbToHex(r, g, b) {
|
||||
return '#' + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b);
|
||||
}
|
||||
|
||||
componentToHex(c) {
|
||||
let hex = parseInt(c, 10).toString(16);
|
||||
return hex.length === 1 ? '0' + hex : hex;
|
||||
}
|
||||
}
|
||||
47
composer.json
Executable file
47
composer.json
Executable file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "evoweb/ew-base",
|
||||
"type": "typo3-cms-extension",
|
||||
"version": "1.0.0",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Evoweb\\EwBase\\": "Classes/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"typo3/cms-core": "^11.5 || ^12.4 || dev-main",
|
||||
|
||||
"typo3/cms-backend": "*",
|
||||
"typo3/cms-extbase": "*",
|
||||
"typo3/cms-extensionmanager": "*",
|
||||
"typo3/cms-filelist": "*",
|
||||
"typo3/cms-fluid": "*",
|
||||
"typo3/cms-frontend": "*",
|
||||
"typo3/cms-install": "*",
|
||||
"typo3/cms-recordlist": "*",
|
||||
|
||||
"typo3/cms-adminpanel": "*",
|
||||
"typo3/cms-belog": "*",
|
||||
"typo3/cms-beuser": "*",
|
||||
"typo3/cms-felogin": "*",
|
||||
"typo3/cms-fluid-styled-content": "*",
|
||||
"typo3/cms-form": "*",
|
||||
"typo3/cms-info": "*",
|
||||
"typo3/cms-lowlevel": "*",
|
||||
"typo3/cms-recycler": "*",
|
||||
"typo3/cms-reports": "*",
|
||||
"typo3/cms-rte-ckeditor": "*",
|
||||
"typo3/cms-seo": "*",
|
||||
"typo3/cms-setup": "*",
|
||||
"typo3/cms-t3editor": "*",
|
||||
"typo3/cms-tstemplate": "*",
|
||||
"typo3/cms-scheduler": "*",
|
||||
|
||||
"helhum/typo3-console": "*",
|
||||
"clickstorm/cs-seo": "*"
|
||||
},
|
||||
"extra": {
|
||||
"typo3/cms": {
|
||||
"extension-key": "ew_base"
|
||||
}
|
||||
}
|
||||
}
|
||||
2
ext_conf_template.txt
Normal file
2
ext_conf_template.txt
Normal file
@ -0,0 +1,2 @@
|
||||
# cat=basic//10; type=boolean; label= Weather the content of css files gets inserted to the source code of the page as inline css
|
||||
inlineCssStyles = 0
|
||||
67
ext_localconf.php
Executable file
67
ext_localconf.php
Executable file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
defined('TYPO3') or die('access denied');
|
||||
|
||||
use Evoweb\EwBase\Form\Element\PickColorFromImage;
|
||||
use Evoweb\EwBase\Form\FormDataProvider\UsercentricsDatabaseEditRow;
|
||||
use Evoweb\EwBase\Form\FormDataProvider\UsercentricsTcaInline;
|
||||
use Evoweb\EwBase\Hooks\UsercentricsPostRenderHook;
|
||||
use Evoweb\EwBase\Xclass\SiteDatabaseEditRow;
|
||||
use Evoweb\EwBase\Xclass\SiteTcaInline;
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseParentPageRow;
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\SiteDatabaseEditRow as BaseSiteDatabaseEditRow;
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\SiteTcaInline as BaseSiteTcaInline;
|
||||
use TYPO3\CMS\Backend\Form\FormDataProvider\TcaSiteLanguage;
|
||||
|
||||
call_user_func(function () {
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['ewb'] = [ 'Evoweb\\EwBase\\ViewHelpers' ];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'][] =
|
||||
UsercentricsPostRenderHook::class . '->executePostRenderHook';
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1681197508] = [
|
||||
'nodeName' => 'pick-color-from-image',
|
||||
'priority' => '70',
|
||||
'class' => PickColorFromImage::class,
|
||||
];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][BaseSiteDatabaseEditRow::class] = [
|
||||
'className' => SiteDatabaseEditRow::class
|
||||
];
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][BaseSiteTcaInline::class] = [
|
||||
'className' => SiteTcaInline::class
|
||||
];
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['siteConfiguration'][
|
||||
UsercentricsDatabaseEditRow::class
|
||||
] = [
|
||||
'depends' => [ BaseSiteDatabaseEditRow::class ],
|
||||
'before' => [ DatabaseParentPageRow::class ],
|
||||
];
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['siteConfiguration'][
|
||||
UsercentricsTcaInline::class
|
||||
] = [
|
||||
'depends' => [ BaseSiteTcaInline::class ],
|
||||
'before' => [ TcaSiteLanguage::class ],
|
||||
];
|
||||
|
||||
if (empty($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['userCentrics'] ?? [])) {
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['userCentrics']['loader']['preload'] =
|
||||
'<link rel="preconnect" href="//app.usercentrics.eu">
|
||||
<link rel="preconnect" href="//privacy-proxy.usercentrics.eu">
|
||||
<link rel="preload" href="//app.usercentrics.eu/browser-ui/latest/loader.js" as="script">';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['userCentrics']['loader']['template'] =
|
||||
'<script src="//app.usercentrics.eu/browser-ui/latest/loader.js" data-settings-id="###ID###" id="usercentrics-cmp" async></script>';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['userCentrics']['main']['preload'] =
|
||||
'<link rel="preconnect" href="//app.usercentrics.eu">
|
||||
<link rel="preconnect" href="//api.usercentrics.eu">
|
||||
<link rel="preconnect" href="//privacy-proxy.usercentrics.eu">
|
||||
<link rel="preload" href="//app.usercentrics.eu/latest/main.js" as="script">';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['userCentrics']['main']['template'] =
|
||||
'<script src="//app.usercentrics.eu/latest/main.js" id="###ID###" type="application/javascript"></script>';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['userCentrics']['block']['preload'] =
|
||||
'<link rel="preload" href="//privacy-proxy.usercentrics.eu/latest/uc-block.bundle.js" as="script">';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['userCentrics']['block']['template'] =
|
||||
'<script type="application/javascript" src="https://privacy-proxy.usercentrics.eu/latest/uc-block.bundle.js"></script>';
|
||||
}
|
||||
});
|
||||
7
ext_tables.sql
Executable file
7
ext_tables.sql
Executable file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# Table structure for table 'pages'
|
||||
#
|
||||
CREATE TABLE pages
|
||||
(
|
||||
sectionIndex_uid int(11) unsigned DEFAULT '0' NOT NULL
|
||||
);
|
||||
Loading…
Reference in New Issue
Block a user