diff --git a/Classes/Backend/EventListener/FlexForm/FlexformEvent.php b/Classes/Backend/EventListener/FlexForm/FlexformEvent.php index d55a3b4d..ca30781f 100644 --- a/Classes/Backend/EventListener/FlexForm/FlexformEvent.php +++ b/Classes/Backend/EventListener/FlexForm/FlexformEvent.php @@ -1,4 +1,5 @@ get('t3sbootstrap'); - - if (array_key_exists('flexformExtend', $extconf) && $extconf['flexformExtend'] === '1') { - - $dataStructure = $event->getDataStructure(); - $identifier = $event->getIdentifier(); - - $ffPath = '/fileadmin/T3SB/FlexForms/'; - - foreach ( $GLOBALS['TCA']['tt_content']['columns']['tx_t3sbootstrap_flexform']['config']['ds'] as $key=>$flexForm ) { + public function __invoke(AfterFlexFormDataStructureParsedEvent $event): void + { + $extconf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); + $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); + $settings = $configurationManager->getConfiguration( + ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, + 't3sbootstrap', + 'm1' + ); - $flexForms[$key] = substr($flexForm, 46, -4); - } + if (array_key_exists('flexformExtend', $extconf) && $extconf['flexformExtend'] === '1') { + $dataStructure = $event->getDataStructure(); + $identifier = $event->getIdentifier(); - if ( array_key_exists($identifier['dataStructureKey'],$flexForms) ) { + if (!empty($settings['sitepackage'])) { + $ffPath = 'EXT:t3sb_package/T3SB/FlexForms/'; + } else { + $ffPath = '/fileadmin/T3SB/FlexForms/'; + } - if ($identifier['type'] === 'tca' && $identifier['tableName'] === 'tt_content' - && $identifier['fieldName'] === 'tx_t3sbootstrap_flexform' && $identifier['dataStructureKey']) { + foreach ($GLOBALS['TCA']['tt_content']['columns']['tx_t3sbootstrap_flexform']['config']['ds'] as $key=>$flexForm) { + $flexForms[$key] = substr($flexForm, 46, -4); + } - $file = Environment::getPublicPath() . $ffPath.$flexForms[$identifier['dataStructureKey']].'.xml'; - if (file_exists($file)) { - $content = @file_get_contents($file); - if ($content) { - $dataStructure['sheets']['extraEntry'] = GeneralUtility::xml2array($content); + if (array_key_exists($identifier['dataStructureKey'], $flexForms)) { + if ($identifier['type'] === 'tca' && $identifier['tableName'] === 'tt_content' + && $identifier['fieldName'] === 'tx_t3sbootstrap_flexform' && $identifier['dataStructureKey']) { + $file = Environment::getPublicPath() . $ffPath.$flexForms[$identifier['dataStructureKey']].'.xml'; + if (file_exists($file)) { + $content = @file_get_contents($file); + if ($content) { + $dataStructure['sheets']['extraEntry'] = GeneralUtility::xml2array($content); - $extraDataStructure['sheets']['extraEntry'] = GeneralUtility::xml2array($content); - ArrayUtility::mergeRecursiveWithOverrule($dataStructure, $extraDataStructure); - } - } - } + $extraDataStructure['sheets']['extraEntry'] = GeneralUtility::xml2array($content); + ArrayUtility::mergeRecursiveWithOverrule($dataStructure, $extraDataStructure); + } + } + } - $event->setDataStructure($dataStructure); - } - } - } + $event->setDataStructure($dataStructure); + } + } + } } diff --git a/Classes/Command/CdnToLocal.php b/Classes/Command/CdnToLocal.php index 2b9830bf..76aad1c1 100644 --- a/Classes/Command/CdnToLocal.php +++ b/Classes/Command/CdnToLocal.php @@ -1,4 +1,5 @@ configurationManager = $configurationManager; - } - - - /** - * Defines the allowed options for this command - * - * @inheritdoc - */ - protected function configure() - { - $this->setDescription('Write required CSS and JS to fileadmin/Resources/Public/'); - } - - - /** - * Update all records - * - * @inheritdoc - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - - $this->configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); - $settings = $this->configurationManager->getConfiguration( - ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, - 't3sbootstrap', - 'm1' - ); - - # check FA version & settings - $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); - - if ( !empty($extConf['fontawesomeCss']) ) { - if ( (int)$extConf['fontawesomeCss'] > 2 ) { - if ( (int)$settings['cdn']['fontawesome'] < 6 ) { - $settings['cdn']['fontawesome'] = $settings['cdn']['fontawesome6latest']; - } - } - } else { - $settings['cdn']['fontawesome'] = $settings['cdn']['fontawesome6latest']; - } - - if ( !empty($settings['cdn']['googlefonts']) && empty($settings['cdn']['noZip']) ) { - self::getGoogleFonts($settings['cdn']['googlefonts'], $settings['preloadGooleFonts'], $settings['gooleFontsWeights']); - } else { - $localZipPath = GeneralUtility::getFileAbsFileName(self::localZipPath); - if ( is_dir($localZipPath) ) { - parent::rmDir($localZipPath); - } - $cssFile = GeneralUtility::getFileAbsFileName(self::localGoogleFile); - if (file_exists($cssFile)) unlink($cssFile); - - $customDir = 'fileadmin/T3SB/Configuration/TypoScript/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'preloadGooleFonts.typoscript'; - $customFile = $customPath.$customFileName; - if (file_exists($customFile)) {unlink($customFile);} - if (!is_dir($customPath)) {mkdir($customPath, 0777, true);} - GeneralUtility::writeFile($customFile, ''); - } - - foreach ($settings['cdn'] as $key=>$version) { - - if ($key == 'jquery') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'jquery.min.js'; - $cdnPath = 'https://code.jquery.com/jquery-'.$version.'.min.js'; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'bootstrap') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'bootstrap.min.css'; - if ($settings['cdn']['bootswatch']) { - $bootswatchTheme = $settings['cdn']['bootswatch']; - $cdnPath = 'https://cdn.jsdelivr.net/npm/bootswatch@'.$version.'/dist/'.$bootswatchTheme.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath, true); - } else { - $cdnPath = 'https://cdn.jsdelivr.net/npm/bootstrap@'.$version.'/dist/css/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath, true); - } - - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'bootstrap.min.js'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/bootstrap@'.$version.'/dist/js/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - $customFileName = 'bootstrap.bundle.min.js'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/bootstrap@'.$version.'/dist/js/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'popperjs') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'popper.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/'.$version.'/umd/popper.min.js'; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'fontawesome') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'fontawesome.min.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/'.$version.'/js/all.min.js'; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'jqueryEasing') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'jquery.easing.min.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'highlight') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'highlight.default.min.css'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/'.$version.'/styles/default.min.css'; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - $customFileName = 'highlight.a11y-light.min.css'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/'.$version.'/styles/a11y-light.min.css'; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'highlight.min.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - $customFileName = 'highlight.php.min.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/'.$version.'/languages/php.min.js'; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'lazyload') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'lazyload.min.js'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/vanilla-lazyload@'.$version.'/dist/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'picturefill') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'picturefill.min.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/picturefill/'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'animate') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'animate.compat.css'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'baguetteBox') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'baguetteBox.min.css'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'baguetteBox.min.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - if ($key == 'halkabox') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'halkaBox.min.css'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/halkabox@'.$version.'/dist/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath, true); - - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'halkaBox.min.js'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/halkabox@'.$version.'/dist/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'glightbox') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'glightbox.min.css'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/glightbox@'.$version.'/dist/css/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'glightbox.min.js'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/glightbox@'.$version.'/dist/js/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'cookieconsent') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'cookieconsent.min.css'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/cookieconsent@'.$version.'/build/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'cookieconsent.min.js'; - $cdnPath = 'https://cdn.jsdelivr.net/npm/cookieconsent@'.$version.'/build/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'masonry') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'masonry.pkgd.min.js'; - $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/masonry/'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'jarallax') { - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'jarallax.min.js'; - $cdnPath = 'https://unpkg.com/jarallax@'.$version.'/dist/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - $customFileName = 'jarallax-video.min.js'; - $cdnPath = 'https://unpkg.com/jarallax@'.$version.'/dist/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - - if ($key == 'swiper') { - $customDir = 'fileadmin/T3SB/Resources/Public/CSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'swiper-bundle.min.css'; - $cdnPath = 'https://unpkg.com/swiper@'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - $customDir = 'fileadmin/T3SB/Resources/Public/JS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'swiper-bundle.min.js'; - $cdnPath = 'https://unpkg.com/swiper@'.$version.'/'.$customFileName; - self::writeCustomFile($customPath, $customFileName, $cdnPath); - } - } - - return 0; - } - - - private function writeCustomFile($customPath, $customFileName, $cdnPath, $extend=false ) { - $customFile = $customPath.$customFileName; - $customContent = GeneralUtility::getURL($cdnPath); - if ($extend && str_contains( (string)$customContent, '/*#')) { - $customContentArr = explode('/*#' , $customContent); - $customContent = $customContentArr[0]; - } elseif (str_contains((string)$customContent, '//#')) { - $customContentArr = explode('//#' , $customContent); - $customContent = $customContentArr[0]; - } - if (file_exists($customFile)) { - unlink($customFile); - } - if (!is_dir($customPath)) { - mkdir($customPath, 0777, true); - } - - GeneralUtility::writeFile($customFile, $customContent); - } - - - private function getGoogleFonts($googleFonts, $preloadGooleFonts, $gooleFontsWeights) { - $localZipPath = GeneralUtility::getFileAbsFileName(self::localZipPath); - if ( is_dir($localZipPath) ) { - parent::rmDir($localZipPath); - } - mkdir($localZipPath, 0777, true); - $localZipFile = GeneralUtility::getFileAbsFileName(self::localZipPath.self::localZipFile); - $googleFontsArr = explode(',', $googleFonts); - foreach ($googleFontsArr as $font) { - $fontFamily = trim($font); - $font = str_replace(' ', '-', trim($font)); - foreach ( explode(',', $gooleFontsWeights) as $style ) { - $style = trim($style); - $zipFilename = strtolower($font).'?download=zip&subsets=latin&variants='.$style; - $zipContent = GeneralUtility::makeInstance(RequestFactory::class)->request(self::zipFilePath . $zipFilename)->getBody()->getContents(); - $fontArr[$fontFamily] = self::getGoogleFiles($zipContent, $localZipFile, $localZipPath); - } - } - - if ( is_array($fontArr)) { - foreach ($fontArr as $fontFamily=>$googlePath) { - $sliceArr[$fontFamily] = array_slice($googlePath, 0, 1); - } - $css = ''; - $headerData = ''; - foreach ($sliceArr as $fontFamily=>$googlePath) { - foreach ( explode(',', $gooleFontsWeights) as $i=>$style ) { - $style = trim($style); - $file = str_replace('300','', explode('.', $googlePath[0])[0]).$style; - $style = $style == 'regular' ? '400' : $style; - if (!empty($preloadGooleFonts)) { - $num = self::generateRandomString(); - $s = $i + 1; - $headerData .= ' 22'.$num.$i.' = TEXT'.LF; - $headerData .= ' 22'.$num.$i.'.value = '.LF; - $headerData .= ' 22'.$num.$s.' = TEXT'.LF; - $headerData .= ' 22'.$num.$s.'.value = '.LF; - } - -$css .= "@font-face { - font-family: '".$fontFamily."'; - font-style: normal; - font-weight: ".$style."; - font-display: swap; - src: url('/fileadmin/T3SB/Resources/Public/CSS/googlefonts/".$file.".eot'); - src: local(''), - url('/fileadmin/T3SB/Resources/Public/CSS/googlefonts/".$file.".eot?#iefix') format('embedded-opentype'), - url('/fileadmin/T3SB/Resources/Public/CSS/googlefonts/".$file.".woff2') format('woff2'), - url('/fileadmin/T3SB/Resources/Public/CSS/googlefonts/".$file.".woff') format('woff'); - url('/fileadmin/T3SB/Resources/Public/CSS/googlefonts/".$file.".ttf') format('truetype'), - url('/fileadmin/T3SB/Resources/Public/CSS/googlefonts/".$file.".svg#".trim(str_replace(' ', '', $fontFamily))."') format('svg'); + /** + * Defines the allowed options for this command + * + * @inheritdoc + */ + protected function configure() + { + $this->setDescription('Write required CSS and JS to fileadmin/ or EXT:t3sb_package/'); + } + + + /** + * Update all records + * + * @inheritdoc + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); + $settings = $configurationManager->getConfiguration( + ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, + 't3sbootstrap', + 'm1' + ); + + if (empty($settings['sitepackage'])) { + $baseDir = GeneralUtility::getFileAbsFileName('fileadmin/T3SB/'); + } else { + if (ExtensionManagementUtility::isLoaded('t3sb_package')) { + $baseDir = GeneralUtility::getFileAbsFileName('EXT:t3sb_package/T3SB/'); + } else { + throw new \InvalidArgumentException('Your t3sb_package is not loaded!', 1657464787); + } + } + + # check FA version & settings + $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); + + if (!empty($extConf['fontawesomeCss'])) { + if ((int)$extConf['fontawesomeCss'] > 2) { + if ((int)$settings['cdn']['fontawesome'] < 6) { + $settings['cdn']['fontawesome'] = $settings['cdn']['fontawesome6latest']; + } + } + } else { + $settings['cdn']['fontawesome'] = $settings['cdn']['fontawesome6latest']; + } + + if (!empty($settings['cdn']['googlefonts']) && empty($settings['cdn']['noZip'])) { + if (empty($settings['sitepackage'])) { + self::getGoogleFonts($settings['cdn']['googlefonts'], $settings['gooleFontsWeights'], $baseDir); + } else { + self::getGoogleFontsSitepackage($settings['cdn']['googlefonts'], $settings['gooleFontsWeights'], $baseDir); + } + } else { + $localZipPath = $baseDir.'Resources/Public/CSS/googlefonts/'; + if (is_dir($localZipPath)) { + parent::rmDir($localZipPath); + } + $cssFile = $baseDir.'Resources/Public/CSS/googlefonts.css'; + if (file_exists($cssFile)) { + unlink($cssFile); + } + } + + foreach ($settings['cdn'] as $key=>$version) { + if ($key == 'jquery') { + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'jquery.min.js'; + $cdnPath = 'https://code.jquery.com/jquery-'.$version.'.min.js'; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'bootstrap') { + $customPath = $baseDir.'Resources/Public/CSS/'; + $customFileName = 'bootstrap.min.css'; + if ($settings['cdn']['bootswatch']) { + $bootswatchTheme = $settings['cdn']['bootswatch']; + $cdnPath = 'https://cdn.jsdelivr.net/npm/bootswatch@'.$version.'/dist/'.$bootswatchTheme.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath, true); + } else { + $cdnPath = 'https://cdn.jsdelivr.net/npm/bootstrap@'.$version.'/dist/css/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath, true); + } + + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'bootstrap.min.js'; + $cdnPath = 'https://cdn.jsdelivr.net/npm/bootstrap@'.$version.'/dist/js/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + $customFileName = 'bootstrap.bundle.min.js'; + $cdnPath = 'https://cdn.jsdelivr.net/npm/bootstrap@'.$version.'/dist/js/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'popperjs') { + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'popper.js'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/'.$version.'/umd/popper.min.js'; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'fontawesome') { + if ((int)$extConf['fontawesomeCss'] == 1 || (int)$extConf['fontawesomeCss'] == 2) { + $customPath = $baseDir.'Resources/Public/FA6-Kit/'; + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + } else { + $customPath = $baseDir.'Resources/Public/CSS/'; + $customFileName = 'fontawesome.min.css'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/'.$version.'/css/all.min.css'; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + + $src = GeneralUtility::getFileAbsFileName('EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/webfonts'); + if (is_dir($src)) { + $dest = $baseDir.'Resources/Public/webfonts/'; + if (!is_dir($dest)) { + mkdir($dest, 0777, true); + } + $fileLists = GeneralUtility::getAllFilesAndFoldersInPath([], $src); + foreach ($fileLists as $file) { + copy($file, $dest.end(explode('/', $file))); + } + } + + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'fontawesome.min.js'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/'.$version.'/js/all.min.js'; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + } + + if ($key == 'jqueryEasing') { + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'jquery.easing.min.js'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'lazyload') { + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'lazyload.min.js'; + $cdnPath = 'https://cdn.jsdelivr.net/npm/vanilla-lazyload@'.$version.'/dist/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'picturefill') { + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'picturefill.min.js'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/picturefill/'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'animate') { + $customPath = $baseDir.'Resources/Public/CSS/'; + $customFileName = 'animate.compat.css'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'baguetteBox') { + $customPath = $baseDir.'Resources/Public/CSS/'; + $customFileName = 'baguetteBox.min.css'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'baguetteBox.min.js'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + if ($key == 'halkabox') { + $customPath = $baseDir.'Resources/Public/CSS/'; + $customFileName = 'halkaBox.min.css'; + $cdnPath = 'https://cdn.jsdelivr.net/npm/halkabox@'.$version.'/dist/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath, true); + + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'halkaBox.min.js'; + $cdnPath = 'https://cdn.jsdelivr.net/npm/halkabox@'.$version.'/dist/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'glightbox') { + $customPath = $baseDir.'Resources/Public/CSS/'; + $customFileName = 'glightbox.min.css'; + $cdnPath = 'https://cdn.jsdelivr.net/npm/glightbox@'.$version.'/dist/css/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'glightbox.min.js'; + $cdnPath = 'https://cdn.jsdelivr.net/npm/glightbox@'.$version.'/dist/js/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'masonry') { + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'masonry.pkgd.min.js'; + $cdnPath = 'https://cdnjs.cloudflare.com/ajax/libs/masonry/'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'jarallax') { + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'jarallax.min.js'; + $cdnPath = 'https://unpkg.com/jarallax@'.$version.'/dist/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + $customFileName = 'jarallax-video.min.js'; + $cdnPath = 'https://unpkg.com/jarallax@'.$version.'/dist/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + + if ($key == 'swiper') { + $customPath = $baseDir.'Resources/Public/CSS/'; + $customFileName = 'swiper-bundle.min.css'; + $cdnPath = 'https://unpkg.com/swiper@'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + $customPath = $baseDir.'Resources/Public/JS/'; + $customFileName = 'swiper-bundle.min.js'; + $cdnPath = 'https://unpkg.com/swiper@'.$version.'/'.$customFileName; + self::writeCustomFile($customPath, $customFileName, $cdnPath); + } + } + + return 0; + } + + + private function writeCustomFile($customPath, $customFileName, $cdnPath, $extend=false) + { + $customFile = $customPath.$customFileName; + $customContent = GeneralUtility::getURL($cdnPath); + + if ($extend && str_contains((string)$customContent, '/*#')) { + $customContentArr = explode('/*#', $customContent); + $customContent = $customContentArr[0]; + } elseif (str_contains((string)$customContent, '//#')) { + $customContentArr = explode('//#', $customContent); + $customContent = $customContentArr[0]; + } + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + + GeneralUtility::writeFile($customFile, $customContent); + } + + + private function getGoogleFonts($googleFonts, $gooleFontsWeights, $baseDir) + { + $localZipPath = $baseDir.'Resources/Public/CSS/googlefonts/'; + if (is_dir($localZipPath)) { + parent::rmDir($localZipPath); + } + mkdir($localZipPath, 0777, true); + $googleFontsArr = explode(',', $googleFonts); + foreach ($googleFontsArr as $font) { + $fontFamily = trim($font); + $font = str_replace(' ', '-', trim($font)); + foreach (explode(',', $gooleFontsWeights) as $style) { + $style = trim($style); + $zipFilename = strtolower($font).'?download=zip&subsets=latin&variants='.$style; + $zipFilePath = 'https://gwfh.mranftl.com/api/fonts/'; + $zipContent = GeneralUtility::makeInstance(RequestFactory::class)->request($zipFilePath . $zipFilename)->getBody()->getContents(); + $fontArr[$fontFamily] = self::getGoogleFiles($zipContent, $baseDir); + } + } + + if (is_array($fontArr)) { + $basePath = '/fileadmin/T3SB/'; + foreach ($fontArr as $fontFamily=>$googlePath) { + $sliceArr[$fontFamily] = array_slice($googlePath, 0, 1); + } + $css = ''; + $headerData = ''; + foreach ($sliceArr as $fontFamily=>$googlePath) { + foreach (explode(',', $gooleFontsWeights) as $i=>$style) { + $style = trim($style); + $file = str_replace('300', '', explode('.', $googlePath[0])[0]).$style; + $style = $style == 'regular' ? '400' : $style; + $css .= "@font-face { + font-family: '".$fontFamily."'; + font-style: normal; + font-weight: ".$style."; + font-display: swap; + src: url('".$basePath."Resources/Public/CSS/googlefonts/".$file.".eot'); + src: local(''), + url('googlefonts/".$file.".eot?#iefix') format('embedded-opentype'), + url('googlefonts/".$file.".woff2') format('woff2'), + url('googlefonts/".$file.".woff') format('woff'); + url('googlefonts/".$file.".ttf') format('truetype'), + url('googlefonts/".$file.".svg#".trim(str_replace(' ', '', $fontFamily))."') format('svg'); }".LF.LF; - } - } - - if (!empty($preloadGooleFonts)) { - $setup = 'page.headerData {'.LF.$headerData; - $setup .= '}'; - $customDir = 'fileadmin/T3SB/Configuration/TypoScript/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'preloadGooleFonts.typoscript'; - $customFile = $customPath.$customFileName; - if (file_exists($customFile)) {unlink($customFile);} - if (!is_dir($customPath)) {mkdir($customPath, 0777, true);} - GeneralUtility::writeFile($customFile, $setup); - } - - if (!empty($css)) { - $cssFile = GeneralUtility::getFileAbsFileName(self::localGoogleFile); - if (file_exists($cssFile)) unlink($cssFile); - GeneralUtility::writeFile($cssFile, $css); - } - } - } - - - private function getGoogleFiles($zipContent, $localZipFile, $localZipPath) { - if ($zipContent) { - GeneralUtility::writeFile($localZipFile, $zipContent); - $zip = new \ZipArchive; - if ($zip->open($localZipFile) === TRUE) { - $zip->extractTo($localZipPath); - $zip->close(); - } else { - throw new \InvalidArgumentException('Sorry ZIP creation failed at this time!', 1655291469); - } - $zipFile = GeneralUtility::getFileAbsFileName($localZipFile); - if (file_exists($zipFile)) unlink($zipFile); - $googleFiles = scandir($localZipPath); - $css = ''; - $googleFileArr = []; - foreach ($googleFiles as $googleFile) { - if ( str_ends_with($googleFile, 'woff') ) { - $googleFileArr[] = $googleFile; - } - } - } else { - throw new \InvalidArgumentException('Check the spelling of the google fonts!', 1657464667); - } - - return $googleFileArr; - } - - - private function generateRandomString($length = 4) { - $characters = '0123456789'; - $charactersLength = strlen($characters); - $randomString = ''; - for ($i = 0; $i < $length; $i++) { - $randomString .= $characters[rand(0, $charactersLength - 1)]; - } - return $randomString; - } - + } + } + if (!empty($css)) { + $cssFile = $baseDir.'Resources/Public/CSS/googlefonts.css'; + if (file_exists($cssFile)) { + unlink($cssFile); + } + GeneralUtility::writeFile($cssFile, $css); + } + } + } + + private function getGoogleFontsSitepackage($googleFonts, $gooleFontsWeights, $baseDir) + { + $localZipPath = $baseDir.'Resources/Public/CSS/googlefonts/'; + if (is_dir($localZipPath)) { + parent::rmDir($localZipPath); + } + mkdir($localZipPath, 0777, true); + $googleFontsArr = explode(',', $googleFonts); + foreach ($googleFontsArr as $font) { + $fontFamily = trim($font); + $font = str_replace(' ', '-', trim($font)); + foreach (explode(',', $gooleFontsWeights) as $style) { + $style = trim($style); + $zipFilename = strtolower($font).'?download=zip&subsets=latin&variants='.$style; + $zipFilePath = 'https://gwfh.mranftl.com/api/fonts/'; + $zipContent = GeneralUtility::makeInstance(RequestFactory::class)->request($zipFilePath . $zipFilename)->getBody()->getContents(); + $fontArr[$fontFamily] = self::getGoogleFiles($zipContent, $baseDir); + } + } + + if (is_array($fontArr)) { + foreach ($fontArr as $fontFamily=>$googlePath) { + $sliceArr[$fontFamily] = array_slice($googlePath, 0, 1); + } + $css = ''; + $headerData = ''; + + foreach ($sliceArr as $fontFamily=>$googlePath) { + foreach (explode(',', $gooleFontsWeights) as $i=>$style) { + $style = trim($style); + $file = str_replace('300', '', explode('.', $googlePath[0])[0]).$style; + $style = $style == 'regular' ? '400' : $style; + $googlefontsPath = 'googlefonts/'; + $css .= "@font-face { + font-family: '".$fontFamily."'; + font-style: normal; + font-weight: ".$style."; + font-display: swap; + src: url('".$googlefontsPath.$file.".eot'); + src: local(''), + url('".$googlefontsPath.$file.".eot?#iefix') format('embedded-opentype'), + url('".$googlefontsPath.$file.".woff2') format('woff2'), + url('".$googlefontsPath.$file.".woff') format('woff'); + url('".$googlefontsPath.$file.".ttf') format('truetype'), + url('".$googlefontsPath.$file.".svg#".trim(str_replace(' ', '', $fontFamily))."') format('svg'); + }".LF.LF; + } + } + if (!empty($css)) { + $cssFile = $baseDir.'Resources/Public/CSS/googlefonts.css'; + if (file_exists($cssFile)) { + unlink($cssFile); + } + GeneralUtility::writeFile($cssFile, $css); + } + } + } + + + private function getGoogleFiles($zipContent, $baseDir='/') + { + $googleFileArr = []; + if ($zipContent) { + $localZipPath = $baseDir.'Resources/Public/CSS/googlefonts/'; + $localZipFile = $localZipPath.'googlefont.zip'; + + GeneralUtility::writeFile($localZipFile, $zipContent); + $zip = new \ZipArchive(); + if ($zip->open($localZipFile) === true) { + $zip->extractTo($localZipPath); + $zip->close(); + } else { + throw new \InvalidArgumentException('Sorry ZIP creation failed at this time!', 1655291469); + } + if (file_exists($localZipFile)) { + unlink($localZipFile); + } + $googleFiles = scandir($localZipPath); + $css = ''; + + foreach ($googleFiles as $googleFile) { + if (str_ends_with($googleFile, 'woff')) { + $googleFileArr[] = $googleFile; + } + } + } else { + throw new \InvalidArgumentException('Check the spelling of the google fonts!', 1657464667); + } + + return $googleFileArr; + } + + + private function generateRandomString($length = 4) + { + $characters = '0123456789'; + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[rand(0, $charactersLength - 1)]; + } + return $randomString; + } } diff --git a/Classes/Command/CustomScss.php b/Classes/Command/CustomScss.php index acfb25fc..46ead289 100644 --- a/Classes/Command/CustomScss.php +++ b/Classes/Command/CustomScss.php @@ -1,16 +1,18 @@ configurationManager = $configurationManager; - } - - - /** - * Defines the allowed options for this command - * - * @inheritdoc - */ - protected function configure() - { - $this->setDescription('T3SB Custom Scss - write a custom scss file'); - } - - - /** - * Update all records - * - * @inheritdoc - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $this->configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); - $settings = $this->configurationManager->getConfiguration( - ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, - 't3sbootstrap', - 'm1' - ); - - $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); - - if ( $settings['customScss'] && array_key_exists('customScss', $extConf) && $extConf['customScss'] === '1' ) { - # get the Boostrap SCSS-Files - $bootstrapVersion = str_starts_with($settings['cdn']['bootstrap'], '5.') ? $settings['cdn']['bootstrap'] : $settings['cdn']['bootstraplatest']; - $bootstrapScssDir = 'fileadmin/T3SB/Resources/Public/Contrib/Bootstrap/scss/'; - $bootstrapScssPath = GeneralUtility::getFileAbsFileName($bootstrapScssDir); - - if ($settings['cdn']['noZip']) { - self::getBootstrapFilesNoZip($settings, $bootstrapVersion, $bootstrapScssPath); - } else { - self::getBootstrapFiles($bootstrapVersion); - } - if (!file_exists(GeneralUtility::getFileAbsFileName(self::localZipPath.'scss/bootstrap.scss'))) { - self::getBootstrapFilesNoZip($settings, $bootstrapVersion, $bootstrapScssPath); - } - - # Custom - $customDir = !empty($settings['customScssPath']) ? $settings['customScssPath'] : 'fileadmin/T3SB/Resources/Public/SCSS/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); - $result = $queryBuilder - ->select('*') - ->from('pages') - ->where( - $queryBuilder->expr()->eq('sys_language_uid', 0), - $queryBuilder->expr()->eq('is_siteroot', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)) - ) - ->executeQuery(); - $siteroots = $result->fetchAll(); - - foreach ($siteroots as $key=>$siteroot) { - if ($key === 0) { - $customFileName = 'custom-variables.scss'; - $customFileNameOverride = 'custom.scss'; - $boottstrapFileName = 'bootstrap.scss'; - } else { - $customFileName = 'custom-variables-'.$siteroot['uid'].'.scss'; - $customFileNameOverride = 'custom-'.$siteroot['uid'].'.scss'; - $boottstrapFileName = 'bootstrap-'.$siteroot['uid'].'.scss'; - } - - self::writeCustomFile($customPath, $customFileName, $settings, '_variables'); - self::writeCustomFile($customPath, $customFileNameOverride, $settings, '_bootswatch'); - - # Include - $includeDir = 'uploads/tx_t3sbootstrap/'; - $includePath = GeneralUtility::getFileAbsFileName($includeDir); - - if ($key === 0) { - self::deleteFilesFromDirectory($includePath); - $includeFileName = 'bootstrap.scss'; - } else { - $includeFileName = 'bootstrap-'.$siteroot['uid'].'.scss'; - } - - $includeFile = $includePath.$includeFileName; - - if (!file_exists($includeFile)) { - - if (!is_dir($includePath)) { - mkdir($includePath, 0777, true); - } - - if ($key === 0) { - $includeContent = ' -@import "../../'.$customDir.'custom-variables"; -@import "../../'.self::localZipPath.'scss/bootstrap"; -@import "../../'.$customDir.'custom"; + public function initializeAction() + { + parent::initializeAction(); + } + + + public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager) + { + $this->configurationManager = $configurationManager; + } + + + /** + * Defines the allowed options for this command + * + * @inheritdoc + */ + protected function configure() + { + $this->setDescription('T3SB Custom Scss - write a custom scss file'); + } + + + /** + * Update all records + * + * @inheritdoc + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); + $settings = $this->configurationManager->getConfiguration( + ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, + 't3sbootstrap', + 'm1' + ); + + if (empty($settings['sitepackage'])) { + $baseDir = GeneralUtility::getFileAbsFileName('fileadmin/T3SB/'); + } else { + if (ExtensionManagementUtility::isLoaded('t3sb_package')) { + $baseDir = GeneralUtility::getFileAbsFileName("EXT:t3sb_package/T3SB/"); + } else { + throw new \InvalidArgumentException('Your t3sb_package is not loaded!', 1657464787); + } + } + + $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); + + if ($settings['customScss'] && array_key_exists('customScss', $extConf) && $extConf['customScss'] === '1') { + # get the Boostrap SCSS-Files + $bootstrapVersion = str_starts_with($settings['cdn']['bootstrap'], '5.') ? $settings['cdn']['bootstrap'] : $settings['cdn']['bootstraplatest']; + $bootstrapScssPath = $baseDir.'Resources/Public/Contrib/Bootstrap/scss/'; + if (!is_dir($bootstrapScssPath)) { + mkdir($bootstrapScssPath, 0777, true); + } + if ($settings['cdn']['noZip']) { + self::getBootstrapFilesNoZip($settings, $bootstrapVersion, $bootstrapScssPath, $baseDir); + } else { + self::getBootstrapFiles($bootstrapVersion, $baseDir); + } + if (!file_exists($baseDir.'Resources/Public/Contrib/Bootstrap/scss/bootstrap.scss')) { + self::getBootstrapFilesNoZip($settings, $bootstrapVersion, $bootstrapScssPath, $baseDir); + } + + # Custom + $customPath = $baseDir.'Resources/Public/SCSS/'; + + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $result = $queryBuilder + ->select('*') + ->from('pages') + ->where( + $queryBuilder->expr()->eq('sys_language_uid', 0), + $queryBuilder->expr()->eq('is_siteroot', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)) + ) + ->executeQuery(); + $siteroots = $result->fetchAllAssociative(); + + foreach ($siteroots as $key=>$siteroot) { + if ($key === 0) { + $customFileName = 'custom-variables.scss'; + $customFileNameOverride = 'custom.scss'; + $boottstrapFileName = 'bootstrap.scss'; + } else { + $customFileName = 'custom-variables-'.$siteroot['uid'].'.scss'; + $customFileNameOverride = 'custom-'.$siteroot['uid'].'.scss'; + $boottstrapFileName = 'bootstrap-'.$siteroot['uid'].'.scss'; + } + + self::writeCustomFile($customPath, $customFileName, $settings, '_variables'); + self::writeCustomFile($customPath, $customFileNameOverride, $settings, '_bootswatch'); + + # Include + $includeDir = 'uploads/tx_t3sbootstrap/'; + $includePath = GeneralUtility::getFileAbsFileName($includeDir); + + if ($key === 0) { + self::deleteFilesFromDirectory($includePath); + $includeFileName = 'bootstrap.scss'; + } else { + $includeFileName = 'bootstrap-'.$siteroot['uid'].'.scss'; + } + + $includeFile = $includePath.$includeFileName; + + if (!file_exists($includeFile)) { + if (!is_dir($includePath)) { + mkdir($includePath, 0777, true); + } + + $customDir = $baseDir.'Resources/Public/SCSS/'; + if ($key === 0) { + $includeContent = ' +@import "'.$customDir.'custom-variables"; +@import "'.$baseDir.'Resources/Public/Contrib/Bootstrap/scss/bootstrap"; +@import "'.$customDir.'custom"; '; - } else { - $includeContent = ' -@import "../../'.$customDir.'custom-variables-'.$siteroot['uid'].'"; -@import "../../'.self::localZipPath.'scss/bootstrap"; -@import "../../'.$customDir.'custom-'.$siteroot['uid'].'"; + } else { + $includeContent = ' +@import "'.$customDir.'custom-variables-'.$siteroot['uid'].'"; +@import "'.$baseDir.'Resources/Public/Contrib/Bootstrap/scss/bootstrap"; +@import "'.$customDir.'custom-'.$siteroot['uid'].'"; '; - } - - GeneralUtility::writeFile($includeFile, $includeContent); - } - } - - $tempPath = GeneralUtility::getFileAbsFileName('typo3temp/assets/t3sbootstrap/css/'); - self::deleteFilesFromDirectory($tempPath); - - $customDir = self::localZipPath.'scss/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 'bootstrap.scss'; - $customFile = $customPath.$customFileName; - $customContent = GeneralUtility::getURL($customFile); - $length = 0; - if ($customContent) { - $length = strlen($customContent); - } - - foreach ( $settings['optimize'] as $component=>$import ) { - if (!$import && $customContent) { - $find = '@import "'.$component.'";'; - $replace = '// @import "'.$component.'";'; - $customContent = str_replace($find, $replace, $customContent); - } - } - - if ($customContent && $length < strlen($customContent)) { - if (file_exists($customFile)) unlink($customFile); - if (!is_dir($customPath)) mkdir($customPath, 0777, true); - GeneralUtility::writeFile($customFile, $customContent); - } - - if ( is_dir(GeneralUtility::getFileAbsFileName(self::localZipPath.'scss')) ) { - - return 0; - - } else { - throw new \InvalidArgumentException('Check the bootstrap version in the constant editor for validity!', 1657204821); - - return 1; - } - - } else { - - throw new \InvalidArgumentException('You have to activate SCSS in the EM config!', 1657204821); - - return 1; - } - - } - - - private function writeCustomFile($customPath, $customFileName, $settings, $name) { - - $customFile = $customPath.$customFileName; - - $keepVariables = (int)$settings['keepVariables']; - if (file_exists($customFile)) { - $copyFile = $customPath.'_'.time().'-'.$customFileName; - if (!copy($customFile, $copyFile)) { - return FALSE; - } elseif (empty($keepVariables)) { - unlink($customFile); - } - } - if (!file_exists($customFile) && empty($keepVariables)) { - if (!is_dir($customPath)) { - mkdir($customPath, 0777, true); - } - $customContent = $name == '_variables' ? '// Overrides Bootstrap variables'.PHP_EOL.'// $enable-shadows: true;'.PHP_EOL.'// $enable-gradients: true;'.PHP_EOL.'// $enable-negative-margins: true;' : '// Your own SCSS'; - - if ( !empty($settings['bootswatch']) ) { - $customContent = @file_get_contents($settings['bootswatchURL'].strtolower($settings['bootswatch']).'/'.$name.'.scss'); - if ($name == '_variables') { - $customContent = str_replace(' !default', '', $customContent); - } - } - - GeneralUtility::writeFile($customFile, $customContent); - } - - return TRUE; - } - - - private function deleteFilesFromDirectory($directory){ - if (is_dir($directory)) { - if ($dh = opendir($directory)) { - while (($file = readdir($dh)) !== false) { - if ($file!='.' && $file !='..' && $file[0] != '_') { - unlink(''.$directory.''.$file.''); - } - } - closedir($dh); - } - } - } - - - public function getBootstrapFiles($bootstrapVersion): void - { - $localZipPath = GeneralUtility::getFileAbsFileName(self::localZipPath); - if ( is_dir($localZipPath) ) { - parent::rmDir($localZipPath); - } - mkdir($localZipPath, 0777, true); - $localZipFile = GeneralUtility::getFileAbsFileName(self::localZipPath.self::localZipFile); - $zipFilename = 'v'.$bootstrapVersion.'.zip'; - $zipContent = GeneralUtility::makeInstance(RequestFactory::class)->request(self::zipFilePath . $zipFilename)->getBody()->getContents(); - if ($zipContent) { - GeneralUtility::writeFile($localZipFile, $zipContent); - $extractTo = $localZipPath; - $zip = new \ZipArchive; - if ($zip->open($localZipFile) === TRUE) { - $zip->extractTo($extractTo); - $zip->close(); - } else { - throw new \InvalidArgumentException('Sorry ZIP creation failed at this time! Set the constant "bootstrap.cdn.noZip=1" and try again.', 1657464538); - } - - $renameFrom = GeneralUtility::getFileAbsFileName(self::localZipPath.'bootstrap-'.$bootstrapVersion.'/scss'); - $renameTo = GeneralUtility::getFileAbsFileName(self::localZipPath.'scss'); - if ( is_dir($renameFrom) ) { - rename($renameFrom, $renameTo); - } - - parent::rmDir(GeneralUtility::getFileAbsFileName(self::localZipPath.'bootstrap-'.$bootstrapVersion)); - $zipFile = GeneralUtility::getFileAbsFileName(self::localZipPath.self::localZipFile); - - if (file_exists($zipFile)) unlink($zipFile); - } else { - throw new \InvalidArgumentException('No content from GitHub archive!', 1657464783); - } - } - - - public function getBootstrapFilesNoZip($settings, $bootstrapVersion, $customPath): void - { - $gitURL = 'https://raw.githubusercontent.com/twbs/bootstrap/'; - $bootstrapPath = 'fileadmin/T3SB/Resources/Public/Contrib/Bootstrap/scss'; - - # get the Boostrap SCSS-Files - if ( $bootstrapVersion > '5.1.3') { - $scssList = '_accordion.scss, _alert.scss, _badge.scss, _breadcrumb.scss, _button-group.scss, _buttons.scss, _card.scss, _carousel.scss, _close.scss, _containers.scss, _dropdown.scss, _forms.scss, _functions.scss, _grid.scss, _helpers.scss, _images.scss, _list-group.scss, _maps.scss, _mixins.scss, _modal.scss, _nav.scss, _navbar.scss, _offcanvas.scss, _pagination.scss, _placeholders.scss, _popover.scss, _progress.scss, _reboot.scss, _root.scss, _spinners.scss, _tables.scss, _toasts.scss, _tooltip.scss, _transitions.scss, _type.scss, _utilities.scss, _variables.scss, bootstrap-grid.scss, bootstrap-reboot.scss, bootstrap-utilities.scss, bootstrap.scss'; - } else { - $scssList = '_accordion.scss, _alert.scss, _badge.scss, _breadcrumb.scss, _button-group.scss, _buttons.scss, _card.scss, _carousel.scss, _close.scss, _containers.scss, _dropdown.scss, _forms.scss, _functions.scss, _grid.scss, _helpers.scss, _images.scss, _list-group.scss, _mixins.scss, _modal.scss, _nav.scss, _navbar.scss, _offcanvas.scss, _pagination.scss, _placeholders.scss, _popover.scss, _progress.scss, _reboot.scss, _root.scss, _spinners.scss, _tables.scss, _toasts.scss, _tooltip.scss, _transitions.scss, _type.scss, _utilities.scss, _variables.scss, bootstrap-grid.scss, bootstrap-reboot.scss, bootstrap-utilities.scss, bootstrap.scss'; - } - - $mixinsList = '_alert.scss, _backdrop.scss, _banner.scss, _border-radius.scss, _box-shadow.scss, _breakpoints.scss, _buttons.scss, _caret.scss, _clearfix.scss, _color-scheme.scss, _container.scss, _deprecate.scss, _forms.scss, _gradients.scss, _grid.scss, _image.scss, _list-group.scss, _lists.scss, _pagination.scss, _reset-text.scss, _resize.scss, _table-variants.scss, _text-truncate.scss, _transition.scss, _utilities.scss, _visually-hidden.scss'; - - $utilitiesList = '_api.scss'; - - $formsList = '_floating-labels.scss, _form-check.scss, _form-control.scss, _form-range.scss, _form-select.scss, _form-text.scss, _input-group.scss, _labels.scss, _validation.scss'; - - $helpersList = '_clearfix.scss, _color-bg.scss, _colored-links.scss, _position.scss, _ratio.scss, _stacks.scss, _stretched-link.scss, _text-truncation.scss, _visually-hidden.scss, _vr.scss'; - - foreach (explode(',', $scssList) as $scss ) { - $customFileName = trim($scss); - $customFile = $customPath.$customFileName; - $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/'.$customFileName; - $customContent = GeneralUtility::getURL($cdnPath); - if (file_exists($customFile)) unlink($customFile); - if (!is_dir($customPath)) mkdir($customPath, 0777, true); - GeneralUtility::writeFile($customFile, $customContent); - } - - $customDir = $bootstrapPath.'/mixins/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - - foreach (explode(',', $mixinsList) as $mixins ) { - $customFileName = trim($mixins); - $customFile = $customPath.$customFileName; - $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/mixins/'.$customFileName; - $customContent = GeneralUtility::getURL($cdnPath); - if (file_exists($customFile)) unlink($customFile); - if (!is_dir($customPath)) mkdir($customPath, 0777, true); - GeneralUtility::writeFile($customFile, $customContent); - } - - $customDir = $bootstrapPath.'/utilities/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - - foreach (explode(',', $utilitiesList) as $utils ) { - $customFileName = trim($utils); - $customFile = $customPath.$customFileName; - $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/utilities/'.$customFileName; - $customContent = GeneralUtility::getURL($cdnPath); - if (file_exists($customFile)) unlink($customFile); - if (!is_dir($customPath)) mkdir($customPath, 0777, true); - GeneralUtility::writeFile($customFile, $customContent); - } - - $customDir = $bootstrapPath.'/forms/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - - - foreach (explode(',', $formsList) as $forms ) { - $customFileName = trim($forms); - $customFile = $customPath.$customFileName; - $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/forms/'.$customFileName; - $customContent = GeneralUtility::getURL($cdnPath); - if (file_exists($customFile)) unlink($customFile); - if (!is_dir($customPath)) mkdir($customPath, 0777, true); - GeneralUtility::writeFile($customFile, $customContent); - } - - $customDir = $bootstrapPath.'/helpers/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - - foreach (explode(',', $helpersList) as $helpers ) { - $customFileName = trim($helpers); - $customFile = $customPath.$customFileName; - $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/helpers/'.$customFileName; - $customContent = GeneralUtility::getURL($cdnPath); - if (file_exists($customFile)) unlink($customFile); - if (!is_dir($customPath)) mkdir($customPath, 0777, true); - GeneralUtility::writeFile($customFile, $customContent); - } - - $customDir = $bootstrapPath.'/vendor/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - - $customFileName = '_rfs.scss'; - $customFile = $customPath.$customFileName; - $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/vendor/_rfs.scss'; - $customContent = GeneralUtility::getURL($cdnPath); - if (file_exists($customFile)) unlink($customFile); - if (!is_dir($customPath)) mkdir($customPath, 0777, true); - GeneralUtility::writeFile($customFile, $customContent); - - } - + } + GeneralUtility::writeFile($includeFile, $includeContent); + } + } + + $tempPath = GeneralUtility::getFileAbsFileName('typo3temp/assets/t3sbootstrap/css/'); + self::deleteFilesFromDirectory($tempPath); + $customPath = $baseDir.'Resources/Public/Contrib/Bootstrap/scss/bootstrap/scss/'; + $customFileName = 'bootstrap.scss'; + $customFile = $customPath.$customFileName; + $customContent = GeneralUtility::getURL($customFile); + $length = 0; + if ($customContent) { + $length = strlen($customContent); + } + + foreach ($settings['optimize'] as $component=>$import) { + if (!$import && $customContent) { + $find = '@import "'.$component.'";'; + $replace = '// @import "'.$component.'";'; + $customContent = str_replace($find, $replace, $customContent); + } + } + + if ($customContent && $length < strlen($customContent)) { + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + GeneralUtility::writeFile($customFile, $customContent); + } + + if (is_dir($baseDir.'Resources/Public/Contrib/Bootstrap/scss/')) { + return 0; + } else { + throw new \InvalidArgumentException('Check the bootstrap version in the constant editor for validity!', 1657204821); + + return 1; + } + } else { + throw new \InvalidArgumentException('You have to activate SCSS in the EM config!', 1657204821); + + return 1; + } + } + + + private function writeCustomFile($customPath, $customFileName, $settings, $name) + { + $customFile = $customPath.$customFileName; + + $keepVariables = (int)$settings['keepVariables']; + if (file_exists($customFile)) { + $copyFile = $customPath.'_'.time().'-'.$customFileName; + + if (!copy($customFile, $copyFile)) { + return false; + } elseif (empty($keepVariables)) { + unlink($customFile); + } + } + + if (!file_exists($customFile) && empty($keepVariables)) { + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + $customContent = $name == '_variables' ? '// Overrides Bootstrap variables'.PHP_EOL.'// $enable-shadows: true;'.PHP_EOL.'// $enable-gradients: true;'.PHP_EOL.'// $enable-negative-margins: true;' : '// Your own SCSS'; + + if (!empty($settings['bootswatch'])) { + $customContent = @file_get_contents($settings['bootswatchURL'].strtolower($settings['bootswatch']).'/'.$name.'.scss'); + if ($name == '_variables') { + $customContent = str_replace(' !default', '', $customContent); + } + } + + GeneralUtility::writeFile($customFile, $customContent); + } + + return true; + } + + + private function deleteFilesFromDirectory($directory) + { + if (is_dir($directory)) { + if ($dh = opendir($directory)) { + while (($file = readdir($dh)) !== false) { + if ($file!='.' && $file !='..' && $file[0] != '_') { + unlink(''.$directory.''.$file.''); + } + } + closedir($dh); + } + } + } + + + public function getBootstrapFiles($bootstrapVersion, $baseDir): void + { + $localZipPath = $baseDir.'Resources/Public/Contrib/Bootstrap/'; + + if (is_dir($localZipPath)) { + parent::rmDir($localZipPath); + } + mkdir($localZipPath, 0777, true); + $localZipFile = $baseDir.'Resources/Public/Contrib/Bootstrap/t3sb.zip'; + $zipFilename = 'v'.$bootstrapVersion.'.zip'; + $requestFactory = GeneralUtility::makeInstance(RequestFactory::class); + # from cdn to local + $zipFilePath = 'https://github.com/twbs/bootstrap/archive/'; + $zipContent = $requestFactory->request($zipFilePath . $zipFilename)->getBody()->getContents(); + + if ($zipContent) { + GeneralUtility::writeFile($localZipFile, $zipContent); + $extractTo = $localZipPath; + $zip = new \ZipArchive(); + if ($zip->open($localZipFile) === true) { + $zip->extractTo($extractTo); + $zip->close(); + } else { + throw new \InvalidArgumentException('Sorry ZIP creation failed at this time! Set the constant "bootstrap.cdn.noZip=1" and try again.', 1657464538); + } + + $renameFrom = $baseDir.'Resources/Public/Contrib/Bootstrap/bootstrap-'.$bootstrapVersion.'/scss'; + $renameTo = $baseDir.'Resources/Public/Contrib/Bootstrap/scss'; + if (is_dir($renameFrom)) { + rename($renameFrom, $renameTo); + } + + parent::rmDir($baseDir.'Resources/Public/Contrib/Bootstrap/bootstrap-'.$bootstrapVersion); + $zipFile = $baseDir.'Resources/Public/Contrib/Bootstrap/t3sb.zip'; + + if (file_exists($zipFile)) { + unlink($zipFile); + } + } else { + throw new \InvalidArgumentException('No content from GitHub archive!', 1657464783); + } + } + + + public function getBootstrapFilesNoZip($settings, $bootstrapVersion, $customPath, $baseDir): void + { + $gitURL = 'https://raw.githubusercontent.com/twbs/bootstrap/'; + $bootstrapPath = $baseDir.'Resources/Public/Contrib/Bootstrap/scss'; + + # get the Boostrap SCSS-Files + if ($bootstrapVersion > '5.1.3') { + $scssList = '_accordion.scss, _alert.scss, _badge.scss, _breadcrumb.scss, _button-group.scss, _buttons.scss, _card.scss, _carousel.scss, _close.scss, _containers.scss, _dropdown.scss, _forms.scss, _functions.scss, _grid.scss, _helpers.scss, _images.scss, _list-group.scss, _maps.scss, _mixins.scss, _modal.scss, _nav.scss, _navbar.scss, _offcanvas.scss, _pagination.scss, _placeholders.scss, _popover.scss, _progress.scss, _reboot.scss, _root.scss, _spinners.scss, _tables.scss, _toasts.scss, _tooltip.scss, _transitions.scss, _type.scss, _utilities.scss, _variables.scss, bootstrap-grid.scss, bootstrap-reboot.scss, bootstrap-utilities.scss, bootstrap.scss'; + } else { + $scssList = '_accordion.scss, _alert.scss, _badge.scss, _breadcrumb.scss, _button-group.scss, _buttons.scss, _card.scss, _carousel.scss, _close.scss, _containers.scss, _dropdown.scss, _forms.scss, _functions.scss, _grid.scss, _helpers.scss, _images.scss, _list-group.scss, _mixins.scss, _modal.scss, _nav.scss, _navbar.scss, _offcanvas.scss, _pagination.scss, _placeholders.scss, _popover.scss, _progress.scss, _reboot.scss, _root.scss, _spinners.scss, _tables.scss, _toasts.scss, _tooltip.scss, _transitions.scss, _type.scss, _utilities.scss, _variables.scss, bootstrap-grid.scss, bootstrap-reboot.scss, bootstrap-utilities.scss, bootstrap.scss'; + } + + $mixinsList = '_alert.scss, _backdrop.scss, _banner.scss, _border-radius.scss, _box-shadow.scss, _breakpoints.scss, _buttons.scss, _caret.scss, _clearfix.scss, _color-scheme.scss, _container.scss, _deprecate.scss, _forms.scss, _gradients.scss, _grid.scss, _image.scss, _list-group.scss, _lists.scss, _pagination.scss, _reset-text.scss, _resize.scss, _table-variants.scss, _text-truncate.scss, _transition.scss, _utilities.scss, _visually-hidden.scss'; + + $utilitiesList = '_api.scss'; + + $formsList = '_floating-labels.scss, _form-check.scss, _form-control.scss, _form-range.scss, _form-select.scss, _form-text.scss, _input-group.scss, _labels.scss, _validation.scss'; + + $helpersList = '_clearfix.scss, _color-bg.scss, _colored-links.scss, _position.scss, _ratio.scss, _stacks.scss, _stretched-link.scss, _text-truncation.scss, _visually-hidden.scss, _vr.scss'; + + foreach (explode(',', $scssList) as $scss) { + $customFileName = trim($scss); + $customFile = $customPath.$customFileName; + $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/'.$customFileName; + $customContent = GeneralUtility::getURL($cdnPath); + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + GeneralUtility::writeFile($customFile, $customContent); + } + + $customPath = $bootstrapPath.'/mixins/'; + + foreach (explode(',', $mixinsList) as $mixins) { + $customFileName = trim($mixins); + $customFile = $customPath.$customFileName; + $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/mixins/'.$customFileName; + $customContent = GeneralUtility::getURL($cdnPath); + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + GeneralUtility::writeFile($customFile, $customContent); + } + + $customPath = $bootstrapPath.'/utilities/'; + + foreach (explode(',', $utilitiesList) as $utils) { + $customFileName = trim($utils); + $customFile = $customPath.$customFileName; + $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/utilities/'.$customFileName; + $customContent = GeneralUtility::getURL($cdnPath); + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + GeneralUtility::writeFile($customFile, $customContent); + } + + $customPath = $bootstrapPath.'/forms/'; + + foreach (explode(',', $formsList) as $forms) { + $customFileName = trim($forms); + $customFile = $customPath.$customFileName; + $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/forms/'.$customFileName; + $customContent = GeneralUtility::getURL($cdnPath); + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + GeneralUtility::writeFile($customFile, $customContent); + } + + $customPath = $bootstrapPath.'/helpers/'; + foreach (explode(',', $helpersList) as $helpers) { + $customFileName = trim($helpers); + $customFile = $customPath.$customFileName; + $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/helpers/'.$customFileName; + $customContent = GeneralUtility::getURL($cdnPath); + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + GeneralUtility::writeFile($customFile, $customContent); + } + + $customPath = $bootstrapPath.'/vendor/'; + $customFileName = '_rfs.scss'; + $customFile = $customPath.$customFileName; + $cdnPath = $gitURL.'v'.trim($bootstrapVersion).'/scss/vendor/_rfs.scss'; + $customContent = GeneralUtility::getURL($cdnPath); + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + GeneralUtility::writeFile($customFile, $customContent); + } } diff --git a/Classes/Components/Button.php b/Classes/Components/Button.php index eddbb419..19c57cb5 100644 --- a/Classes/Components/Button.php +++ b/Classes/Components/Button.php @@ -1,4 +1,5 @@ $dropdownItem) { + $dIarray = explode(' ', $dropdownItem['list']['group']); + if (str_contains($dropdownItem['list']['group'], '"')) { + // if title have more than one word + $btnDropdownItem[$key]['link'] = $dIarray[0]; + $btnDropdownItem[$key]['target'] = $dIarray[1] != '-' ? $dIarray[1] : ''; + $btnDropdownItem[$key]['class'] = !empty($dIarray[2]) && $dIarray[2] != '-' ? $dIarray[2] : ''; + $btnDropdownItem[$key]['title'] = !empty($dIarray[3]) && $dIarray[3] != '-' ? str_replace('"', '', $dIarray[3].' '.$dIarray[4]) : 'no tilte'; + $btnDropdownItem[$key]['param'] = !empty($dIarray[5]) ? $dIarray[5] : ''; + } else { + $btnDropdownItem[$key]['link'] = $dIarray[0]; + $btnDropdownItem[$key]['target'] = !empty($dIarray[1]) && $dIarray[1] != '-' ? $dIarray[1] : ''; + $btnDropdownItem[$key]['class'] = !empty($dIarray[2]) && $dIarray[2] != '-' ? $dIarray[2] : ''; + $btnDropdownItem[$key]['title'] = !empty($dIarray[3]) && $dIarray[3] != '-' ? $dIarray[3] : 'no title'; + $btnDropdownItem[$key]['param'] = !empty($dIarray[4]) ? $dIarray[4] : ''; + } + } + } + $processedData['dropdownItems'] = !empty($btnDropdownItem) ? $btnDropdownItem : ''; + $outline = !empty($flexconf['outline']) ? 'outline-' : ''; + $style = !empty($flexconf['style']) ? $flexconf['style'] : ''; + $typolinkButtonClass = ' btn btn-'.$outline.$style; + $typolinkButtonClass .= !empty($flexconf['btnsize']) && $flexconf['btnsize'] != 'default' ? ' '.$flexconf['btnsize'] : ''; + if (empty($parentflexconf)) { + $processedData['btn-block'] = false; + if (!empty($flexconf['block'])) { + $processedData['btn-block'] = true; + } + } + $headerPosition = ''; + if ($processedData['data']['header_position']) { + $headerPosition = $processedData['data']['header_position']; + if ($headerPosition == 'left') { + $headerPosition = ''; + } + if ($headerPosition == 'center') { + $headerPosition = 'text-center'; + } + if ($headerPosition == 'right') { + $headerPosition = 'd-md-flex justify-content-md-end'; + } + } - /** - * Returns the $processedData - */ - public function getProcessedData(array $processedData, array $flexconf, array $parentflexconf): array - { - - $btnDropdownItem = []; - if ( !empty($flexconf['dropdownItems']) && is_array($flexconf['dropdownItems']) ) { - $processedData['dropdowndirection'] = !empty($flexconf['direction']) ? ' '.$flexconf['direction'] : ''; - foreach ($flexconf['dropdownItems'] as $key=>$dropdownItem) { - $dIarray = explode(' ', $dropdownItem['list']['group']); - if (str_contains($dropdownItem['list']['group'], '"')) { - // if title have more than one word - $btnDropdownItem[$key]['link'] = $dIarray[0]; - $btnDropdownItem[$key]['target'] = $dIarray[1] != '-' ? $dIarray[1] : ''; - $btnDropdownItem[$key]['class'] = !empty($dIarray[2]) && $dIarray[2] != '-' ? $dIarray[2] : ''; - $btnDropdownItem[$key]['title'] = !empty($dIarray[3]) && $dIarray[3] != '-' ? str_replace('"', '', $dIarray[3].' '.$dIarray[4]) : 'no tilte'; - $btnDropdownItem[$key]['param'] = !empty($dIarray[5]) ? $dIarray[5] : ''; - } else { - $btnDropdownItem[$key]['link'] = $dIarray[0]; - $btnDropdownItem[$key]['target'] = !empty($dIarray[1]) && $dIarray[1] != '-' ? $dIarray[1] : ''; - $btnDropdownItem[$key]['class'] = !empty($dIarray[2]) && $dIarray[2] != '-' ? $dIarray[2] : ''; - $btnDropdownItem[$key]['title'] = !empty($dIarray[3]) && $dIarray[3] != '-' ? $dIarray[3] : 'no title'; - $btnDropdownItem[$key]['param'] = !empty($dIarray[4]) ? $dIarray[4] : ''; - } - } - } - $processedData['dropdownItems'] = !empty($btnDropdownItem) ? $btnDropdownItem : ''; - $outline = !empty($flexconf['outline']) ? 'outline-':''; - $style = !empty($flexconf['style']) ? $flexconf['style'] : ''; - $typolinkButtonClass = ' btn btn-'.$outline.$style; - $typolinkButtonClass .= !empty($flexconf['btnsize']) && $flexconf['btnsize'] != 'default' ? ' '.$flexconf['btnsize']:''; - if ( empty($parentflexconf) ) { - $processedData['btn-block'] = false; - if (!empty($flexconf['block'])) { - $processedData['btn-block'] = true; - } - } - $headerPosition = ''; - if ($processedData['data']['header_position']) { - $headerPosition = $processedData['data']['header_position']; - if ( $headerPosition == 'left' ) $headerPosition = ''; - if ( $headerPosition == 'center' ) $headerPosition = 'text-center'; - if ( $headerPosition == 'right' ) $headerPosition = 'd-md-flex justify-content-md-end'; - } - - $processedData['headerPosition'] = $headerPosition; - - if ( !empty($flexconf['fixedPosition']) ) { - $typolinkButtonClass .= ' d-none fixedPosition fixedPosition-'.$flexconf['fixedPosition']; - $typolinkButtonClass .= !empty($flexconf['rotate']) ? ' rotateFixedPosition rotate-'.$flexconf['rotate'] : ''; - $processedData['fixedButton'] = $flexconf['fixedPosition']; - } + $processedData['headerPosition'] = $headerPosition; - $processedData['linkTitle'] = !empty($flexconf['linkTitle']) ? $flexconf['linkTitle'] : ''; - $processedData['slideInButton'] = FALSE; - $processedData['slideInButtonFaIcon'] = FALSE; + if (!empty($flexconf['fixedPosition'])) { + $typolinkButtonClass .= ' d-none fixedPosition fixedPosition-'.$flexconf['fixedPosition']; + $typolinkButtonClass .= !empty($flexconf['rotate']) ? ' rotateFixedPosition rotate-'.$flexconf['rotate'] : ''; + $processedData['fixedButton'] = $flexconf['fixedPosition']; + } - if ( !empty($parentflexconf['fixedPosition']) && $parentflexconf['fixedPosition'] == 'right' - && $parentflexconf['slideIn'] - && $parentflexconf['visiblePart'] - && $parentflexconf['vertical'] - ) { - // slide in button - $processedData['slideInButton'] = TRUE; + $processedData['linkTitle'] = !empty($flexconf['linkTitle']) ? $flexconf['linkTitle'] : ''; + $processedData['slideInButton'] = false; + $processedData['slideInButtonFaIcon'] = false; - if ( $processedData['data']['tx_t3sbootstrap_header_fontawesome'] ) { - $processedData['slideInButtonFaIcon'] = TRUE; - } else { - $processedData['data']['tx_t3sbootstrap_header_fontawesome'] = 'fa-solid fa-ban text-danger'; - $processedData['slideInButtonFaIcon'] = TRUE; - } - } + if (!empty($parentflexconf['fixedPosition']) && $parentflexconf['fixedPosition'] == 'right' + && $parentflexconf['slideIn'] + && $parentflexconf['visiblePart'] + && $parentflexconf['vertical'] + ) { + // slide in button + $processedData['slideInButton'] = true; - $processedData['class'] .= $typolinkButtonClass; + if ($processedData['data']['tx_t3sbootstrap_header_fontawesome']) { + $processedData['slideInButtonFaIcon'] = true; + } else { + $processedData['data']['tx_t3sbootstrap_header_fontawesome'] = 'fa-solid fa-ban text-danger'; + $processedData['slideInButtonFaIcon'] = true; + } + } - return $processedData; - } + $processedData['class'] .= $typolinkButtonClass; + return $processedData; + } } diff --git a/Classes/Components/Card.php b/Classes/Components/Card.php index 072f1103..640cd18c 100644 --- a/Classes/Components/Card.php +++ b/Classes/Components/Card.php @@ -1,4 +1,5 @@ convertFlexFormContentToArray($parentFlexformData['tx_t3sbootstrap_flexform']); + $parentflexconf =$flexformHelper->addMissingElements($parentflexconf, $parentFlexformData['CType'], true); + } + } + $cardData = $flexconf; + + // crop max characters + $cardData['cropMaxCharacters'] = !empty($parentflexconf['cropMaxCharacters']) ? $parentflexconf['cropMaxCharacters'] : ''; + // image position + if ((int)$processedData['data']['imageorient'] == 8) { + $processedData['data']['imageorient'] = 'bottom'; + } else { + $processedData['data']['imageorient'] = 'top'; + } + // title position + if (!empty($cardData['title']['onTop']) && $processedData['data']['imageorient'] == 'top' && !$cardData['image']['overlay']) { + $cardData['title']['position'] = 'top'; + } else { + $cardData['title']['position'] = 'default'; + } + // button + if (!empty($processedData['data']['bodytext']) && !empty($processedData['data']['tx_t3sbootstrap_bodytext'])) { + $cardData['button']['position'] = 'bottom'; + } elseif (!empty($processedData['data']['tx_t3sbootstrap_bodytext'])) { + $cardData['button']['position'] = 'top'; + } else { + $cardData['button']['position'] = 'bottom'; + } + if (!empty($flexconf['button']['enable'])) { + $cardData['button']['link'] = $processedData['data']['header_link']; + $processedData['data']['header_link'] = ''; + } + $cardData['button']['linkClass'] = !empty($flexconf['button']['outline']) ? '-outline' : ''; + $cardData['button']['linkClass'] .= !empty($flexconf['button']['style']) ? '-'.$flexconf['button']['style'] : ''; + $cardData['button']['linkClass'] .= !empty($flexconf['button']['block']) ? ' btn-block' : ''; + $cardData['button']['linkClass'] .= !empty($flexconf['button']['stretchedLink']) ? ' stretched-link' : ''; + // dimensions + $cardData['dimensions']['width'] = $processedData['data']['imagewidth']; + $cardData['dimensions']['height'] = $processedData['data']['imageheight']; + // class + $cardClass = !empty($processedData['class']) ? $processedData['class'] : ''; + $cardClass = 'card'.$cardClass; + $cardClass .= !empty($flexconf['button']['stretchedLink']) ? ' ce-link-content' : ''; + // image + if (!empty($cardData['image']['overlay'])) { + $cardClass .= ' overflow-hidden'; + $cardData['image']['class'] = 'img-fluid'; + $cardData['image']['overlay'] = 'card-img-overlay d-flex'; + $cardData['mobile']['overlay'] = false; + } else { + if (!empty($cardData['mobile']['overlay'])) { + # card-img-overlay for mobile < 576 by JS and class overlay + $cardData['mobile']['overlay'] = 'img-overlay'; + } + if ($processedData['data']['imageorient'] == 'top') { + if (!empty($cardData['title']['onTop']) || !empty($processedData['data']['tx_t3sbootstrap_cardheader'])) { + $cardData['image']['class'] = 'img-fluid'; + } else { + $cardData['image']['class'] = 'card-img-top img-fluid'; + } + } else { + if ($processedData['data']['tx_t3sbootstrap_cardfooter']) { + $cardData['image']['class'] = 'img-fluid'; + } else { + $cardData['image']['class'] = 'card-img-bottom img-fluid'; + } + } + } + // block + if (empty($processedData['data']['bodytext']) && empty($processedData['data']['tx_t3sbootstrap_bodytext']) + && empty($processedData['data']['header']) && empty($processedData['data']['subheader'])) { + $cardData['block']['enable'] = false; + } else { + $cardData['block']['enable'] = true; + } + // flip card + if (!empty($flexconf['flipcard'])) { + $backstyle = ''; + $backclass = ''; + $cardClass .= ' flip-card border-0 bg-transparent'; + $cardData['flipcard'] = true; + $cardData['rotateY'] = $flexconf['rotateY']; + if ($processedData['data']['tx_t3sbootstrap_textcolor']) { + $backclass .= 'text-'.$processedData['data']['tx_t3sbootstrap_textcolor']; + } + if ($processedData['data']['tx_t3sbootstrap_bgcolor']) { + $backstyle .= $processedData['data']['tx_t3sbootstrap_bgcolor']; + } else { + if ($processedData['data']['tx_t3sbootstrap_contextcolor']) { + $backclass .= ' bg-'.$processedData['data']['tx_t3sbootstrap_contextcolor']; + } + } + $processedData['backclass'] = trim((string)$backclass); + $processedData['backstyle'] = $backstyle; + } else { + $cardClass .= $processedData['data']['tx_t3sbootstrap_header_position'] ? ' '.$processedData['data']['tx_t3sbootstrap_header_position'] : ''; + } + // list group + $cardData['list'] = []; + if (!empty($processedData['data']['tx_t3sbootstrap_list_item'])) { + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + $queryBuilder = $connectionPool->getQueryBuilderForTable('tx_t3sbootstrap_list_item_inline'); + $listGroup = $queryBuilder + ->select('listitem') + ->from('tx_t3sbootstrap_list_item_inline') + ->where( + $queryBuilder->expr()->eq('parentid', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT)) + ) + ->executeQuery() + ->fetchAllAssociative(); + + $cardData['list'] = $listGroup; + } + + // profile card + $cardData['multiImage']['enable'] = false; + if (!empty($flexconf['multiImage']['enable'])) { + $cardData['multiImage']['enable'] = true; + $cardData['multiImage']['percent'] = '0.'.$flexconf['multiImage']['percent']; + $cardData['multiImage']['style'] = 'top: -' . $flexconf['multiImage']['percent']/2 .'px'; + $borderColor = $flexconf['multiImage']['borderColor'] ? ' border-'.$flexconf['multiImage']['borderColor'] : ''; + $shadow = $flexconf['multiImage']['shadow'] ? ' circularshadow' : ''; + $cardData['multiImage']['shadow'] = $flexconf['multiImage']['shadow'] ? true : false; + $cardData['multiImage']['border'] = $flexconf['multiImage']['borderWidth'].$borderColor.$shadow; + $cardData['multiImage']['slope'] = $flexconf['multiImage']['diagonal'] ? $flexconf['multiImage']['slope'] : 0; + $cardData['multiImage']['socialmedia']['enable'] = $flexconf['multiImage']['socialmedia']['enable']; + $cardData['multiImage']['socialmedia']['footer'] = $flexconf['multiImage']['socialmedia']['footer']; + if (!empty($flexconf['multiImage']['socialmedia']['enable'])) { + foreach ($flexconf['multiImage']['socialmedia'] as $key=>$socialmedia) { + if ($key != 'enable' && $key != 'footer' && !empty($socialmedia)) { + $cardData['multiImage']['socialmediaLinks'][$key] = $socialmedia; + } + } + } + } + + # if ( !empty($cardData['square']['enable']) ) { + # $cardClass .= ' rounded-0 border-0'; + # } + + if (!empty($cardData['tiling']['enable'])) { + $cardClass = 'card tiling rounded-0 border-0'.$processedData['class']; + if (empty($processedData['data']['tx_t3sbootstrap_contextcolor'])) { + $cardClass .= ' bg-transparent'; + } + } + + // header position + if ($processedData['data']['header_position']) { + $headerPosition = $processedData['data']['header_position']; + if ($headerPosition == 'left') { + $headerPosition = 'start'; + } + if ($headerPosition == 'right') { + $headerPosition = 'end'; + } + $cardClass .= ' text-'.$headerPosition; + } + // effect + if (!empty($cardData['effect'])) { + $cardClass .= ' card-effect-'.$cardData['effect']; + if (!empty($cardData['effectColor'])) { + $cardClass .= ' '.$cardData['effectColor']; + } + } + // custom border class + if (!empty($cardData['cardborder'])) { + $cardClass .= ' border-'.$cardData['cardborderstyle']; + } + // parent equal Height + if (!empty($parentflexconf['equalHeight']) && isset($parentflexconf['card_wrapper']) && $parentflexconf['card_wrapper'] !== 'group') { + $cardClass .= ' h-100'; + } + + if (!empty($cardData['tiling']['enable'])) { + $processedData['addmedia']['imgclass'] = ' rounded-0 '.$cardData['image']['class']; + $bgMediaQueries = '768,576'; + $bgimages = GeneralUtility::makeInstance(BackgroundImageUtility::class) + ->getBgImage( + $processedData['data']['uid'], + 'tt_content', + false, + false, + $flexconf, + false, + $processedData['data']['uid'], + $bgMediaQueries + ); + if ($bgimages) { + $cardData['bgimages'] = $bgimages; + } + } + + $processedData['class'] = trim($cardClass); + + // addmedia + $processedData['addmedia']['imgclass'] = $cardData['image']['class']; + $processedData['addmedia']['imgclass'] .= !empty($flexconf['horizontal']) ? ' rounded-start' : ''; + $processedData['addmedia']['figureclass'] = ' text-center'; + $processedData['addmedia']['figureclass'] .= !empty($flexconf['horizontal']) ? ' d-block' : ''; + + if (!empty($cardData['square']['enable'])) { + $processedData['addmedia']['imgclass'] = 'img-fluid'; + } + + $processedData['card'] = $cardData; - /** - * Returns the $processedData - */ - public function getProcessedData(array $processedData, array $flexconf, array $parentflexconf): array - { - $flexformService = GeneralUtility::makeInstance(FlexFormService::class); - $flexformHelper = GeneralUtility::makeInstance(FlexformHelper::class); - $parentflexconf = []; - $parentUid = $processedData['data']['tx_container_parent']; - if ($parentUid) { - $parentFlexformData = BackendUtility::getRecord('tt_content', $parentUid, 'CType, tx_t3sbootstrap_flexform'); - if ($parentFlexformData['tx_t3sbootstrap_flexform']) { - $parentflexconf = $flexformService->convertFlexFormContentToArray($parentFlexformData['tx_t3sbootstrap_flexform']); - $parentflexconf =$flexformHelper->addMissingElements($parentflexconf, $parentFlexformData['CType'], TRUE); - } - } - $cardData = $flexconf; - // crop max characters - $cardData['cropMaxCharacters'] = !empty($parentflexconf['cropMaxCharacters']) ? $parentflexconf['cropMaxCharacters'] : ''; - // image position - if ( (int)$processedData['data']['imageorient'] == 8 ) { - $processedData['data']['imageorient'] = 'bottom'; - } else { - $processedData['data']['imageorient'] = 'top'; - } - // title position - if ( !empty($cardData['title']['onTop']) && $processedData['data']['imageorient'] == 'top' && !$cardData['image']['overlay'] ) { - $cardData['title']['position'] = 'top'; - } else { - $cardData['title']['position'] = 'default'; - } - // button - if ( !empty($processedData['data']['bodytext']) && !empty($processedData['data']['tx_t3sbootstrap_bodytext']) ) { - $cardData['button']['position'] = 'bottom'; - } elseif ( !empty($processedData['data']['tx_t3sbootstrap_bodytext']) ) { - $cardData['button']['position'] = 'top'; - } else { - $cardData['button']['position'] = 'bottom'; - } - if (!empty($flexconf['button']['enable'])) { - $cardData['button']['link'] = $processedData['data']['header_link']; - $processedData['data']['header_link'] = ''; - } - $cardData['button']['linkClass'] = !empty($flexconf['button']['outline']) ? '-outline': ''; - $cardData['button']['linkClass'] .= !empty($flexconf['button']['style']) ? '-'.$flexconf['button']['style'] : ''; - $cardData['button']['linkClass'] .= !empty($flexconf['button']['block']) ? ' btn-block' : ''; - $cardData['button']['linkClass'] .= !empty($flexconf['button']['stretchedLink']) ? ' stretched-link' : ''; - // dimensions - $cardData['dimensions']['width'] = $processedData['data']['imagewidth']; - $cardData['dimensions']['height'] = $processedData['data']['imageheight']; - // class - $cardClass = 'card'.$processedData['class']; - $cardClass .= !empty($flexconf['button']['stretchedLink']) ? ' ce-link-content' : ''; - // image - if ( !empty($cardData['image']['overlay']) ) { - $cardClass .= ' overflow-hidden'; - $cardData['image']['class'] = 'img-fluid'; - $cardData['image']['overlay'] = 'card-img-overlay d-flex'; - $cardData['mobile']['overlay'] = FALSE; - } else { - if ( !empty($cardData['mobile']['overlay']) ) { - # card-img-overlay for mobile < 576 by JS and class overlay - $cardData['mobile']['overlay'] = 'img-overlay'; - } - if ( $processedData['data']['imageorient'] == 'top' ) { - if ( !empty($cardData['title']['onTop']) || !empty($processedData['data']['tx_t3sbootstrap_cardheader']) ) { - $cardData['image']['class'] = 'img-fluid'; - } else { - $cardData['image']['class'] = 'card-img-top img-fluid'; - } - } else { - if ( $processedData['data']['tx_t3sbootstrap_cardfooter'] ) { - $cardData['image']['class'] = 'img-fluid'; - } else { - $cardData['image']['class'] = 'card-img-bottom img-fluid'; - } - } - } - // block - if ( empty($processedData['data']['bodytext']) && empty($processedData['data']['tx_t3sbootstrap_bodytext']) - && empty($processedData['data']['header']) && empty($processedData['data']['subheader']) ) { - $cardData['block']['enable'] = FALSE; - } else { - $cardData['block']['enable'] = TRUE; - } - // flip card - if ( !empty($flexconf['flipcard']) ) { - $backstyle = ''; - $backclass = ''; - $cardClass .= ' flip-card border-0 bg-transparent'; - $cardData['flipcard'] = TRUE; - $cardData['rotateY'] = $flexconf['rotateY']; - if ( $processedData['data']['tx_t3sbootstrap_textcolor'] ) { - $backclass .= 'text-'.$processedData['data']['tx_t3sbootstrap_textcolor']; - } - if ( $processedData['data']['tx_t3sbootstrap_bgcolor'] ) { - $backstyle .= $processedData['data']['tx_t3sbootstrap_bgcolor']; - } else { - if ( $processedData['data']['tx_t3sbootstrap_contextcolor'] ) { - $backclass .= ' bg-'.$processedData['data']['tx_t3sbootstrap_contextcolor']; - } - } - $processedData['backclass'] = trim((string)$backclass); - $processedData['backstyle'] = $backstyle; - } else { - $cardClass .= $processedData['data']['tx_t3sbootstrap_header_position'] ? ' '.$processedData['data']['tx_t3sbootstrap_header_position']:''; - } - // list group - $cardData['list'] = []; - if (!empty($processedData['data']['tx_t3sbootstrap_list_item'])) { - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - $queryBuilder = $connectionPool->getQueryBuilderForTable('tx_t3sbootstrap_list_item_inline'); - $listGroup = $queryBuilder - ->select('listitem') - ->from('tx_t3sbootstrap_list_item_inline') - ->where( - $queryBuilder->expr()->eq('parentid', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT)) - ) - ->executeQuery() - ->fetchAll(); - - $cardData['list'] = $listGroup; - } - - // profile card - $cardData['multiImage']['enable'] = FALSE; - if ( !empty($flexconf['multiImage']['enable']) ) { - $cardData['multiImage']['enable'] = TRUE; - $cardData['multiImage']['percent'] = '0.'.$flexconf['multiImage']['percent']; - $cardData['multiImage']['style'] = 'top: -' . $flexconf['multiImage']['percent']/2 .'px'; - $borderColor = $flexconf['multiImage']['borderColor'] ? ' border-'.$flexconf['multiImage']['borderColor'] : ''; - $shadow = $flexconf['multiImage']['shadow'] ? ' circularshadow' : ''; - $cardData['multiImage']['shadow'] = $flexconf['multiImage']['shadow'] ? TRUE : FALSE; - $cardData['multiImage']['border'] = $flexconf['multiImage']['borderWidth'].$borderColor.$shadow; - $cardData['multiImage']['slope'] = $flexconf['multiImage']['diagonal'] ? $flexconf['multiImage']['slope'] : 0; - $cardData['multiImage']['socialmedia']['enable'] = $flexconf['multiImage']['socialmedia']['enable']; - $cardData['multiImage']['socialmedia']['footer'] = $flexconf['multiImage']['socialmedia']['footer']; - if (!empty($flexconf['multiImage']['socialmedia']['enable'])) { - foreach ($flexconf['multiImage']['socialmedia'] as $key=>$socialmedia) { - if ($key != 'enable' && $key != 'footer' && !empty($socialmedia)) { - $cardData['multiImage']['socialmediaLinks'][$key] = $socialmedia; - } - } - } - } - -# if ( !empty($cardData['square']['enable']) ) { -# $cardClass .= ' rounded-0 border-0'; -# } - - if ( !empty($cardData['tiling']['enable']) ) { - $cardClass = 'card tiling rounded-0 border-0 h-100'.$processedData['class']; - if (empty($processedData['data']['tx_t3sbootstrap_contextcolor'])) { - $cardClass .= ' bg-transparent'; - } - } - - // header position - if ( $processedData['data']['header_position'] ) { - $headerPosition = $processedData['data']['header_position']; - if ( $headerPosition == 'left' ) $headerPosition = 'start'; - if ( $headerPosition == 'right' ) $headerPosition = 'end'; - $cardClass .= ' text-'.$headerPosition; - } - // effect - if ( !empty($cardData['effect']) ) { - $cardClass .= ' card-effect-'.$cardData['effect']; - } - // custom border class - if ( !empty($cardData['cardborder']) ) { - $cardClass .= ' border-'.$cardData['cardborderstyle']; - } - // parent equal Height - if ( !empty($parentflexconf['equalHeight']) && isset($parentflexconf['card_wrapper']) && $parentflexconf['card_wrapper'] !== 'group' ) { - $cardClass .= ' h-100'; - } - - if ( !empty($cardData['tiling']['enable']) ) { - $processedData['addmedia']['imgclass'] = ' rounded-0 '.$cardData['image']['class']; - $bgMediaQueries = '768,576'; - $bgimages = GeneralUtility::makeInstance(BackgroundImageUtility::class) - ->getBgImage($processedData['data']['uid'], 'tt_content', FALSE, FALSE, - $flexconf, FALSE, $processedData['data']['uid'],$bgMediaQueries); - if ($bgimages) { - $cardData['bgimages'] = $bgimages; - } - } - - $processedData['class'] = trim($cardClass); - - // addmedia - $processedData['addmedia']['imgclass'] = $cardData['image']['class']; - $processedData['addmedia']['imgclass'] .= !empty($flexconf['horizontal']) ? ' rounded-start' : ''; - $processedData['addmedia']['figureclass'] = ' text-center'; - $processedData['addmedia']['figureclass'] .= !empty($flexconf['horizontal']) ? ' d-block' : ''; - - if ( !empty($cardData['square']['enable']) ) { - $processedData['addmedia']['imgclass'] = 'img-fluid'; - } - - $processedData['card'] = $cardData; - - if ( !empty($processedData['data']['imagewidth']) && !empty($flexconf['maxwidth'])) { - $processedData['style'] .= ' max-width: '.$processedData['data']['imagewidth'].'px;'; - } - - return $processedData; - } + if (!empty($processedData['data']['imagewidth']) && !empty($flexconf['maxwidth'])) { + $processedData['style'] .= ' max-width: '.$processedData['data']['imagewidth'].'px;'; + } + return $processedData; + } } diff --git a/Classes/Components/Carousel.php b/Classes/Components/Carousel.php index 4cabdc80..99e7929e 100644 --- a/Classes/Components/Carousel.php +++ b/Classes/Components/Carousel.php @@ -31,11 +31,11 @@ public function getProcessedData(array $processedData, array $flexconf, array $p $processedData['data']['header_link'] = ''; } - $flexconf['captionVAlign'] = $flexconf['captionVAlign'] ? $flexconf['captionVAlign'] : 'end'; - if ($flexconf['bgOverlay'] == 'caption') { + $flexconf['captionVAlign'] = !empty($flexconf['captionVAlign']) ? $flexconf['captionVAlign'] : 'end'; + if (!empty($flexconf['bgOverlay']) && $flexconf['bgOverlay'] == 'caption') { $innerCaptionStyle = $processedData['style'].' padding:15px 0; z-index:1'; $processedData['style'] = ''; - } elseif ($flexconf['bgOverlay'] == 'image') { + } elseif (!empty($flexconf['bgOverlay']) && $flexconf['bgOverlay'] == 'image') { $innerCaptionStyle = 'z-index:1'; } else { $processedData['style'] = ''; diff --git a/Classes/Controller/AbstractController.php b/Classes/Controller/AbstractController.php index 880faf85..9dd36dc2 100644 --- a/Classes/Controller/AbstractController.php +++ b/Classes/Controller/AbstractController.php @@ -1,4 +1,5 @@ rootPageId = $site->getRootPageId(); - $this->currentUid = (int) $this->request->getQueryParams()['id']; - $this->isSiteroot = $this->rootPageId === $this->currentUid ? TRUE : FALSE; - $this->tcaColumns = $GLOBALS['TCA']['tx_t3sbootstrap_domain_model_config']['columns']; - $this->isAdmin = $GLOBALS['BE_USER']->isAdmin(); - $this->configRepository = GeneralUtility::makeInstance(ConfigRepository::class); - $this->rootConfig = $this->configRepository->findOneByPid($this->rootPageId); - $this->persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class); - - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template'); - $this->rootTemplates = $queryBuilder - ->select('uid','pid', 'constants') - ->from('sys_template') - ->where( - $queryBuilder->expr()->eq('root', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)) - ) - ->executeQuery()->fetchAll(); - - $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class); - } - - - /** - * SCSS in the BE - */ - protected function getCustomScss( string $file ): array - { - $assignedOptions = []; - $customScssDir = !empty($this->settings['customScssPath']) ? $this->settings['customScssPath'] : 'fileadmin/T3SB/Resources/Public/SCSS/'; - $customScssFilePath = GeneralUtility::getFileAbsFileName($customScssDir); - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); - $result = $queryBuilder - ->select('*') - ->from('pages') - ->where( - $queryBuilder->expr()->eq('sys_language_uid', 0), - $queryBuilder->expr()->eq('is_siteroot', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)) - ) - ->executeQuery(); - - $siteroots = $result->fetchAll(); - $customScssFileName = ''; - - foreach ($siteroots as $key=>$siteroot) { - if ( $siteroot['uid'] == $this->currentUid ) { - if ( $key === 0 ) { - $customScssFileName = $file.'.scss'; - } else { - $customScssFileName = $file.'-'.$siteroot['uid'].'.scss'; - } - } - } - - $customScssFile = $customScssFilePath.$customScssFileName; - - if ( file_exists($customScssFile) ) { - - $customScssFile = $customScssFilePath.$customScssFileName; - if ($file == 'custom') { - $assignedOptions['customScss'] = TRUE; - } - $arguments = $this->request->getArguments(); - if ( !empty($arguments['t3sbootstrap'][$file]) ) { - $scss = $arguments['t3sbootstrap'][$file]; - } else { - $scss = !empty($arguments[$file]) ? $arguments[$file] : ''; - } - if ($scss) { - $assignedOptions[$file] = $scss; - $handle = fopen($customScssFile, 'w') or die('Cannot open file: '.$customScssFile); - fwrite($handle, $scss); - fclose($handle); - if ($file == 'custom') { - // clean typo3temp/assets/t3sbootstrap/css/ - $tempPath = GeneralUtility::getFileAbsFileName('typo3temp/assets/t3sbootstrap/css/'); - self::deleteFilesFromDirectory($tempPath); - } - } else { - $handle = fopen($customScssFile, 'r'); - if (filesize($customScssFile)) { - $assignedOptions[$file] = fread($handle,filesize($customScssFile)); - } else { - $assignedOptions[$file] = '// empty file'; - } - fclose($handle); - } - } - - return (array)$assignedOptions; - } - - - - /** - * prepare options for select fields - */ - protected function getFieldsOptions(): array - { - foreach ( $this->tcaColumns as $field=>$columns ) { - // is select-field - if ( $columns['config']['type'] == 'select' && $columns['config']['renderType'] == 'selectSingle' ) { - $var = GeneralUtility::underscoredToLowerCamelCase($field).'Options'; - foreach ( $columns['config']['items'] as $key=>$entry ) { - $option = new \stdClass(); - $option->key = $entry['value']; - $option->value = $entry['label']; - $fieldsOptions[$var][$entry['value']] = $option; - } - } - } - - return $fieldsOptions; - } - - - /** - * take over $rootConfig settings - */ - protected function getNewConfig(Config $rootConfig): Config - { - $newConfig = new Config(); - - foreach ( $this->tcaColumns as $field=>$columns ) { - $var = GeneralUtility::underscoredToUpperCamelCase($field); - $set = 'set'.$var; - $get = 'get'.$var; - $newConfig->$set( $rootConfig->$get() ); - } - - return $newConfig; - } - - - /** - * compare config with rootconfig - */ - protected function compareConfig(Config $config): array - { - $compare = []; - - foreach ( $this->tcaColumns as $field=>$columns ) { - $filedsArr[] = 'get'.GeneralUtility::underscoredToUpperCamelCase($field); - } - foreach ($filedsArr as $field) { - if ( $config->$field() !== $this->rootConfig->$field() ) { - $key = lcfirst(substr($field,3)); - $rootConfigField = $this->rootConfig->$field(); - if ( $rootConfigField === TRUE ) { - $compare[$key] = 'enabled'; - } elseif ( $rootConfigField === FALSE ) { - $compare[$key] = 'disabled'; - } else { - $compare[$key] = $rootConfigField ?: 'not set'; - } - } - } - - return $compare; - } - - - /** - * override config - info in BE Module - */ - protected function overrideConfig(): array - { - $override = []; - $ts = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); - - foreach ( $this->tcaColumns as $field=>$columns ) { - $filedsArr[$field] = 'get'.GeneralUtility::underscoredToUpperCamelCase($field); - } - - foreach ($filedsArr as $fKey=>$field) { - $fKey = GeneralUtility::underscoredToLowerCamelCase($fKey); - if ( !empty($ts['page.']['10.']['settings.']['config.'][$fKey]) ) { - $tsField = $ts['page.']['10.']['settings.']['config.'][$fKey]; - if ( $tsField != $this->rootConfig->$field() && str_starts_with((string)$tsField, '{$bootstrap.config.') != TRUE ) { - if ( $this->rootConfig->$field() === TRUE ) { - $override[$fKey] = 'enabled'; - } elseif ( $this->rootConfig->$field() === FALSE ) { - $override[$fKey] = 'disabled'; - } elseif ($this->rootConfig->$field() == '') { - $override[$fKey] = 'not set'; - } else { - $override[$fKey] = $tsField; - } - } - } - } - - return $override; - } - - - /** - * Delete files from directory - */ - protected function deleteFilesFromDirectory(string $directory): void - { - if (is_dir($directory)) { - if ($dh = opendir($directory)) { - while (($file = readdir($dh)) !== false) { - if ($file!='.' && $file !='..' && $file[0] != '_') { - unlink(''.$directory.''.$file.''); - } - } - closedir($dh); - } - } - } - - - /** - * Write data from DB to constant file and import in sys_template - */ - protected function writeConstants(): void - { - $this->persistenceManager->persistAll(); - if ( count($this->rootTemplates) ) { - $configRepository = $this->configRepository->findOneByPid($this->rootPageId); - $navbarBreakpoint = $configRepository->getNavbarBreakpoint(); - $breakpointWidth = $navbarBreakpoint == 'no' ? '' : $this->settings['breakpoint'][$navbarBreakpoint]; - $siteroots = []; - $filecontent = ''; - foreach( $this->configRepository->findAll() as $config ) { - $page = GeneralUtility::makeInstance(PageRepository::class)->getPage($config->getPid()); - if ( $page['hidden'] === 0 && $page['deleted'] === 0 ) { - if (!empty($page['is_siteroot'])) { - $siteroots[$config->getUid()] = $page['is_siteroot']; - } - $pages[$config->getPid()] = $page; - $configurations[$config->getPid()] = $config; - } - } - - // outsourced setup - $setup = ''; - $model = GeneralUtility::makeInstance(Config::class); - foreach ( $this->objectToArr($model) as $key=>$value) { - if ( !str_starts_with($key, '_') ) { - $setup .= 'page.10.settings.config.'.$key.' = {$bootstrap.config.'.$key.'}'.PHP_EOL; - } - } - $setup .= 'page.10.settings.config.navbarBreakpointWidth = {$bootstrap.config.navbarBreakpointWidth}'.PHP_EOL; - - // outsourced constants - foreach ( $configurations as $config ) { - if ($config->getPid() == $config->getHomepageUid()) { - // is root page - if ( count($siteroots) === 1 ) { - $filecontent .= self::getConstants($config, TRUE); - $filecontent .= 'bootstrap.config.navbarBreakpointWidth = '.$breakpointWidth.PHP_EOL; - } else { - $filecontent .= '['.$config->getPid().' in tree.rootLineIds]'.PHP_EOL; - $filecontent .= self::getConstants($config, TRUE); - $filecontent .= 'bootstrap.config.navbarBreakpointWidth = '.$breakpointWidth.PHP_EOL; - $filecontent .= '[END]'.PHP_EOL.PHP_EOL; - } - } else { - if ($config->getGeneralRootline()) { - $filecontent .= '['.$config->getPid().' in tree.rootLineIds]'.PHP_EOL; - } else { - $filecontent .= '[traverse(page, "uid") == '.$config->getPid().']'.PHP_EOL; - } - if ($config->getGeneralOverride()) { - $filecontent .= self::getConstants($config, TRUE); - } else { - $filecontent .= self::getConstants($config, FALSE); - } - $filecontent .= '[END]'.PHP_EOL.PHP_EOL; - } - } - $customDir = 'fileadmin/T3SB/Configuration/TypoScript/'; - $customPath = GeneralUtility::getFileAbsFileName($customDir); - $customFileName = 't3sbconstants.typoscript'; - $customFile = $customPath.$customFileName; - - if (file_exists($customFile)) { - unlink($customFile); - } - if (!is_dir($customPath)) { - mkdir($customPath, 0777, true); - } - // constants - GeneralUtility::writeFile($customFile, $filecontent); - - $customFileName = 't3sbsetup.typoscript'; - $customFile = $customPath.$customFileName; - - if (file_exists($customFile)) { - unlink($customFile); - } - if (!is_dir($customPath)) { - mkdir($customPath, 0777, true); - } - // setup - GeneralUtility::writeFile($customFile, $setup); - - } - } - - - private function objectToArr($obj) - { - $result = []; - $cls = new \ReflectionClass($obj); - $props = $cls->getProperties(); - foreach ($props as $key=>$prop) - { - $result[$prop->getName()] = 'get'.ucfirst($prop->getName()); - } - - return $result; - } - - - /** - * Get the data from DB - */ - protected function getConstants(Config $config, bool $isRoot): string - { - $constants = 'bootstrap.config.uid = '.$config->getUid() .PHP_EOL; - - foreach ( $this->tcaColumns as $field=>$columns ) { - $field = GeneralUtility::underscoredToLowerCamelCase($field); - $var = str_replace(' ', '_', $field); - $getField = 'get'.GeneralUtility::underscoredToUpperCamelCase($field); - $value = $config->$getField() == '' ? 0 : $config->$getField(); - if ( $var == 'jumbotronCarouselPause' && $value == 1 ) { - $value = 'hover'; - } elseif ( $var == 'jumbotronCarouselPause' && $value == 0 ) { - $value = ''; - } - if ($isRoot){ - $constants .= 'bootstrap.config.'.$var.' = '.$value .PHP_EOL; - } else { - if ($config->$getField() != $this->rootConfig->$getField()) { - $constants .= 'bootstrap.config.'.$var.' = '.$value .PHP_EOL; - } - } - } - - return $constants; - } - - - /** - * Get the Tca Columns - */ - protected function getTcaColumns(): array - { - foreach ( $this->tcaColumns as $key=>$column ) { - if (!empty($column['accordion_id'])) { - if ( !empty($column['accordion_sub']) ) { - $sub = $column['accordion_sub']; - $tca[$column['accordion_id']][$sub][$key] = $column; - $tca[$column['accordion_id']][$sub][$key]['property'] = GeneralUtility::underscoredToLowerCamelCase($key); - $tca[$column['accordion_id']][$sub][$key]['type'] = ucfirst($column['config']['type']); - $tca[$column['accordion_id']][$sub][$key]['noSub'] = FALSE; - } else { - $tca[$column['accordion_id']][$key] = $column; - $tca[$column['accordion_id']][$key]['property'] = GeneralUtility::underscoredToLowerCamelCase($key); - $tca[$column['accordion_id']][$key]['type'] = ucfirst($column['config']['type']); - $tca[$column['accordion_id']][$key]['noSub'] = TRUE; - } - } - } - - return $tca; - } - - - /** - * Get the Utility Colors - */ - protected function getUtilityColors(): array - { - $defaultUtilColorsList = '$white,$gray-100,$gray-200,$gray-300,$gray-400,$gray-500,$gray-600,$gray-700,$gray-800,$gray-900,$black,$blue,$indigo,$purple,$pink,$red,$orange,$yellow,$green,$teal,$cyan,$primary,$secondary,$success,$info,$warning,$danger,$light,$dark'; - $utilityColors = []; - $colors = []; - $customScssArr = []; - $defaultUtilityColors = []; - $defaultcolors = []; - - $customScss = self::getCustomScss('custom-variables'); - $custom_variables = empty($customScss['custom-variables']) ? '' : preg_replace('/\s+/', ' ', trim($customScss['custom-variables'])); - $default = '// Overrides Bootstrap variables // $enable-shadows: true; // $enable-gradients: true; // $enable-negative-margins: true;'; - - if ( !empty($customScss['custom-variables']) && str_starts_with($custom_variables, $default) == FALSE ) { - foreach( GeneralUtility::trimExplode(';', $customScss['custom-variables']) as $customvariables ) { - $scsscolor = GeneralUtility::trimExplode(':', $customvariables); - if ( str_starts_with((string)$customvariables, '$') && GeneralUtility::inList($defaultUtilColorsList, $scsscolor[0]) ) { - $scsscolor = GeneralUtility::trimExplode(':', $customvariables); - $customScssArr[$scsscolor[0]] = $scsscolor[1]; - } - } - foreach( $customScssArr as $key=>$customvariables ) { - if (str_starts_with((string)$customvariables, '$')) { - if (!empty($customScssArr[$customvariables]) && $customScssArr[$customvariables]) - $utilityColors[$key] = $customScssArr[$customvariables]; - } elseif ( str_starts_with((string)$customvariables, '#') ) { - if ($customvariables) - $utilityColors[$key] = $customvariables; - } - } - } - - $variablesSCSS = 'fileadmin/T3SB/Resources/Public/Contrib/Bootstrap/scss/_variables.scss'; - $variablesSCSS = GeneralUtility::getFileAbsFileName($variablesSCSS); - $variablesSCSS = GeneralUtility::getURL($variablesSCSS); - - if (!empty($variablesSCSS)) { - foreach ( GeneralUtility::trimExplode(';', $variablesSCSS) as $defaultVariables) { - $defaultScssColor = GeneralUtility::trimExplode(':', $defaultVariables); - if ( str_starts_with((string)$defaultVariables, '$') && GeneralUtility::inList($defaultUtilColorsList, $defaultScssColor[0]) - && ( str_starts_with((string)$defaultScssColor[1], '$') || str_starts_with((string)$defaultScssColor[1], '#') ) ) { - $scsscolor = GeneralUtility::trimExplode(':', $defaultVariables); - $defaultUtilColors[$scsscolor[0]] = substr($scsscolor[1], 0, -9); - } - } - foreach( $defaultUtilColors as $key=>$customvariables ) { - if (str_starts_with((string)$customvariables, '$')) { - if ( !empty($customScssArr[$customvariables]) && $customScssArr[$customvariables]) - $defaultUtilityColors[$key] = $customScssArr[$customvariables]; - } elseif ( str_starts_with((string)$customvariables, '#') ) { - if ($customvariables) - $defaultUtilityColors[$key] = $customvariables; - } - } - } - if ( is_array($utilityColors) && is_array($defaultUtilityColors) ) { - - if ( !empty($utilityColors) ) { - $colorArr = array_merge($defaultUtilityColors, $utilityColors); - ksort($colorArr); - return $colorArr; - } else { - ksort($defaultUtilityColors); - return $defaultUtilityColors; - } - } else { - return []; - } - } - - - /** - * Returns some default settings for new root configuration - */ - protected function setDefaults(Config $newConfig): Config - { - $defaultNavbarImagePath = isset($this->settings['defaultNavbarImagePath']) ? $this->settings['defaultNavbarImagePath'] : ''; - $newConfig->setHomepageUid($this->currentUid); - $newConfig->setPageTitle( 'jumbotron' ); - $newConfig->setPageTitlealign( 'center' ); - $newConfig->setNavbarImage($defaultNavbarImagePath); - $newConfig->setNavbarEnable( 'light' ); - $newConfig->setNavbarLevels(4); - $newConfig->setNavbarbrandAlignment( 'left' ); - $newConfig->setNavbarColor( 'warning' ); - $newConfig->setNavbarAlignment( 'left' ); - $newConfig->setNavbarBrand( 'imgText' ); - $newConfig->setNavbarContainer( 'inside' ); - $newConfig->setNavbarClass(''); - $newConfig->setJumbotronEnable(1); - $newConfig->setJumbotronSlide(0); - $newConfig->setJumbotronPosition( 'below' ); - $newConfig->setJumbotronContainer( 'container' ); - $newConfig->setJumbotronContainerposition( 'Inside' ); - $newConfig->setJumbotronCarouselInterval(5000); - $newConfig->setJumbotronCarouselPause(0); - $newConfig->setJumbotronClass( 'p-5 mb-4 bg-light rounded-0' ); - $newConfig->setBreadcrumbEnable(1); - $newConfig->setBreadcrumbCorner(1); - $newConfig->setBreadcrumbPosition( 'belowJum' ); - $newConfig->setBreadcrumbContainer( 'container' ); - $newConfig->setSidebarLevels(4); - $newConfig->setFooterEnable(1); - $newConfig->setFooterSlide(0); - $newConfig->setFooterContainer( 'container' ); - $newConfig->setFooterSticky(1); - $newConfig->setFooterContainerposition( 'inside' ); - $newConfig->setFooterClass( 'bg-dark text-light py-4' ); - $newConfig->setStickyFooterExtraPadding(100); - $newConfig->setCompress(1); - $newConfig->setDisablePrefixComment(1); - $newConfig->setGlobalPaddingTop( 'pt-5' ); - $newConfig->setLoadingSpinnerColor( 'primary' ); - $newConfig->setLightboxSelection(1); - $newConfig->setShrinkingNavPadding( '5' ); - $newConfig->setSidebarMenuPosition( 'above' ); - $newConfig->setLangMenuWithFaIcon(1); - $newConfig->setDateFormat( 'd.m.Y' ); - $newConfig->setSubheaderColor( 'secondary' ); - $newConfig->setFaLinkIcons(1); - $newConfig->setSectionmenuAnchorOffset(29); - $newConfig->setSectionmenuScrollspy(1); - $newConfig->setNavbarLangFlags(1); - $newConfig->setSectionmenuScrollspyThreshold('0.1, 0.5, 1'); - $newConfig->setSectionmenuScrollspyRootMargin('0px 0px -75%'); - - return $newConfig; - } - - - /** - * Returns the currently configured "site" if a site is configured (= resolved) in the current request. - */ - protected function getCurrentSite(): SiteInterface - { - $matcher = GeneralUtility::makeInstance(SiteMatcher::class); - return $matcher->matchByPageId((int) $this->request->getQueryParams()['id']); - } - - - protected function getTreeList($id, $depth, $begin = 0, $permsClause = ''): string - { - $depth = (int)$depth; - $begin = (int)$begin; - $id = (int)$id; - if ($id < 0) { - $id = abs($id); - } - if ($begin == 0) { - $theList = $id; - } else { - $theList = ''; - } - if ($id && $depth > 0) { - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); - $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class)); - $statement = $queryBuilder->select('uid') - ->from('pages') - ->where( - $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)), - $queryBuilder->expr()->eq('sys_language_uid', 0), - QueryHelper::stripLogicalOperatorPrefix($permsClause) - ) - ->executeQuery(); - while ($row = $statement->fetch()) { - if ($begin <= 0) { - $theList .= ',' . $row['uid']; - } - if ($depth > 1) { - $theSubList = self::getTreeList($row['uid'], $depth - 1, $begin - 1, $permsClause); - if (!empty($theList) && !empty($theSubList) && ($theSubList[0] !== ',')) { - $theList .= ','; - } - $theList .= $theSubList; - } - } - } - - return (string)$theList; - } - - -} \ No newline at end of file + protected $configRepository; + protected $isSiteroot; + protected $rootPageId; + protected $currentUid; + protected $tcaColumns; + protected $isAdmin; + protected $rootConfig; + protected $rootTemplates; + protected $persistenceManager; + + + /** + * init all actions + */ + public function initializeAction() + { + $site = $this->request->getAttribute('site'); + $this->rootPageId = $site->getRootPageId(); + $this->currentUid = (int) $this->request->getQueryParams()['id']; + $this->isSiteroot = $this->rootPageId === $this->currentUid ? true : false; + $this->tcaColumns = $GLOBALS['TCA']['tx_t3sbootstrap_domain_model_config']['columns']; + $this->isAdmin = $GLOBALS['BE_USER']->isAdmin(); + $this->configRepository = GeneralUtility::makeInstance(ConfigRepository::class); + $this->rootConfig = $this->configRepository->findOneByPid($this->rootPageId); + $this->persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class); + + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template'); + $this->countRootTemplates = $queryBuilder + ->count('uid') + ->from('sys_template') + ->where( + $queryBuilder->expr()->eq('root', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)) + ) + ->executeQuery()->fetchOne(); + +# $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class); + } + + + /** + * SCSS in the BE + */ + protected function getCustomScss(string $file): array + { + $assignedOptions = []; + + if (!empty($this->settings['sitepackage'])) { + $customScssDir = 'EXT:t3sb_package/T3SB/Resources/Public/SCSS/'; + } else { + $customScssDir = 'fileadmin/T3SB/Resources/Public/SCSS/'; + } + $customScssFilePath = GeneralUtility::getFileAbsFileName($customScssDir); + + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $result = $queryBuilder + ->select('*') + ->from('pages') + ->where( + $queryBuilder->expr()->eq('sys_language_uid', 0), + $queryBuilder->expr()->eq('is_siteroot', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)) + ) + ->executeQuery(); + + $siteroots = $result->fetchAllAssociative(); + $customScssFileName = ''; + + foreach ($siteroots as $key=>$siteroot) { + if ($siteroot['uid'] == $this->currentUid) { + if ($key === 0) { + $customScssFileName = $file.'.scss'; + } else { + $customScssFileName = $file.'-'.$siteroot['uid'].'.scss'; + } + } + } + + $customScssFile = $customScssFilePath.$customScssFileName; + + if (file_exists($customScssFile)) { + if ($file == 'custom') { + $assignedOptions['customScss'] = true; + } + $arguments = $this->request->getArguments(); + if (!empty($arguments['t3sbootstrap'][$file])) { + $scss = $arguments['t3sbootstrap'][$file]; + } else { + $scss = !empty($arguments[$file]) ? $arguments[$file] : ''; + } + if ($scss) { + $assignedOptions[$file] = $scss; + $handle = fopen($customScssFile, 'w') or die('Cannot open file: '.$customScssFile); + fwrite($handle, $scss); + fclose($handle); + if ($file == 'custom') { + // clean typo3temp/assets/t3sbootstrap/css/ + $tempPath = GeneralUtility::getFileAbsFileName('typo3temp/assets/t3sbootstrap/css/'); + self::deleteFilesFromDirectory($tempPath); + } + } else { + $handle = fopen($customScssFile, 'r'); + if (filesize($customScssFile)) { + $assignedOptions[$file] = fread($handle, filesize($customScssFile)); + } else { + $assignedOptions[$file] = '// empty file'; + } + fclose($handle); + } + } + + return (array)$assignedOptions; + } + + + + /** + * prepare options for select fields + */ + protected function getFieldsOptions(): array + { + foreach ($this->tcaColumns as $field=>$columns) { + // is select-field + if ($columns['config']['type'] == 'select' && $columns['config']['renderType'] == 'selectSingle') { + $var = GeneralUtility::underscoredToLowerCamelCase($field).'Options'; + foreach ($columns['config']['items'] as $key=>$entry) { + $option = new \stdClass(); + $option->key = $entry['value']; + $option->value = $entry['label']; + $fieldsOptions[$var][$entry['value']] = $option; + } + } + } + + return $fieldsOptions; + } + + + /** + * take over $rootConfig settings + */ + protected function getNewConfig(Config $rootConfig): Config + { + $newConfig = new Config(); + foreach ($this->tcaColumns as $field=>$columns) { + $var = GeneralUtility::underscoredToUpperCamelCase($field); + $set = 'set'.$var; + $get = 'get'.$var; + $newConfig->$set($rootConfig->$get()); + } + + return $newConfig; + } + + + /** + * compare config with rootconfig + */ + protected function compareConfig(Config $config): array + { + $compare = []; + + foreach ($this->tcaColumns as $field=>$columns) { + $filedsArr[] = 'get'.GeneralUtility::underscoredToUpperCamelCase($field); + } + foreach ($filedsArr as $field) { + if ($config->$field() !== $this->rootConfig->$field()) { + $key = lcfirst(substr($field, 3)); + $rootConfigField = $this->rootConfig->$field(); + if ($rootConfigField === true) { + $compare[$key] = 'enabled'; + } elseif ($rootConfigField === false) { + $compare[$key] = 'disabled'; + } else { + $compare[$key] = $rootConfigField ?: 'not set'; + } + } + } + + return $compare; + } + + + /** + * override config - info in BE Module + */ + protected function overrideConfig(): array + { + $override = []; + $ts = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); + + foreach ($this->tcaColumns as $field=>$columns) { + $filedsArr[$field] = 'get'.GeneralUtility::underscoredToUpperCamelCase($field); + } + + foreach ($filedsArr as $fKey=>$field) { + $fKey = GeneralUtility::underscoredToLowerCamelCase($fKey); + if (!empty($ts['page.']['10.']['settings.']['config.'][$fKey])) { + $tsField = $ts['page.']['10.']['settings.']['config.'][$fKey]; + if ($tsField != $this->rootConfig->$field() && str_starts_with((string)$tsField, '{$bootstrap.config.') != true) { + if ($this->rootConfig->$field() === true) { + $override[$fKey] = 'enabled'; + } elseif ($this->rootConfig->$field() === false) { + $override[$fKey] = 'disabled'; + } elseif ($this->rootConfig->$field() == '') { + $override[$fKey] = 'not set'; + } else { + $override[$fKey] = $tsField; + } + } + } + } + + return $override; + } + + + /** + * Delete files from directory + */ + protected function deleteFilesFromDirectory(string $directory): void + { + if (is_dir($directory)) { + if ($dh = opendir($directory)) { + while (($file = readdir($dh)) !== false) { + if ($file!='.' && $file !='..' && $file[0] != '_') { + unlink(''.$directory.''.$file.''); + } + } + closedir($dh); + } + } + } + + + /** + * Write data from DB to constant file and import in sys_template + */ + protected function writeConstants(): void + { + if (empty($this->settings['sitepackage'])) { + $baseDir = GeneralUtility::getFileAbsFileName('fileadmin/T3SB/'); + } else { + if (ExtensionManagementUtility::isLoaded('t3sb_package')) { + $baseDir = GeneralUtility::getFileAbsFileName("EXT:t3sb_package/T3SB/"); + } else { + throw new \InvalidArgumentException('Your t3sb_package is not loaded!', 1657464787); + } + } + + $this->persistenceManager->persistAll(); + if ($this->countRootTemplates) { + $configRepository = $this->configRepository->findOneByPid($this->rootPageId); + $navbarBreakpoint = $configRepository->getNavbarBreakpoint(); + $breakpointWidth = $navbarBreakpoint == 'no' ? '' : $this->settings['breakpoint'][$navbarBreakpoint]; + $siteroots = []; + $filecontent = ''; + foreach ($this->configRepository->findAll() as $config) { + $page = GeneralUtility::makeInstance(PageRepository::class)->getPage($config->getPid()); + if ($page['hidden'] === 0 && $page['deleted'] === 0) { + if (!empty($page['is_siteroot'])) { + $siteroots[$config->getUid()] = $page['is_siteroot']; + } + $pages[$config->getPid()] = $page; + $configurations[$config->getPid()] = $config; + } + } + + // outsourced setup + $setup = ''; + $model = GeneralUtility::makeInstance(Config::class); + foreach ($this->objectToArr($model) as $key=>$value) { + if (!str_starts_with($key, '_')) { + $setup .= 'page.10.settings.config.'.$key.' = {$bootstrap.config.'.$key.'}'.PHP_EOL; + } + } + $setup .= 'page.10.settings.config.navbarBreakpointWidth = {$bootstrap.config.navbarBreakpointWidth}'.PHP_EOL; + + // outsourced constants + foreach ($configurations as $config) { + if ($config->getPid() == $config->getHomepageUid()) { + // is root page + if (count($siteroots) === 1) { + $filecontent .= self::getConstants($config, true); + $filecontent .= 'bootstrap.config.navbarBreakpointWidth = '.$breakpointWidth.PHP_EOL; + } else { + $filecontent .= '['.$config->getPid().' in tree.rootLineIds]'.PHP_EOL; + $filecontent .= self::getConstants($config, true); + $filecontent .= 'bootstrap.config.navbarBreakpointWidth = '.$breakpointWidth.PHP_EOL; + $filecontent .= '[END]'.PHP_EOL.PHP_EOL; + } + } else { + if ($config->getGeneralRootline()) { + $filecontent .= '['.$config->getPid().' in tree.rootLineIds]'.PHP_EOL; + } else { + $filecontent .= '[traverse(page, "uid") == '.$config->getPid().']'.PHP_EOL; + } + if ($config->getGeneralOverride()) { + $filecontent .= self::getConstants($config, true); + } else { + $filecontent .= self::getConstants($config, false); + } + $filecontent .= '[END]'.PHP_EOL.PHP_EOL; + } + } + $customPath = $baseDir.'Configuration/TypoScript/'; + $customFileName = 't3sbconstants.typoscript'; + $customFile = $customPath.$customFileName; + + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + // constants + GeneralUtility::writeFile($customFile, $filecontent); + + $customFileName = 't3sbsetup.typoscript'; + $customFile = $customPath.$customFileName; + + if (file_exists($customFile)) { + unlink($customFile); + } + if (!is_dir($customPath)) { + mkdir($customPath, 0777, true); + } + // setup + GeneralUtility::writeFile($customFile, $setup); + } + } + + + private function objectToArr($obj) + { + $result = []; + $cls = new \ReflectionClass($obj); + $props = $cls->getProperties(); + foreach ($props as $key=>$prop) { + $result[$prop->getName()] = 'get'.ucfirst($prop->getName()); + } + + return $result; + } + + + /** + * Get the data from DB + */ + protected function getConstants(Config $config, bool $isRoot): string + { + $constants = 'bootstrap.config.uid = '.$config->getUid() .PHP_EOL; + + foreach ($this->tcaColumns as $field=>$columns) { + $field = GeneralUtility::underscoredToLowerCamelCase($field); + $var = str_replace(' ', '_', $field); + $getField = 'get'.GeneralUtility::underscoredToUpperCamelCase($field); + $value = $config->$getField() == '' ? 0 : $config->$getField(); + if ($var == 'jumbotronCarouselPause' && $value == 1) { + $value = 'hover'; + } elseif ($var == 'jumbotronCarouselPause' && $value == 0) { + $value = ''; + } + if ($isRoot) { + $constants .= 'bootstrap.config.'.$var.' = '.$value .PHP_EOL; + } else { + if ($config->$getField() != $this->rootConfig->$getField()) { + $constants .= 'bootstrap.config.'.$var.' = '.$value .PHP_EOL; + } + } + } + + return $constants; + } + + + /** + * Get the Tca Columns + */ + protected function getTcaColumns(): array + { + foreach ($this->tcaColumns as $key=>$column) { + if (!empty($column['accordion_id'])) { + if (!empty($column['accordion_sub'])) { + $sub = $column['accordion_sub']; + $tca[$column['accordion_id']][$sub][$key] = $column; + $tca[$column['accordion_id']][$sub][$key]['property'] = GeneralUtility::underscoredToLowerCamelCase($key); + $tca[$column['accordion_id']][$sub][$key]['type'] = ucfirst($column['config']['type']); + $tca[$column['accordion_id']][$sub][$key]['noSub'] = false; + } else { + $tca[$column['accordion_id']][$key] = $column; + $tca[$column['accordion_id']][$key]['property'] = GeneralUtility::underscoredToLowerCamelCase($key); + $tca[$column['accordion_id']][$key]['type'] = ucfirst($column['config']['type']); + $tca[$column['accordion_id']][$key]['noSub'] = true; + } + } + } + + return $tca; + } + + + /** + * Get the Utility Colors + */ + protected function getUtilityColors(): array + { + $defaultUtilColorsList = '$white,$gray-100,$gray-200,$gray-300,$gray-400,$gray-500,$gray-600,$gray-700,$gray-800,$gray-900,$black,$blue,$indigo,$purple,$pink,$red,$orange,$yellow,$green,$teal,$cyan,$primary,$secondary,$success,$info,$warning,$danger,$light,$dark'; + $utilityColors = []; + $colors = []; + $customScssArr = []; + $defaultUtilityColors = []; + $defaultcolors = []; + + $customScss = self::getCustomScss('custom-variables'); + $custom_variables = empty($customScss['custom-variables']) ? '' : preg_replace('/\s+/', ' ', trim($customScss['custom-variables'])); + $default = '// Overrides Bootstrap variables // $enable-shadows: true; // $enable-gradients: true; // $enable-negative-margins: true;'; + + if (!empty($customScss['custom-variables']) && str_starts_with($custom_variables, $default) == false) { + foreach (GeneralUtility::trimExplode(';', $customScss['custom-variables']) as $customvariables) { + $scsscolor = GeneralUtility::trimExplode(':', $customvariables); + if (str_starts_with((string)$customvariables, '$') && GeneralUtility::inList($defaultUtilColorsList, $scsscolor[0])) { + $scsscolor = GeneralUtility::trimExplode(':', $customvariables); + $customScssArr[$scsscolor[0]] = $scsscolor[1]; + } + } + foreach ($customScssArr as $key=>$customvariables) { + if (str_starts_with((string)$customvariables, '$')) { + if (!empty($customScssArr[$customvariables]) && $customScssArr[$customvariables]) { + $utilityColors[$key] = $customScssArr[$customvariables]; + } + } elseif (str_starts_with((string)$customvariables, '#')) { + if ($customvariables) { + $utilityColors[$key] = $customvariables; + } + } + } + } + + if (empty($this->settings['sitepackage'])) { + $variablesSCSS = 'fileadmin/T3SB/Resources/Public/Contrib/Bootstrap/scss/_variables.scss'; + } else { + $variablesSCSS = 'EXT:t3sb_package/T3SB/Resources/Public/Contrib/Bootstrap/scss/_variables.scss'; + } + + $variablesSCSS = GeneralUtility::getFileAbsFileName($variablesSCSS); + $variablesSCSS = GeneralUtility::getURL($variablesSCSS); + + if (!empty($variablesSCSS)) { + foreach (GeneralUtility::trimExplode(';', $variablesSCSS) as $defaultVariables) { + $defaultScssColor = GeneralUtility::trimExplode(':', $defaultVariables); + if (str_starts_with((string)$defaultVariables, '$') && GeneralUtility::inList($defaultUtilColorsList, $defaultScssColor[0]) + && (str_starts_with((string)$defaultScssColor[1], '$') || str_starts_with((string)$defaultScssColor[1], '#'))) { + $scsscolor = GeneralUtility::trimExplode(':', $defaultVariables); + $defaultUtilColors[$scsscolor[0]] = substr($scsscolor[1], 0, -9); + } + } + foreach ($defaultUtilColors as $key=>$customvariables) { + if (str_starts_with((string)$customvariables, '$')) { + if (!empty($customScssArr[$customvariables]) && $customScssArr[$customvariables]) { + $defaultUtilityColors[$key] = $customScssArr[$customvariables]; + } + } elseif (str_starts_with((string)$customvariables, '#')) { + if ($customvariables) { + $defaultUtilityColors[$key] = $customvariables; + } + } + } + } + if (is_array($utilityColors) && is_array($defaultUtilityColors)) { + if (!empty($utilityColors)) { + $colorArr = array_merge($defaultUtilityColors, $utilityColors); + ksort($colorArr); + return $colorArr; + } else { + ksort($defaultUtilityColors); + return $defaultUtilityColors; + } + } else { + return []; + } + } + + + /** + * Returns some default settings for new root configuration + */ + protected function setDefaults(Config $newConfig): Config + { + $defaultNavbarImagePath = isset($this->settings['defaultNavbarImagePath']) ? $this->settings['defaultNavbarImagePath'] : ''; + $newConfig->setHomepageUid($this->currentUid); + $newConfig->setPageTitle('jumbotron'); + $newConfig->setPageTitlealign('center'); + $newConfig->setNavbarImage($defaultNavbarImagePath); + $newConfig->setNavbarEnable('light'); + $newConfig->setNavbarLevels(4); + $newConfig->setNavbarbrandAlignment('left'); + $newConfig->setNavbarColor('warning'); + $newConfig->setNavbarAlignment('left'); + $newConfig->setNavbarBrand('imgText'); + $newConfig->setNavbarContainer('inside'); + $newConfig->setNavbarClass(''); + $newConfig->setJumbotronEnable(1); + $newConfig->setJumbotronSlide(0); + $newConfig->setJumbotronPosition('below'); + $newConfig->setJumbotronContainer('container'); + $newConfig->setJumbotronContainerposition('Inside'); + $newConfig->setJumbotronCarouselInterval(5000); + $newConfig->setJumbotronCarouselPause(0); + $newConfig->setJumbotronClass('p-5 mb-4 bg-light rounded-0'); + $newConfig->setBreadcrumbEnable(1); + $newConfig->setBreadcrumbCorner(1); + $newConfig->setBreadcrumbPosition('belowJum'); + $newConfig->setBreadcrumbContainer('container'); + $newConfig->setSidebarLevels(4); + $newConfig->setFooterEnable(1); + $newConfig->setFooterSlide(0); + $newConfig->setFooterContainer('container'); + $newConfig->setFooterSticky(1); + $newConfig->setFooterContainerposition('inside'); + $newConfig->setFooterClass('bg-dark text-light py-4'); + $newConfig->setStickyFooterExtraPadding(100); + $newConfig->setCompress(1); + $newConfig->setDisablePrefixComment(1); + $newConfig->setGlobalPaddingTop('pt-5'); + $newConfig->setLoadingSpinnerColor('primary'); + $newConfig->setLightboxSelection(1); + $newConfig->setShrinkingNavPadding('5'); + $newConfig->setSidebarMenuPosition('above'); + $newConfig->setLangMenuWithFaIcon(1); + $newConfig->setDateFormat('d.m.Y'); + $newConfig->setSubheaderColor('secondary'); + $newConfig->setFaLinkIcons(1); + $newConfig->setSectionmenuAnchorOffset(29); + $newConfig->setSectionmenuScrollspy(1); + $newConfig->setNavbarLangFlags(1); + $newConfig->setSectionmenuScrollspyThreshold('0.1, 0.5, 1'); + $newConfig->setSectionmenuScrollspyRootMargin('0px 0px -75%'); + + return $newConfig; + } + + + protected function getTreeList($id, $depth, $begin = 0, $permsClause = ''): string + { + $depth = (int)$depth; + $begin = (int)$begin; + $id = (int)$id; + if ($id < 0) { + $id = abs($id); + } + if ($begin == 0) { + $theList = $id; + } else { + $theList = ''; + } + if ($id && $depth > 0) { + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); + $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class)); + $statement = $queryBuilder->select('uid') + ->from('pages') + ->where( + $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)), + $queryBuilder->expr()->eq('sys_language_uid', 0), + QueryHelper::stripLogicalOperatorPrefix($permsClause) + ) + ->executeQuery(); + while ($row = $statement->fetch()) { + if ($begin <= 0) { + $theList .= ',' . $row['uid']; + } + if ($depth > 1) { + $theSubList = self::getTreeList($row['uid'], $depth - 1, $begin - 1, $permsClause); + if (!empty($theList) && !empty($theSubList) && ($theSubList[0] !== ',')) { + $theList .= ','; + } + $theList .= $theSubList; + } + } + } + + return (string)$theList; + } +} diff --git a/Classes/Controller/ConfigController.php b/Classes/Controller/ConfigController.php index ee649ed6..e39af6ce 100644 --- a/Classes/Controller/ConfigController.php +++ b/Classes/Controller/ConfigController.php @@ -1,4 +1,5 @@ isSiteroot && $this->rootPageId ) { - $pidList = parent::getTreeList($this->rootPageId, 999999, 0, '1'); - $allConfig = []; - foreach ( $this->configRepository->findAll() as $config ) { - if (GeneralUtility::inList($pidList, $config->getPid())) { - $page = BackendUtility::getRecord('pages',$config->getPid(),'uid,title'); - $allConfig[$page['uid']]['confUid'] = $config->getUid(); - $allConfig[$page['uid']]['title'] = $page['title']; - $allConfig[$page['uid']]['uid'] = $page['uid']; - $assignedOptions['compress'] = $config->getCompress(); - } - } - $assignedOptions['isSiteroot'] = TRUE; - $assignedOptions['allConfig'] = $allConfig; - } - - $assignedOptions['rootTemplate'] = TRUE; - if (count($this->rootTemplates) === 0) { - $assignedOptions['rootTemplate'] = FALSE; - } - $assignedOptions['rootConfig'] = $this->rootConfig ? TRUE : FALSE; - $assignedOptions['config'] = $this->configRepository->findOneByPid($this->currentUid); - $assignedOptions['admin'] = $this->isAdmin; - $assignedOptions['customScss'] = FALSE; - $assignedOptions['scss'] = ''; - $assignedOptions['action'] = 'list'; - $assignedOptions['updateScss'] = $updateSss; - $assignedOptions['deleted'] = $deleted; - $assignedOptions['created'] = $created; - - if ( !empty($this->settings['customScss']) && (int)$this->settings['customScss'] === 1 ) { - $customScss = parent::getCustomScss('custom-variables'); - $assignedOptions['custom-variables'] = !empty($customScss['custom-variables']) ? $customScss['custom-variables'] : ''; - $customScss = parent::getCustomScss('custom'); - $assignedOptions['custom'] = !empty($customScss['custom']) ? $customScss['custom'] : ''; - $assignedOptions['customScss'] = !empty($customScss['customScss']) ? $customScss['customScss'] : ''; - if ( !empty($this->settings['enableUtilityColors']) ) { - $assignedOptions['utilColors'] = parent::getUtilityColors(); - } - } - - if ( !empty($this->settings['pages']['override']) ) { - foreach ($this->settings['pages']['override'] as $field=>$override) { - if (!empty($override)) { - $assignedOptions['pagesOverride'][$field] = $override; - } - } - } - - $assignedOptions['webpIsLoaded'] = false; - if ( ExtensionManagementUtility::isLoaded('webp') ) { - $assignedOptions['webpIsLoaded'] = true; - } - - $this->view->assignMultiple($assignedOptions); - $moduleTemplate = $this->moduleTemplateFactory->create($this->request); - $moduleTemplate->setContent($this->view->render()); - return $this->htmlResponse($moduleTemplate->renderContent()); - } - - - /** - * action new - */ - public function newAction(): ResponseInterface - { - $assignedOptions = parent::getFieldsOptions(); - $assignedOptions['pid'] = $this->currentUid; - $assignedOptions['tcaColumns'] = parent::getTcaColumns(); - - if ( $this->rootConfig ) { - // config from rootline - if ( $this->rootConfig->getGeneralRootline() ) { - $rootLineArray = GeneralUtility::makeInstance(RootlineUtility::class, $this->currentUid)->get(); - // unset current page - if (count($rootLineArray) > 1) - unset($rootLineArray[count($rootLineArray)-1]); - foreach ($rootLineArray as $rootline) { - $rootlineConfig = $this->configRepository->findOneByPid((int)$rootline['uid']); - if ( !empty($rootlineConfig) ) break; - } - $assignedOptions['newConfig'] = parent::getNewConfig($rootlineConfig); - // config from rootpage - } else { - $assignedOptions['newConfig'] = parent::getNewConfig($this->rootConfig); - } - - } else { - $newConfig = new Config(); - // some defaults - $newConfig = parent::setDefaults($newConfig); - $assignedOptions['newConfig'] = $newConfig; - } - - $this->view->assignMultiple($assignedOptions); - $moduleTemplate = $this->moduleTemplateFactory->create($this->request); - $moduleTemplate->setContent($this->view->render()); - return $this->htmlResponse($moduleTemplate->renderContent()); - } - - - /** - * action create - */ - public function createAction(Config $newConfig): ResponseInterface - { - $newConfig->setHomepageUid($this->rootPageId); - $newConfig->setPid($this->currentUid); - $this->configRepository->add($newConfig); - parent::writeConstants(); - return $this->redirect('list',NULL,Null,array('created' => TRUE)); - } - - - /** - * action edit - */ - public function editAction(Config $config, bool $updated = FALSE): ResponseInterface - { - $assignedOptions = parent::getFieldsOptions(); - $assignedOptions['config'] = $config; - $assignedOptions['pid'] = $this->currentUid; - $assignedOptions['admin'] = $this->isAdmin; - $assignedOptions['isSiteroot'] = $this->isSiteroot; - $assignedOptions['updated'] = $updated; - $assignedOptions['override'] = parent::overrideConfig(); - $assignedOptions['tcaColumns'] = parent::getTcaColumns(); - $assignedOptions['action'] = 'edit'; - if ( !$this->isSiteroot ) { - $assignedOptions['compare'] = parent::compareConfig($config); - } - - if ($updated) { - $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); - $notificationQueue = $flashMessageService->getMessageQueueByIdentifier(FlashMessageQueue::NOTIFICATION_QUEUE); - $flashMessage = GeneralUtility::makeInstance( - FlashMessage::class, - 'The configuration was successfully updated.', - 'Record saved', - ContextualFeedbackSeverity::OK, - ); - $notificationQueue->enqueue($flashMessage); - } - - $this->view->assignMultiple($assignedOptions); - $moduleTemplate = $this->moduleTemplateFactory->create($this->request); - $moduleTemplate->setContent($this->view->render()); - return $this->htmlResponse($moduleTemplate->renderContent()); - } - - - /** - * action update - */ - public function updateAction(Config $config): ResponseInterface - { - $config->setHomepageUid($this->rootPageId); - $this->configRepository->update($config); - parent::writeConstants(); - return $this->redirect('edit',NULL,Null,array('config' => $config, 'updated' => TRUE)); - } - - - /** - * action delete - */ - public function deleteAction(Config $config): ResponseInterface - { - $this->configRepository->remove($config); - parent::writeConstants(); - return $this->redirect('list',NULL,Null,array('deleted' => TRUE)); - } - - - /** - * action dashboard - */ - public function dashboardAction(): ResponseInterface - { - if ( $this->isSiteroot ) { - $assignedOptions['extconf'] = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); - } - - $assignedOptions['action'] = 'dashboard'; - $assignedOptions['isSiteroot'] = $this->isSiteroot; - $assignedOptions['admin'] = $this->isAdmin; - - $this->view->assignMultiple($assignedOptions); - $moduleTemplate = $this->moduleTemplateFactory->create($this->request); - $moduleTemplate->setContent($this->view->render()); - return $this->htmlResponse($moduleTemplate->renderContent()); - } - - - /** - * action constants - */ - public function constantsAction(): ResponseInterface - { - if ( $this->isSiteroot ) { - $constantPath = GeneralUtility::getFileAbsFileName('fileadmin/T3SB/Configuration/TypoScript/t3sbconstants.typoscript'); - if ( file_exists($constantPath) ) { - $fileGetContents = @file_get_contents($constantPath); - $outsourcedConstantsArr = explode('[END]', trim($fileGetContents)); - $toEnd = count($outsourcedConstantsArr); - $filecontent = ''; - foreach ($outsourcedConstantsArr as $outsourcedConstants) { - if (0 === --$toEnd) { - $filecontent .= trim($outsourcedConstants).PHP_EOL.PHP_EOL; - } else { - $filecontent .= trim($outsourcedConstants).PHP_EOL . '[END]'.PHP_EOL.PHP_EOL; - } - } - $assignedOptions['filecontent'] = $filecontent; - } - } - - $assignedOptions['action'] = 'constants'; - $assignedOptions['isSiteroot'] = $this->isSiteroot; - $assignedOptions['admin'] = $this->isAdmin; - - $this->view->assignMultiple($assignedOptions); - $moduleTemplate = $this->moduleTemplateFactory->create($this->request); - $moduleTemplate->setContent($this->view->render()); - return $this->htmlResponse($moduleTemplate->renderContent()); - } - + public function __construct( + private ModuleTemplateFactory $moduleTemplateFactory + ) { + } + + /** + * Init all actions. + */ + public function initializeAction() + { + parent::initializeAction(); + } + + /** + * action list + */ + public function listAction(bool $deleted = false, bool $created = false, bool $updateSss = false): ResponseInterface + { + if ($this->isSiteroot && $this->rootPageId) { + $pidList = parent::getTreeList($this->rootPageId, 999999, 0, '1'); + $allConfig = []; + foreach ($this->configRepository->findAll() as $config) { + if (GeneralUtility::inList($pidList, $config->getPid())) { + $page = BackendUtility::getRecord('pages', $config->getPid(), 'uid,title'); + $allConfig[$page['uid']]['confUid'] = $config->getUid(); + $allConfig[$page['uid']]['title'] = $page['title']; + $allConfig[$page['uid']]['uid'] = $page['uid']; + $assignedOptions['compress'] = $config->getCompress(); + } + } + $assignedOptions['isSiteroot'] = true; + $assignedOptions['allConfig'] = $allConfig; + } + + $assignedOptions['rootTemplate'] = true; + if ($this->countRootTemplates === 0) { + $assignedOptions['rootTemplate'] = false; + } + $assignedOptions['rootConfig'] = $this->rootConfig ? true : false; + $assignedOptions['config'] = $this->configRepository->findOneByPid($this->currentUid); + $assignedOptions['admin'] = $this->isAdmin; + $assignedOptions['customScss'] = false; + $assignedOptions['scss'] = ''; + $assignedOptions['action'] = 'list'; + $assignedOptions['updateScss'] = $updateSss; + $assignedOptions['deleted'] = $deleted; + $assignedOptions['created'] = $created; + + if (!empty($this->settings['customScss']) && (int)$this->settings['customScss'] === 1) { + $customScss = parent::getCustomScss('custom-variables'); + $assignedOptions['custom-variables'] = !empty($customScss['custom-variables']) ? $customScss['custom-variables'] : ''; + $customScss = parent::getCustomScss('custom'); + $assignedOptions['custom'] = !empty($customScss['custom']) ? $customScss['custom'] : ''; + $assignedOptions['customScss'] = !empty($customScss['customScss']) ? $customScss['customScss'] : ''; + if (!empty($this->settings['enableUtilityColors'])) { + $assignedOptions['utilColors'] = parent::getUtilityColors(); + } + } + + if (!empty($this->settings['pages']['override'])) { + foreach ($this->settings['pages']['override'] as $field=>$override) { + if (!empty($override)) { + $assignedOptions['pagesOverride'][$field] = $override; + } + } + } + + $assignedOptions['webpIsLoaded'] = false; + if (ExtensionManagementUtility::isLoaded('webp')) { + $assignedOptions['webpIsLoaded'] = true; + } + + $this->view->assignMultiple($assignedOptions); + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $moduleTemplate->assignMultiple($assignedOptions); + $moduleTemplate->setContent($this->view->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } + + + /** + * action new + */ + public function newAction(): ResponseInterface + { + $assignedOptions = parent::getFieldsOptions(); + $assignedOptions['pid'] = $this->currentUid; + $assignedOptions['tcaColumns'] = parent::getTcaColumns(); + + if ($this->rootConfig) { + // config from rootline + if ($this->rootConfig->getGeneralRootline()) { + $rootLineArray = GeneralUtility::makeInstance(RootlineUtility::class, $this->currentUid)->get(); + // unset current page + if (count($rootLineArray) > 1) { + unset($rootLineArray[count($rootLineArray)-1]); + } + foreach ($rootLineArray as $rootline) { + $rootlineConfig = $this->configRepository->findOneByPid((int)$rootline['uid']); + if (!empty($rootlineConfig)) { + break; + } + } + $assignedOptions['newConfig'] = parent::getNewConfig($rootlineConfig); + // config from rootpage + } else { + $assignedOptions['newConfig'] = parent::getNewConfig($this->rootConfig); + } + } else { + $newConfig = new Config(); + // some defaults + $newConfig = parent::setDefaults($newConfig); + $assignedOptions['newConfig'] = $newConfig; + } + + $this->view->assignMultiple($assignedOptions); + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $moduleTemplate->setContent($this->view->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } + + + /** + * action create + */ + public function createAction(Config $newConfig): ResponseInterface + { + $newConfig->setHomepageUid($this->rootPageId); + $newConfig->setPid($this->currentUid); + $this->configRepository->add($newConfig); + parent::writeConstants(); + return $this->redirect('list', null, null, array('created' => true)); + } + + + /** + * action edit + */ + public function editAction(Config $config, bool $updated = false): ResponseInterface + { + $assignedOptions = parent::getFieldsOptions(); + $assignedOptions['config'] = $config; + $assignedOptions['pid'] = $this->currentUid; + $assignedOptions['admin'] = $this->isAdmin; + $assignedOptions['isSiteroot'] = $this->isSiteroot; + $assignedOptions['updated'] = $updated; + $assignedOptions['override'] = parent::overrideConfig(); + $assignedOptions['tcaColumns'] = parent::getTcaColumns(); + $assignedOptions['action'] = 'edit'; + if (!$this->isSiteroot) { + $assignedOptions['compare'] = parent::compareConfig($config); + } + + if ($updated) { + $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); + $notificationQueue = $flashMessageService->getMessageQueueByIdentifier(FlashMessageQueue::NOTIFICATION_QUEUE); + $flashMessage = GeneralUtility::makeInstance( + FlashMessage::class, + 'The configuration was successfully updated.', + 'Record saved', + ContextualFeedbackSeverity::OK, + ); + $notificationQueue->enqueue($flashMessage); + } + + $this->view->assignMultiple($assignedOptions); + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $moduleTemplate->setContent($this->view->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } + + + /** + * action update + */ + public function updateAction(Config $config): ResponseInterface + { + $config->setHomepageUid($this->rootPageId); + $this->configRepository->update($config); + parent::writeConstants(); + return $this->redirect('edit', null, null, array('config' => $config, 'updated' => true)); + } + + + /** + * action delete + */ + public function deleteAction(Config $config): ResponseInterface + { + $this->configRepository->remove($config); + parent::writeConstants(); + return $this->redirect('list', null, null, array('deleted' => true)); + } + + + /** + * action dashboard + */ + public function dashboardAction(): ResponseInterface + { + if ($this->isSiteroot) { + $assignedOptions['extconf'] = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); + } + + $assignedOptions['action'] = 'dashboard'; + $assignedOptions['isSiteroot'] = $this->isSiteroot; + $assignedOptions['admin'] = $this->isAdmin; + + $this->view->assignMultiple($assignedOptions); + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $moduleTemplate->setContent($this->view->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } + + + /** + * action constants + */ + public function constantsAction(): ResponseInterface + { + if (empty($this->settings['sitepackage'])) { + $baseDir = GeneralUtility::getFileAbsFileName('fileadmin/T3SB/'); + } else { + if (ExtensionManagementUtility::isLoaded('t3sb_package')) { + $baseDir = GeneralUtility::getFileAbsFileName("EXT:t3sb_package/T3SB/"); + } else { + throw new \InvalidArgumentException('Your t3sb_package is not loaded!', 1657464787); + } + } + + if ($this->isSiteroot) { + $constantPath = $baseDir.'Configuration/TypoScript/t3sbconstants.typoscript'; + if (file_exists($constantPath)) { + $fileGetContents = @file_get_contents($constantPath); + $outsourcedConstantsArr = explode('[END]', trim($fileGetContents)); + $toEnd = count($outsourcedConstantsArr); + $filecontent = ''; + foreach ($outsourcedConstantsArr as $outsourcedConstants) { + if (0 === --$toEnd) { + $filecontent .= trim($outsourcedConstants).PHP_EOL.PHP_EOL; + } else { + $filecontent .= trim($outsourcedConstants).PHP_EOL . '[END]'.PHP_EOL.PHP_EOL; + } + } + $assignedOptions['filecontent'] = $filecontent; + } + } + + $assignedOptions['action'] = 'constants'; + $assignedOptions['isSiteroot'] = $this->isSiteroot; + $assignedOptions['admin'] = $this->isAdmin; + + $this->view->assignMultiple($assignedOptions); + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $moduleTemplate->setContent($this->view->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } } diff --git a/Classes/DataProcessing/BootstrapProcessor.php b/Classes/DataProcessing/BootstrapProcessor.php index fef638a6..dab611da 100644 --- a/Classes/DataProcessing/BootstrapProcessor.php +++ b/Classes/DataProcessing/BootstrapProcessor.php @@ -69,7 +69,6 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu } $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); - $cType = $processedData['data']['CType']; $parentCType = ''; $flexFormService = GeneralUtility::makeInstance(FlexFormService::class); @@ -102,9 +101,9 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu $processedData['dataAnimate'] = ''; $processedData['isAnimateCss'] = false; $processedData['animateCssRepeat'] = false; - $processedData['codesnippet'] = false; $processedData['containsVideo'] = false; $processedData['containerError'] = false; + $processedData['lightBox'] = false; $processedData['data']['configuid'] = (int)$processorConfiguration['configuid']; $processedData['header_fontawesome'] = ''; @@ -271,7 +270,9 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu # # plug-ins # - #if ( $cType == 'list' ) {} + if ($cType == 'news_newsdetail') { + $processedData['lightBox'] = true; + } // media if ($processedData['data']['assets'] || $processedData['data']['image'] || $processedData['data']['media']) { @@ -281,6 +282,7 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu $fileObjects = $fileRepository->findByRelation('tt_content ', 'assets', $processedData['data']['uid']); $fileParts = []; $processedData['addmedia']['ratioClass'] = 'ratio-16x9'; + $processedData['addmedia']['origImageZoom'] = $processedData['data']['tx_t3sbootstrap_zoom_orig']; foreach ($fileObjects as $key=>$fileObject) { if ($fileObject->getType() === 4) { $fileConfig = $fileObject->getStorage()->getConfiguration(); @@ -318,13 +320,6 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu } } - // codesnippet - if (array_key_exists('codesnippet', $extConf) && $extConf['codesnippet'] === '1' && $processedData['data']['bodytext']) { - if (str_contains($processedData['data']['bodytext'], '
')) {
-                $processedData['codesnippet'] = true;
-            }
-        }
-
         // child of autoLayout_row
         if ($parentCType == 'autoLayout_row') {
             $processedData['newLine'] = $flexconf['newLine'] ? true : false;
diff --git a/Classes/DataProcessing/ConfigProcessor.php b/Classes/DataProcessing/ConfigProcessor.php
index 70473973..3dd6a7dc 100644
--- a/Classes/DataProcessing/ConfigProcessor.php
+++ b/Classes/DataProcessing/ConfigProcessor.php
@@ -78,7 +78,7 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu
         $smallColumnsCurrent = (int)$currentPage['tx_t3sbootstrap_smallColumns'];
         $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
         $rootlinePage = $pageRepository->getPage($processedRecordVariables['homepageUid']);
-        $smallColumnsRootline = (int)$rootlinePage['tx_t3sbootstrap_smallColumns'];
+        $smallColumnsRootline = !empty($rootlinePage['tx_t3sbootstrap_smallColumns']) ? (int)$rootlinePage['tx_t3sbootstrap_smallColumns'] : 3;
         $smallColumns = $smallColumnsCurrent ?: $smallColumnsRootline;
 
         // global override page data
@@ -173,14 +173,18 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu
         if ($processedRecordVariables['navbarEnable']) {
             // navbar menu
             $mainMenu = [];
-
             if (!empty($processedData['navbarMenu'])) {
                 foreach ($processedData['navbarMenu'] as $key=>$navbarMenu) {
                     $mainMenu[$key] = $navbarMenu;
                     if (!empty($navbarMenu['data']['tx_t3sbootstrap_fontawesome_icon'])) {
                         $mainMenu[$key]['faIcon'] = ' ';
                     }
+					$mainMenu[$key]['linkTitle'] = $navbarMenu['data']['title'];
+					if (!empty($settings['navbar.']['noLinkTitle'])) {
+						$mainMenu[$key]['linkTitle'] = '';
+					}
                     if ($navbarMenu['data']['tx_t3sbootstrap_icon_only']) {
+                        $mainMenu[$key]['linkTitle'] = $navbarMenu['data']['title'];
                         $mainMenu[$key]['title'] = '';
                     }
                     $mainMenu[$key]['target'] = $navbarMenu['data']['target'] ? $navbarMenu['data']['target'] : '_self';
@@ -685,7 +689,7 @@ protected function getNavigationColor(int $languageUid): string
             )
              ->executeQuery();
 
-        $navbarColors = $result->fetchAll();
+        $navbarColors = $result->fetchAllAssociative();
         $navbarColorCSS = '';
 
         if (is_array($navbarColors)) {
diff --git a/Classes/DataProcessing/GalleryProcessor.php b/Classes/DataProcessing/GalleryProcessor.php
index 3c1e7dba..4bd1e2d6 100644
--- a/Classes/DataProcessing/GalleryProcessor.php
+++ b/Classes/DataProcessing/GalleryProcessor.php
@@ -1,4 +1,5 @@
  24px
-
-	protected $contentObjectRenderer;
-	protected $contentObjectConfiguration;
-	protected $processorConfiguration;
-	protected $numberOfColumns;
-	protected $mediaOrientation;
-	protected $maxGalleryWidth;
-	protected $equalMediaHeight;
-	protected $equalMediaWidth;
-	protected $cropVariant = 'default';
-	protected $fileObjects = [];
-	protected $mediaDimensions = [];
-	protected $beLayout = 'OneCol';
-	protected $colPos;
-	protected $parentgridColPos;
-	protected $minimumWidth;
-	protected $ratioWithHeight;
-	protected $pageContainer;
-	protected $rowWidth;
-	protected $columns;
-	protected $cType;
-	protected $bodytext;
-	protected $maxWidthMediaObject;
-	protected $maxWidthToast;
-	protected $disableAutoRow;
-	protected $parentflexconf;
-	protected $processedData;
-	protected $processedParentData;
-	protected $cardWrapper;
-	protected $availableGalleryPositions = [
-		'horizontal' => [
-			'center' => [0, 8],
-			'right' => [1, 9, 17, 25],
-			'left' => [2, 10, 18, 26]
-		],
-		'vertical' => [
-			'above' => [0, 1, 2],
-			'intext' => [17, 18, 25, 26, 66, 77],
-			'below' => [8, 9, 10]
-		]
-	];
-	protected $galleryData = [
-		'position' => [
-			'horizontal' => '',
-			'vertical' => '',
-			'noWrap' => false
-		],
-		'width' => 0,
-		'count' => [
-			'files' => 0,
-			'columns' => 0,
-			'rows' => 0,
-		],
-		'border' => [
-			'enabled' => false,
-			'width' => 0,
-			'padding' => 0,
-		],
-		'rows' => []
-	];
-
-
-	/**
-	 * Process data for a gallery, for instance the CType "textmedia"
-	 *
-	 * @param ContentObjectRenderer $cObj The content object renderer, which contains data of the content element
-	 * @param array $contentObjectConfiguration The configuration of Content Object
-	 * @param array $processorConfiguration The configuration of this processor
-	 * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
-	 * @return array the processed data as key/value store
-	 * @throws ContentRenderingException
-	 */
-	public function process(
-		ContentObjectRenderer $cObj,
-		array $contentObjectConfiguration,
-		array $processorConfiguration,
-		array $processedData
-	): array
-	{
-		if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
-			return $processedData;
-		}
-
-		$this->contentObjectRenderer = $cObj;
-		$this->processorConfiguration = $processorConfiguration;
-		$this->processedData = $processedData;
-		$this->contentObjectConfiguration = $contentObjectConfiguration;
-
-		if (!empty($this->processedData['data']['tx_container_parent'])) {
-			$this->processedParentData = self::getContentRecord($this->processedData['data']['tx_container_parent']);
-		} else {
-			$this->processedParentData = [];
-		}
-
-		$filesProcessedDataKey = (string)$cObj->stdWrapValue(
-			'filesProcessedDataKey',
-			$processorConfiguration,
-			'files'
-		);
-
-		if (isset($this->processedData[$filesProcessedDataKey]) && is_array($this->processedData[$filesProcessedDataKey])) {
-			$this->fileObjects = $this->processedData[$filesProcessedDataKey];
-
-			if ( !empty($this->fileObjects[0]) ) {
-				$fileObjects = [];
-				// image gallery
-				foreach ( $this->fileObjects as $fileObject ) {
-					$fileObjects[] = $fileObject;
-				}
-				$this->fileObjects = $fileObjects;
-			}
-			$this->galleryData['count']['files'] = count($this->fileObjects);
-		} else {
-			throw new ContentRenderingException('No files found for key ' . $filesProcessedDataKey . ' in $processedData.', 1436809789);
-		}
-
-		if (empty($this->fileObjects)) {
-			return $this->processedData;
-		}
-
-		$this->ratioWithHeight = $this->getConfigurationValue('ratioWithHeight');
-		$this->cropVariant = $this->getConfigurationValue('cropVariant') ?: 'default';
-		$this->equalMediaHeight = (int)$this->getConfigurationValue('equalMediaHeight', 'imageheight');
-		$this->equalMediaWidth = (int)$this->getConfigurationValue('equalMediaWidth', 'imagewidth');
-		$this->numberOfColumns = (int)$this->getConfigurationValue('numberOfColumns', 'imagecols');
-		$this->maxGalleryWidth = (int)$this->getConfigurationValue('maxGalleryWidth') ?: self::maxGalleryWidth;
-		$this->mediaOrientation = (int)$this->getConfigurationValue('mediaOrientation', 'imageorient');
-		$this->beLayout = $this->processedData['be_layout'];
-		$this->colPos = (int)$this->processedData['data']['colPos'];
-		$this->minimumWidth = $this->getConfigurationValue('minimumWidth');
-		$this->bodytext = $this->processedData['data']['bodytext'];
-		$this->cType = $this->processedData['data']['CType'];
-		$this->rowWidth = $this->processedData['data']['tx_t3sbootstrap_inTextImgRowWidth'];
-		$this->maxWidthMediaObject = $this->getConfigurationValue('maxWidthMediaObject');
-		$this->maxWidthToast = $this->getConfigurationValue('maxWidthToast');
-		$this->disableAutoRow = $this->getConfigurationValue('disableAutoRow');
-
-		$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
-		$this->parentflexconf = !empty($this->processedParentData['tx_t3sbootstrap_flexform'])
-		 ? $flexFormService->convertFlexFormContentToArray($this->processedParentData['tx_t3sbootstrap_flexform']) : [];
-
-		$pageContainer = self::getFrontendController()->page['tx_t3sbootstrap_container'];
-		$contentContainer = $this->processedData['data']['tx_t3sbootstrap_container'];
-		if ( $pageContainer ) {
-			$this->pageContainer = $pageContainer;
-		} elseif ( $contentContainer ) {
-			$this->pageContainer = $contentContainer;
-		} else {
-			$this->pageContainer = '';
-		}
-
-		$this->determineGalleryPosition();
-		$this->calculateRowsAndColumns();
-		$this->determineMaximumGalleryWidth();
-		$this->calculateMediaWidthsAndHeights();
-		$this->prepareGalleryData();
-
-		$targetFieldName = (string)$cObj->stdWrapValue(
-			'as',
-			$processorConfiguration,
-			'gallery'
-		);
-
-		$this->processedData[$targetFieldName] = $this->galleryData;
-
-		return $this->processedData;
-	}
-
-	/**
-	 * Get configuration value from processorConfiguration
-	 * with when $dataArrayKey fallback to value from cObj->data array
-	 *
-	 * @param string $key
-	 * @param string|NULL $dataArrayKey
-	 * @return string
-	 */
-	protected function getConfigurationValue(string $key, string|NULL $dataArrayKey = null): string
-	{
-		$defaultValue = '';
-		if ($dataArrayKey && isset($this->contentObjectRenderer->data[$dataArrayKey])) {
-			$defaultValue = $this->contentObjectRenderer->data[$dataArrayKey];
-		}
-		return $this->contentObjectRenderer->stdWrapValue(
-			$key,
-			$this->processorConfiguration,
-			$defaultValue
-		);
-	}
-
-	/**
-	 * Define the gallery position
-	 *
-	 * Gallery has a horizontal and a vertical position towards the text
-	 * and a possible wrapping of the text around the gallery.
-	 */
-	protected function determineGalleryPosition()
-	{
-		foreach ($this->availableGalleryPositions as $positionDirectionKey => $positionDirectionValue) {
-			foreach ($positionDirectionValue as $positionKey => $positionArray) {
-				if (in_array($this->mediaOrientation, $positionArray, true)) {
-					$this->galleryData['position'][$positionDirectionKey] = $positionKey;
-				}
-			}
-		}
-
-		if ($this->mediaOrientation === 25 || $this->mediaOrientation === 26) {
-			$this->galleryData['position']['noWrap'] = true;
-		}
-		$this->galleryData['position']['alignCenter'] = false;
-		if ($this->mediaOrientation === 66 || $this->mediaOrientation === 77) {
-			$this->galleryData['position']['alignCenter'] = true;
-		}
-	}
-
-
-	/**
-	 * Get the gallery width if 'tx_t3sbootstrap_inTextImgRowWidth' is set to 'auto'
-	 */
-	protected function determineMaximumGalleryWidth(): void
-	{
-		if ( $this->rowWidth == 'auto' && $this->disableAutoRow ) {
-			$this->rowWidth = 'none';
-		}
-
-		if ( $this->rowWidth == 'auto' ) {
-			if ( $this->cType == 'textmedia' || $this->cType == 'textpic' || $this->cType == 'image' ) {
-				if ( $this->bodytext ) {
-					if ( $this->galleryData['position']['vertical'] === 'intext' ) {
-						if ( $this->galleryData['count']['columns'] === 1 ) {
-							$this->rowWidth = 33;
-						} else {
-							$this->rowWidth = 50;
-						}
-					} else {
-						// above or below
-						$this->rowWidth = 66;
-					}
-					if ( $this->galleryData['position']['vertical'] == 'above' || $this->galleryData['position']['vertical'] == 'below' ) {
-						$this->rowWidth = 100;
-					}
-				} else {
-					$this->rowWidth = 100;
-				}
-
-			// Cards inside a card-wrapper
-			} elseif ( $this->cType == 't3sbs_card' && $this->processedData['data']['tx_container_parent']
-			 && $this->processedParentData['CType'] == 'card_wrapper') {
-				$this->rowWidth = 100;
-			} else {
-				$this->rowWidth = 100;
-			}
-		}
-	}
-
-
-	/**
-	 * Calculate the amount of rows and columns
-	 */
-	protected function calculateRowsAndColumns(): void
-	{
-		// If no columns defined, set it to 1
-		$columns = max((int)$this->numberOfColumns, 1);
-
-		if ($columns === 88) {
-			$columns = 1;
-		} else {
-			// When more columns than media elements, set the columns to the amount of media elements
-			if ($columns > $this->galleryData['count']['files']) {
-				if ( $this->processedData['data']['CType'] !== 't3sbs_gallery' ) {
-					$columns = $this->galleryData['count']['files'];
-				}
-			}
-		}
-
-		if ($columns === 0) {
-			$columns = 1;
-		}
-
-		// Calculate the rows from the amount of files and the columns
-		$rows = ceil($this->galleryData['count']['files'] / $columns);
-		$this->galleryData['count']['columns'] = $columns;
-		$this->galleryData['count']['rows'] = (int)$rows;
-	}
-
-
-	/**
-	 * Calculate the width/height of the media elements
-	 *
-	 * Based on the width of the gallery, defined equal width or height by a user, the spacing between columns and
-	 * the use of a border, defined by user, where the border width and padding are taken into account
-	 *
-	 * File objects MUST already be filtered. They need a height and width to be shown in the gallery
-	 */
-	protected function calculateMediaWidthsAndHeights()
-	{
-
-		if ( $this->equalMediaWidth == 0 && $this->equalMediaHeight == 0 ) {
-
-			// container
-			$pageContainer = self::getPageContainer($this->pageContainer);
-			if ( str_contains($pageContainer, 'container-fluid') ) {
-				$bsMaxGridWidth = !empty($_COOKIE['viewportWidth']) ? (int)$_COOKIE['viewportWidth'] : 1920;
-				$bsMaxGridWidth = $bsMaxGridWidth - self::gridGutterWidth;
-			} else {
-				$bsMaxGridWidth = self::maxGalleryWidth;
-			}
-
-			// row width
-			if ( is_int($this->rowWidth) ) {
-				$rowWidth = $this->rowWidth;
-			} elseif ( $this->rowWidth != 'none' && is_string($this->rowWidth) ) {
-				$rowWidth = (int) end(explode('-', $this->rowWidth));
-			} else {
-				$rowWidth = 100;
-			}
-			if ( $this->cType == 't3sbs_gallery' ) {
-				$rowWidth = 100;
-			}
-
-			if ( $this->colPos == 0
-				|| $this->colPos == 1
-				|| $this->colPos == 2
-				|| ($this->colPos > 199 && $this->processedParentData['colPos'] < 3)
-			)
-			{
-				if ( $this->processorConfiguration['overrideSmallColumns'] ) {
-					$defaultSmallColumns = $this->processorConfiguration['overrideSmallColumns'];
-				} else {
-					$defaultSmallColumns = 0;
-				}
-				$smallColumns = $defaultSmallColumns ?: self::getFrontendController()->page['tx_t3sbootstrap_smallColumns'];
-
-				if ($this->beLayout == 'OneCol') {
-
-					$bsGridWidth = $bsMaxGridWidth;
-
-				} elseif ($this->beLayout == 'ThreeCol') {
-
-					// Three columns
-					$bsMaxGridWidth = $bsMaxGridWidth + self::gridGutterWidth;
-					$bsAsideGridWidth = $bsMaxGridWidth / self::gridColumns * (int) $smallColumns;
-					$bsMainGridWidth = $bsMaxGridWidth - $bsAsideGridWidth * 2;
-
-					// Main
-					if ( $this->colPos === 0 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 0) ) {
-						$bsGridWidth = $bsMainGridWidth;
-					// Aside
-					} elseif ( $this->colPos === 1 || $this->colPos === 2
-					 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 1)
-					 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 2 ) ) {
-						$bsGridWidth = $bsAsideGridWidth;
-					}
-
-				} else {
-
-					// Two columns
-					$bsMaxGridWidth = $bsMaxGridWidth + self::gridGutterWidth;
-					$bsAsideGridWidth = $bsMaxGridWidth / self::gridColumns * (int) $smallColumns;
-					$bsMainGridWidth = $bsMaxGridWidth - $bsAsideGridWidth;
-
-					// Main
-					if ( $this->colPos === 0 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 0) ) {
-						$bsGridWidth = $bsMainGridWidth;
-					// Aside
-					} elseif ( $this->colPos === 1 || $this->colPos === 2
-					 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 1)
-					 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 2) ) {
-						$bsGridWidth = $bsAsideGridWidth;
-					}
-				}
-			}
-
-			// Jumbotron, footer && expanded content
-			if ( $this->colPos == 3
-				|| $this->colPos == 4
-				|| $this->colPos == 20
-				|| $this->colPos == 21
-				|| (($this->colPos > 199) && ($this->processedParentData['colPos'] > 2))
-			)
-			{
-				$bsGridWidth = $bsMaxGridWidth;
-			}
-
-			// Modal - INFO: https://getbootstrap.com/docs/5.3/components/modal/#optional-sizes
-			if ( isset($this->processedParentData['CType']) && $this->processedParentData['CType'] == 'modal' ) {
-				$size = $this->parentflexconf['size'];
-
-				if ( $size == 'modal-fullscreen' ) {
-					$bsGridWidth = $bsMaxGridWidth;
-				} elseif ( $size == 'modal-xl' ) {
-					$bsGridWidth = 1140;
-				} elseif ($size == 'modal-lg') {
-					$bsGridWidth = 800;
-				} elseif ($size == 'modal-sm') {
-					$bsGridWidth = 300;
-				} else {
-					$bsGridWidth = 500;
-				}
-
-			}
-
-			if ( isset($this->processedParentData['CType']) && $this->processedParentData['CType'] == 'collapsible_accordion' ) {
-				$bsGridWidth = $bsGridWidth - self::gridGutterWidth - 17;
-			}
-
-			// Child of grid container
-			if ( !empty($this->processedParentData['CType']) && ($this->processedParentData['CType'] == 'two_columns'
-			 || $this->processedParentData['CType'] == 'three_columns'
-			 || $this->processedParentData['CType'] == 'four_columns'
-			 || $this->processedParentData['CType'] == 'six_columns') ) {
-			 	$bsGridWidth = $bsGridWidth + self::gridGutterWidth;
-				$bsGridWidth = self::getCalculatedGridWidth($bsGridWidth);
-			} else {
-				if ($this->beLayout == 'OneCol') {
-					$bsGridWidth = $bsGridWidth + self::gridGutterWidth;
-				}
-			}
-
-			$rowWidth = $rowWidth ? $rowWidth : 100;
-
-			$galleryWidth = $bsGridWidth / 100 * $rowWidth;
-
-			// Card Wrapper
-			if ( $this->cType == 't3sbs_card' && $this->processedData['data']['tx_container_parent']
-						 && $this->processedParentData['CType'] == 'card_wrapper') {
-				$galleryWidth = $galleryWidth - self::gridGutterWidth;
-				if ($this->parentflexconf['card_wrapper'] === 'group' || $this->parentflexconf['card_wrapper'] === 'columns') {
-					$this->processedData['data']['tx_t3sbootstrap_gutters'] = '';
-					$this->galleryData['count']['columns'] = -1;
-					// Masonry (columns)
-					if ($this->parentflexconf['card_wrapper'] === 'columns' && str_contains($this->parentflexconf['colclass'], 'col-lg-')) {
-						foreach ( explode(' ', $this->parentflexconf['colclass']) as $class) {
-							if (str_contains($class, 'col-lg-')) {
-								$countChildren = 12 / (int)end(explode('-', $class));
-							}
-						}
-						$galleryWidth = $galleryWidth + self::gridGutterWidth - self::gridGutterWidth * $countChildren;
-					} else {
-						// Group
-						$countChildren = self::countContentRecord($this->processedData['data']['tx_container_parent'], 'tt_content', 'tx_container_parent');
-					}
-					$galleryWidth = $galleryWidth / $countChildren;
-				} elseif ($this->parentflexconf['card_wrapper'] === 'slider') {
-					// Slider
-					$this->galleryData['count']['columns'] = -1;
-					$this->processedData['data']['tx_t3sbootstrap_gutters'] = '';
-				} elseif ($this->parentflexconf['card_wrapper'] === 'flipper') {
-					// Flipper
-					$this->galleryData['count']['columns'] = -1;
-					$this->processedData['data']['tx_t3sbootstrap_gutters'] = '';
-				} else {
-					$this->processedData['data']['tx_t3sbootstrap_gutters'] = 'gx-'.$this->parentflexconf['gutter'];
-					$this->galleryData['count']['columns'] = $this->parentflexconf['visibleCards'];
-				}
-			}
-		}
-
-
-
-		// User entered a predefined width
-		if ( $this->equalMediaWidth ) {
-
-			$mediaWidth = self::checkMediaWidth($this->equalMediaWidth);
-
-			// User entered a predefined width & height
-			if ( $this->equalMediaHeight ) {
-				// Set the corrected dimensions for each media element
-				foreach ($this->fileObjects as $key => $fileObject) {
-
-					if ( $this->ratioWithHeight ) {
-						$ratio = $this->equalMediaWidth .':'. $this->equalMediaHeight;
-						$mediaHeight = '';
-					} else {
-						$ratio = '';
-						if ($fileObject instanceof \TYPO3\CMS\Core\Resource\FileReference) {
-							$mediaHeight = $this->getCroppedDimensionalProperty($fileObject, 'height')
-							 * ($mediaWidth / max($this->getCroppedDimensionalProperty($fileObject, 'width'), 1));
-						}
-					}
-
-					$mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
-					$this->mediaDimensions[$key] = [
-						'width' => floor($mediaWidth),
-						'height' => $mediaHeight,
-						'ratio' => $ratio
-					];
-				}
-
-			} else {
-				// Set the corrected dimensions for each media element
-				foreach ($this->fileObjects as $key => $fileObject) {
-					if ( is_array($fileObject)){
-						foreach($fileObject as $fO) {
-							$fileObject = $fO;
-						}
-					}
-					$mediaHeight = $this->getCroppedDimensionalProperty($fileObject, 'height')
-					 * ($mediaWidth / max($this->getCroppedDimensionalProperty($fileObject, 'width'), 1));
-
-					$mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
-					$this->mediaDimensions[$key] = [
-						'width' => floor($mediaWidth),
-						'height' => $mediaHeight,
-						'ratio' => ''
-					];
-				}
-			}
-
-		// User entered a predefined height only
-		} elseif ($this->equalMediaHeight) {
-
-			// Set the corrected dimensions for each media element
-			foreach ($this->fileObjects as $key => $fileObject) {
-				$mediaHeight = $this->equalMediaHeight;
-				if (is_array($fileObject)) {
-					$fileObject = $fileObject[0];
-				}
-				if ($fileObject instanceof \TYPO3\CMS\Core\Resource\FileReference) {
-					$mediaWidth = $this->getCroppedDimensionalProperty($fileObject, 'width')
-					 * ($mediaHeight / max($this->getCroppedDimensionalProperty($fileObject, 'height'), 1));
-				}
-				$mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
-				$this->mediaDimensions[$key] = [
-					'width' => floor($mediaWidth),
-					'height' => $mediaHeight,
-					'ratio' => ''
-				];
-			}
-
-		// Automatic setting of width and height
-		} else {
-
-			$gutterWidth = 0;
-			$ratio = 0;
-
-			if (!empty($this->processedData['data']['tx_t3sbootstrap_gutters'])) {
-				// margin rem in px (base 16px)
-				$gx = [ 'gx-0' => 0, 'gx-1' => 4, 'gx-2' => 8, 'gx-3' => 16, 'gx-4' => 24, 'gx-5' => 48 ];
-				$gutterWidth = $gx[$this->processedData['data']['tx_t3sbootstrap_gutters']];
-				if ( !empty($this->parentflexconf['noGutters']) ) {
-					$gutterWidth = 0;
-				}
-			}
-
-
-			if ( $this->processedData['data']['CType'] === 't3sbs_gallery' ) {
-
-				$galleryWidth = $galleryWidth - self::gridGutterWidth + $gutterWidth;
-				$gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
-				$mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
-
-			} else {
-
-				if ( $this->galleryData['count']['columns'] > 1 ) {
-
-					if ($this->galleryData['position']['noWrap']) {
-						# imageorient 25 & 26
-						if ( $this->processedData['data']['tx_t3sbootstrap_gutters'] ==  'gx-0') {
-							$galleryWidth = $galleryWidth - self::gridGutterWidth;
-						} else {
-							$galleryWidth = $galleryWidth - $gutterWidth * $this->galleryData['count']['columns'];
-						}
-						$mediaWidth = ceil($galleryWidth / $this->galleryData['count']['columns']);
-					} else {
-						if ( $this->galleryData['position']['alignCenter'] ) {
-							# imageorient 66 & 77
-							if ( $this->processedData['data']['tx_t3sbootstrap_gutters'] ==	'gx-0') {
-								$galleryWidth = $galleryWidth - self::gridGutterWidth;
-							} else {
-								$galleryWidth = $galleryWidth + self::gridGutterWidth;
-							}
-							$gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
-							$mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
-						} else {
-							if ( $this->galleryData['position']['vertical'] === 'above' || $this->galleryData['position']['vertical'] === 'below' ) {
-								# imageorient 0 - 10
-								$galleryWidth = $galleryWidth - self::gridGutterWidth + $gutterWidth;
-								$gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
-								$mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
-							} else {
-								# imageorient 17 & 18
-								if ( $this->processedData['data']['tx_t3sbootstrap_gutters'] ==	 'gx-0') {
-									$galleryWidth = $galleryWidth - self::gridGutterWidth / 2;
-									$mediaWidth = ceil($galleryWidth / $this->galleryData['count']['columns']);
-								} else {
-									$galleryWidth = $galleryWidth - self::gridGutterWidth / 2 + $gutterWidth;
-									$gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
-									$mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
-								}
-							}
-						}
-					}
-				} else {
-					if ($this->galleryData['count']['columns'] === -1 && $this->parentflexconf['card_wrapper'] !== 'slider') {
-						$mediaWidth = $galleryWidth;
-					} elseif ($this->mediaOrientation === 17 || $this->mediaOrientation === 18) {
-						// workaround
-						$mediaWidth = $galleryWidth - 7;
-					} elseif (!empty($this->parentflexconf) && isset($this->parentflexconf['card_wrapper']) && $this->parentflexconf['card_wrapper'] === 'slider') {
-						$mediaWidth = ($galleryWidth - (int)$this->parentflexconf['spaceBetween']) / (int)$this->parentflexconf['breakpoints992'];
-						$ratio = $this->parentflexconf['ratio'];
-					} else {
-						$mediaWidth = $galleryWidth - self::gridGutterWidth;
-					}
-				}
-			}
-
-			$mediaWidth = self::checkMediaWidth($mediaWidth);
-
-			// Set the corrected dimensions for each media element
-			foreach ($this->fileObjects as $key => $fileObject) {
-				if (is_array($fileObject)) {
-					$fileObject = $fileObject[0];
-				}
-				if ($fileObject instanceof \TYPO3\CMS\Core\Resource\FileReference) {
-					$mediaHeight = $this->getCroppedDimensionalProperty($fileObject, 'height')
-					 * ($mediaWidth / max($this->getCroppedDimensionalProperty($fileObject, 'width'), 1));
-				}
-				$mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
-				$this->mediaDimensions[$key] = [
-					'width' => floor($mediaWidth),
-					'height' => $mediaHeight,
-					'ratio' => $ratio
-				];
-			}
-		}
-
-		$this->galleryData['width'] = (int) ceil($mediaWidth);
-	}
-
-
-	/**
-	 * When retrieving the height or width for a media file
-	 * a possible cropping needs to be taken into account.
-	 */
-	protected function getCroppedDimensionalProperty(FileInterface $fileObject, string $dimensionalProperty): int|array
-	{
-		if (!$fileObject->hasProperty('crop') || empty($fileObject->getProperty('crop'))) {
-			return $fileObject->getProperty($dimensionalProperty);
-		}
-
-		$croppingConfiguration = $fileObject->getProperty('crop');
-		$cropVariantCollection = CropVariantCollection::create((string)$croppingConfiguration);
-		return (int) $cropVariantCollection->getCropArea($this->cropVariant)->makeAbsoluteBasedOnFile($fileObject)->asArray()[$dimensionalProperty];
-	}
-
-
-	/**
-	 * Prepare the gallery data
-	 *
-	 * Make an array for rows, columns and configuration
-	 */
-	protected function prepareGalleryData(): void
-	{
-		for ($row = 1; $row <= $this->galleryData['count']['rows']; $row++) {
-			$this->galleryData['count']['columns'] = $this->galleryData['count']['columns'] === -1 ? 3 : $this->galleryData['count']['columns'];
-			for ($column = 1; $column <= $this->galleryData['count']['columns']; $column++) {
-				$fileKey = (($row - 1) * $this->galleryData['count']['columns']) + $column - 1;
-				$this->galleryData['rows'][$row]['columns'][$column] = [
-					'media' => $this->fileObjects[$fileKey] ?? null,
-					'dimensions' => [
-						'width' => $this->mediaDimensions[$fileKey]['width'] ?? null,
-						'height' => $this->mediaDimensions[$fileKey]['height'] ?? null,
-						'ratio' => $this->mediaDimensions[$fileKey]['ratio'] ?? null
-					]
-				];
-			}
-		}
-	}
-
-
-	/**
-	 * Returns the page container
-	 *
-	 * @param string $pageContainer
-	 * @return string
-	 */
-	protected function getPageContainer($pageContainer): string
-	{
-		if ( $this->processedData['data']['tx_container_parent'] && !$pageContainer ) {
-			if ( $this->processedParentData['tx_t3sbootstrap_container'] ) {
-				$pageContainer = $this->processedParentData['tx_t3sbootstrap_container'];
-			} else {
-				if ( $this->processedParentData['tx_container_parent'] ) {
-					$grandParent = self::getContentRecord($this->processedParentData['tx_container_parent']);
-					if ( $grandParent['tx_t3sbootstrap_container'] ) {
-						$pageContainer = $grandParent['tx_t3sbootstrap_container'];
-					}
-				}
-			}
-		}
-
-		// Container if Jumbotron, footer OR expanded content
-		if ( $this->colPos == 3
-			|| $this->colPos == 4
-			|| $this->colPos == 20
-			|| $this->colPos == 21
-			|| ($this->colPos > 199 && $this->processedParentData['colPos'] > 2)
-			|| ($this->colPos > 199 && $this->processedData['data']['CType'] == 'background_wrapper')
-		)
-		{
-			$t3sbconfig = self::getContentRecord((int)$this->getConfigurationValue('configuid'), 'tx_t3sbootstrap_domain_model_config');
-
-			$jumbotronContainer = $t3sbconfig['jumbotron_container'];
-			$footerContainer = $t3sbconfig['footer_container'];
-			$expandedcontentTopContainer = $t3sbconfig['expandedcontent_containertop'];
-			$expandedcontentBottomContainer = $t3sbconfig['expandedcontent_containerbottom'];
-
-			switch ($this->colPos) {
-				case 3: // jumbotron
-					$pageContainer = $jumbotronContainer;
-					break;
-				case 4: // Footer
-					$pageContainer = $footerContainer;
-					break;
-				case 20: // Expanded content Top Container
-					$pageContainer = $expandedcontentTopContainer;
-					break;
-				case 21: // Expanded content Bottom Container
-					$pageContainer = $expandedcontentBottomContainer;
-					break;
-				default:
-					if ($this->colPos > 199) {
-						if ( $this->processedParentData['colPos'] == 3 ) {
-							$pageContainer = $jumbotronContainer;
-						} elseif ( $this->processedParentData['colPos'] == 4 ) {
-							$pageContainer = $footerContainer;
-						} elseif ( $this->processedParentData['colPos'] == 20 ) {
-							$pageContainer = $expandedcontentTopContainer;
-						} elseif ( $this->processedParentData['colPos'] == 21 ) {
-							$pageContainer = $expandedcontentBottomContainer;
-						}
-					}
-					break;
-			}
-
-			if (!$footerContainer && $t3sbconfig['footer_pid'] && $this->colPos > 199 && $this->processedParentData['colPos'] == 0
-			 && $this->processedData['data']['CType'] == 'background_wrapper') {
-
-				$pageContainer = $this->processedParentData['data']['tx_t3sbootstrap_container'];
-			}
-		}
-
-		return !empty($this->processorConfiguration['overrideContainer']) ? $this->processorConfiguration['overrideContainer'] : $pageContainer;
-	}
-
-
-	/**
-	 * Returns content record
-	 *
-	 * @param int $uid
-	 * @param string $table
-	 * @param string $equal
-	 *
-	 * @return array $result
-	 */
-	protected function getContentRecord($uid, $table='tt_content', $equal='uid'): array
-	{
-		return BackendUtility::getRecord($table, $uid, '*');
-	}
-
-
-	/**
-	 * Returns content record
-	 *
-	 * @param int $uid
-	 * @param string $table
-	 * @param string $equal
-	 *
-	 * @return int $result
-	 */
-	protected function countContentRecord($uid, $table='tt_content', $equal='uid'): int
-	{
-		$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
-		$result = $queryBuilder
-			 ->count('uid')
-			 ->from($table)
-			 ->where(
-			 $queryBuilder->expr()->eq($equal, $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
-			 )
-			 ->executeQuery()->fetchOne();
-
-		return $result;
-	}
-
-
-	/**
-	 * Returns calculated grid width
-	 *
-	 * @param int $bsGridWidth
-	 *
-	 * @return int $gridWidth
-	 */
-	protected function getCalculatedGridWidth($bsGridWidth): int
-	{
-		switch ($this->processedParentData['CType']) {
-			case 'two_columns':
-				if ( $this->processedData['data']['colPos'] === 221 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'one');
-				} else {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'two');
-				}
-				break;
-			case 'three_columns':
-				if ( $this->processedData['data']['colPos'] === 231 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'one');
-				} elseif ( $this->processedData['data']['colPos'] === 232 ) {
-
-					$gridWidth = self::getGridWidth($bsGridWidth, 'two');
-				} else {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'three');
-				}
-				break;
-			case 'four_columns':
-				if ( $this->processedData['data']['colPos'] === 241 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'one');
-				} elseif ( $this->processedData['data']['colPos'] === 242 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'two');
-				} elseif ( $this->processedData['data']['colPos'] === 243 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'three');
-				} else {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'four');
-				}
-				break;
-			case 'six_columns':
-				if ( $this->processedData['data']['colPos'] === 261 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'one');
-				} elseif ( $this->processedData['data']['colPos'] === 262 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'two');
-				} elseif ( $this->processedData['data']['colPos'] === 263 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'three');
-				} elseif ( $this->processedData['data']['colPos'] === 264 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'four');
-				} elseif ( $this->processedData['data']['colPos'] === 265 ) {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'five');
-				} else {
-					$gridWidth = self::getGridWidth($bsGridWidth, 'six');
-				}
-				break;
-		}
-
-		return $gridWidth;
-	}
-
-
-	/**
-	 * Returns $ mediaWidth if there is a parent grid element
-	 *
-	 * @param int $bsGridWidth
-	 * @param string $suffix
-	 *
-	 * @return int $gridWidth
-	 */
-	protected function getGridWidth($bsGridWidth, $suffix): int
-	{
-		if (!empty($this->parentflexconf['sm_'.$suffix])) {
-			$gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['sm_'.$suffix];
-		} elseif (!empty($this->parentflexconf['md_'.$suffix])) {
-			$gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['md_'.$suffix];
-		} elseif (!empty($this->parentflexconf['lg_'.$suffix])) {
-			$gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['lg_'.$suffix];
-		} elseif (!empty($this->parentflexconf['xl_'.$suffix])) {
-			$gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['xl_'.$suffix];
-		} elseif (!empty($this->parentflexconf['xxl_'.$suffix])) {
-			$gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['xxl_'.$suffix];
-		} else {
-			$gridWidth = $bsGridWidth / self::gridColumns * ($columns-1);
-		}
-
-		return $gridWidth;
-	}
-
-
-	/**
-	 * Returns $mediaWidth and check some conditions
-	 *
-	 * @param int $mediaWidth
-	 *
-	 * @return int $mediaWidth
-	 */
-	protected function checkMediaWidth($mediaWidth): int
-	{
-		if ( $this->minimumWidth && $mediaWidth < self::minimumWidth ) {
-			// set to 575px and therefore 100% wide on mobile (constant: minimumWidth=1)
-			$mediaWidth = self::minimumWidth;
-		}
-		// t3sbs_mediaobject
-		if ( $this->cType == 't3sbs_mediaobject' && $this->maxWidthMediaObject < $mediaWidth ) {
-			$mediaWidth = $this->maxWidthMediaObject;
-		}
-		// t3sbs_toast
-		if ( $this->cType == 't3sbs_toast' && $this->maxWidthToast < $mediaWidth ) {
-			$mediaWidth = $this->maxWidthToast;
-		}
-		// card slider
-		if ( !empty($this->parentflexconf['width']) && !empty($this->parentflexconf['card_wrapper']) && $this->parentflexconf['card_wrapper'] === 'slider') {
-			$mediaWidth = (int)$this->parentflexconf['width'];
-		}
-		// masonry_wrapper
-		if ( !empty($this->processedParentData['CType']) && $this->processedParentData['CType'] == 'masonry_wrapper' ) {
-			$classPrefix = 'col-lg-';
-			$mediaWidth = $this->getMansoryColumns($classPrefix);
-			if (!$mediaWidth) {
-				$classPrefix = 'col-xl-';
-				$mediaWidth = $this->getMansoryColumns($classPrefix);
-			}
-			if (!$mediaWidth) {
-				$classPrefix = 'col-xxl-';
-				$mediaWidth = $this->getMansoryColumns($classPrefix);
-			}
-			if (!$mediaWidth) {
-				$classPrefix = 'col-sm-';
-				$mediaWidth = $this->getMansoryColumns($classPrefix);
-			}
-			if (!$mediaWidth) {
-				$mediaWidth = self::bsMaxGridWidth / 2;
-			}
-		}
-
-		return (int) $mediaWidth;
-	}
-
-
-	/**
-	 * Returns mansory columns
-	 *
-	 * @param string $classPrefix
-	 *
-	 * @return int $mediaWidth
-	 */
-	protected function getMansoryColumns($classPrefix): int
-	{
-		# 2 columns
-		$pos = strpos($this->parentflexconf['colclass'], $classPrefix.'6');
-		if ($pos !== false) {
-			$mediaWidth = self::bsMaxGridWidth / 2 - self::gridGutterWidth;
-		}
-		# 3 columns
-		$pos = strpos($this->parentflexconf['colclass'], $classPrefix.'4');
-		if ($pos !== false) {
-			$mediaWidth = self::bsMaxGridWidth / 3 - self::gridGutterWidth;
-		}
-		# 4 columns
-		$pos = strpos($this->parentflexconf['colclass'], $classPrefix.'3');
-		if ($pos !== false) {
-			$mediaWidth = self::bsMaxGridWidth / 4 - self::gridGutterWidth;
-		}
-		# 6 columns
-		$pos = strpos($this->parentflexconf['colclass'], $classPrefix.'2');
-		if ($pos !== false) {
-			$mediaWidth = self::bsMaxGridWidth / 6 - self::gridGutterWidth;
-		}
-
-		return (int) $mediaWidth;
-	}
-
-
-	/**
-	 * Returns the frontend controller
-	 */
-	protected function getFrontendController(): TypoScriptFrontendController
-	{
-		return $GLOBALS['TSFE'];
-	}
-
-
+    public const bsMaxGridWidth = 1320;
+    public const maxGalleryWidth = 1296;
+    public const minimumWidth = 575;
+    public const gridColumns = 12;
+    public const gridGutterWidth = 24; // default 1.5rem => 24px
+
+    protected $contentObjectRenderer;
+    protected $contentObjectConfiguration;
+    protected $processorConfiguration;
+    protected $numberOfColumns;
+    protected $mediaOrientation;
+    protected $maxGalleryWidth;
+    protected $equalMediaHeight;
+    protected $equalMediaWidth;
+    protected $cropVariant = 'default';
+    protected $fileObjects = [];
+    protected $mediaDimensions = [];
+    protected $beLayout = 'OneCol';
+    protected $colPos;
+    protected $parentgridColPos;
+    protected $minimumWidth;
+    protected $ratioWithHeight;
+    protected $pageContainer;
+    protected $rowWidth;
+    protected $columns;
+    protected $cType;
+    protected $bodytext;
+    protected $maxWidthMediaObject;
+    protected $maxWidthToast;
+    protected $disableAutoRow;
+    protected $parentflexconf;
+    protected $processedData;
+    protected $processedParentData;
+    protected $cardWrapper;
+    protected $availableGalleryPositions = [
+        'horizontal' => [
+            'center' => [0, 8],
+            'right' => [1, 9, 17, 25],
+            'left' => [2, 10, 18, 26]
+        ],
+        'vertical' => [
+            'above' => [0, 1, 2],
+            'intext' => [17, 18, 25, 26, 66, 77],
+            'below' => [8, 9, 10]
+        ]
+    ];
+    protected $galleryData = [
+        'position' => [
+            'horizontal' => '',
+            'vertical' => '',
+            'noWrap' => false
+        ],
+        'width' => 0,
+        'count' => [
+            'files' => 0,
+            'columns' => 0,
+            'rows' => 0,
+        ],
+        'border' => [
+            'enabled' => false,
+            'width' => 0,
+            'padding' => 0,
+        ],
+        'rows' => []
+    ];
+
+
+    /**
+     * Process data for a gallery, for instance the CType "textmedia"
+     *
+     * @param ContentObjectRenderer $cObj The content object renderer, which contains data of the content element
+     * @param array $contentObjectConfiguration The configuration of Content Object
+     * @param array $processorConfiguration The configuration of this processor
+     * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
+     * @return array the processed data as key/value store
+     * @throws ContentRenderingException
+     */
+    public function process(
+        ContentObjectRenderer $cObj,
+        array $contentObjectConfiguration,
+        array $processorConfiguration,
+        array $processedData
+    ): array {
+        if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
+            return $processedData;
+        }
+
+        $this->contentObjectRenderer = $cObj;
+        $this->processorConfiguration = $processorConfiguration;
+        $this->processedData = $processedData;
+        $this->contentObjectConfiguration = $contentObjectConfiguration;
+
+        if (!empty($this->processedData['data']['tx_container_parent'])) {
+            $this->processedParentData = self::getContentRecord($this->processedData['data']['tx_container_parent']);
+        } else {
+            $this->processedParentData = [];
+        }
+
+        $filesProcessedDataKey = (string)$cObj->stdWrapValue(
+            'filesProcessedDataKey',
+            $processorConfiguration,
+            'files'
+        );
+
+        if (isset($this->processedData[$filesProcessedDataKey]) && is_array($this->processedData[$filesProcessedDataKey])) {
+            $this->fileObjects = $this->processedData[$filesProcessedDataKey];
+
+            if (!empty($this->fileObjects[0])) {
+                $fileObjects = [];
+                // image gallery
+                foreach ($this->fileObjects as $fileObject) {
+                    $fileObjects[] = $fileObject;
+                }
+                $this->fileObjects = $fileObjects;
+            }
+            $this->galleryData['count']['files'] = count($this->fileObjects);
+        } else {
+            throw new ContentRenderingException('No files found for key ' . $filesProcessedDataKey . ' in $processedData.', 1436809789);
+        }
+
+        if (empty($this->fileObjects)) {
+            return $this->processedData;
+        }
+
+        $this->ratioWithHeight = $this->getConfigurationValue('ratioWithHeight');
+        $this->cropVariant = $this->getConfigurationValue('cropVariant') ?: 'default';
+        $this->equalMediaHeight = (int)$this->getConfigurationValue('equalMediaHeight', 'imageheight');
+        $this->equalMediaWidth = (int)$this->getConfigurationValue('equalMediaWidth', 'imagewidth');
+        $this->numberOfColumns = (int)$this->getConfigurationValue('numberOfColumns', 'imagecols');
+        $this->maxGalleryWidth = (int)$this->getConfigurationValue('maxGalleryWidth') ?: self::maxGalleryWidth;
+        $this->mediaOrientation = (int)$this->getConfigurationValue('mediaOrientation', 'imageorient');
+        $this->beLayout = $this->processedData['be_layout'];
+        $this->colPos = (int)$this->processedData['data']['colPos'];
+        $this->minimumWidth = $this->getConfigurationValue('minimumWidth');
+        $this->bodytext = $this->processedData['data']['bodytext'];
+        $this->cType = $this->processedData['data']['CType'];
+        $this->rowWidth = $this->processedData['data']['tx_t3sbootstrap_inTextImgRowWidth'];
+        $this->maxWidthMediaObject = $this->getConfigurationValue('maxWidthMediaObject');
+        $this->maxWidthToast = $this->getConfigurationValue('maxWidthToast');
+        $this->disableAutoRow = $this->getConfigurationValue('disableAutoRow');
+
+        $flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
+        $this->parentflexconf = !empty($this->processedParentData['tx_t3sbootstrap_flexform'])
+         ? $flexFormService->convertFlexFormContentToArray($this->processedParentData['tx_t3sbootstrap_flexform']) : [];
+
+        $pageContainer = self::getFrontendController()->page['tx_t3sbootstrap_container'];
+        $contentContainer = $this->processedData['data']['tx_t3sbootstrap_container'];
+        if ($pageContainer) {
+            $this->pageContainer = $pageContainer;
+        } elseif ($contentContainer) {
+            $this->pageContainer = $contentContainer;
+        } else {
+            $this->pageContainer = '';
+        }
+
+        $this->determineGalleryPosition();
+        $this->calculateRowsAndColumns();
+        $this->determineMaximumGalleryWidth();
+        $this->calculateMediaWidthsAndHeights();
+        $this->prepareGalleryData();
+
+        $targetFieldName = (string)$cObj->stdWrapValue(
+            'as',
+            $processorConfiguration,
+            'gallery'
+        );
+
+        $this->processedData[$targetFieldName] = $this->galleryData;
+
+        return $this->processedData;
+    }
+
+    /**
+     * Get configuration value from processorConfiguration
+     * with when $dataArrayKey fallback to value from cObj->data array
+     *
+     * @param string $key
+     * @param string|NULL $dataArrayKey
+     * @return string
+     */
+    protected function getConfigurationValue(string $key, string|null $dataArrayKey = null): string
+    {
+        $defaultValue = '';
+        if ($dataArrayKey && isset($this->contentObjectRenderer->data[$dataArrayKey])) {
+            $defaultValue = $this->contentObjectRenderer->data[$dataArrayKey];
+        }
+        return $this->contentObjectRenderer->stdWrapValue(
+            $key,
+            $this->processorConfiguration,
+            $defaultValue
+        );
+    }
+
+    /**
+     * Define the gallery position
+     *
+     * Gallery has a horizontal and a vertical position towards the text
+     * and a possible wrapping of the text around the gallery.
+     */
+    protected function determineGalleryPosition()
+    {
+        foreach ($this->availableGalleryPositions as $positionDirectionKey => $positionDirectionValue) {
+            foreach ($positionDirectionValue as $positionKey => $positionArray) {
+                if (in_array($this->mediaOrientation, $positionArray, true)) {
+                    $this->galleryData['position'][$positionDirectionKey] = $positionKey;
+                }
+            }
+        }
+
+        if ($this->mediaOrientation === 25 || $this->mediaOrientation === 26) {
+            $this->galleryData['position']['noWrap'] = true;
+        }
+        $this->galleryData['position']['alignCenter'] = false;
+        if ($this->mediaOrientation === 66 || $this->mediaOrientation === 77) {
+            $this->galleryData['position']['alignCenter'] = true;
+        }
+    }
+
+
+    /**
+     * Get the gallery width if 'tx_t3sbootstrap_inTextImgRowWidth' is set to 'auto'
+     */
+    protected function determineMaximumGalleryWidth(): void
+    {
+        if ($this->rowWidth == 'auto' && $this->disableAutoRow) {
+            $this->rowWidth = 'none';
+        }
+
+        if ($this->rowWidth == 'auto') {
+            if ($this->cType == 'textmedia' || $this->cType == 'textpic' || $this->cType == 'image') {
+                if ($this->bodytext) {
+                    if ($this->galleryData['position']['vertical'] === 'intext') {
+                        if ($this->galleryData['count']['columns'] === 1) {
+                            $this->rowWidth = 33;
+                        } else {
+                            $this->rowWidth = 50;
+                        }
+                    } else {
+                        // above or below
+                        $this->rowWidth = 66;
+                    }
+                    if ($this->galleryData['position']['vertical'] == 'above' || $this->galleryData['position']['vertical'] == 'below') {
+                        $this->rowWidth = 100;
+                    }
+                } else {
+                    $this->rowWidth = 100;
+                }
+
+                // Cards inside a card-wrapper
+            } elseif ($this->cType == 't3sbs_card' && $this->processedData['data']['tx_container_parent']
+             && $this->processedParentData['CType'] == 'card_wrapper') {
+                $this->rowWidth = 100;
+            } else {
+                $this->rowWidth = 100;
+            }
+        }
+    }
+
+
+    /**
+     * Calculate the amount of rows and columns
+     */
+    protected function calculateRowsAndColumns(): void
+    {
+        // If no columns defined, set it to 1
+        $columns = max((int)$this->numberOfColumns, 1);
+
+        if ($columns === 88) {
+            $columns = 1;
+        } else {
+            // When more columns than media elements, set the columns to the amount of media elements
+            if ($columns > $this->galleryData['count']['files']) {
+                if ($this->processedData['data']['CType'] !== 't3sbs_gallery') {
+                    $columns = $this->galleryData['count']['files'];
+                }
+            }
+        }
+
+        if ($columns === 0) {
+            $columns = 1;
+        }
+
+        // Calculate the rows from the amount of files and the columns
+        $rows = ceil($this->galleryData['count']['files'] / $columns);
+        $this->galleryData['count']['columns'] = $columns;
+        $this->galleryData['count']['rows'] = (int)$rows;
+    }
+
+
+    /**
+     * Calculate the width/height of the media elements
+     *
+     * Based on the width of the gallery, defined equal width or height by a user, the spacing between columns and
+     * the use of a border, defined by user, where the border width and padding are taken into account
+     *
+     * File objects MUST already be filtered. They need a height and width to be shown in the gallery
+     */
+    protected function calculateMediaWidthsAndHeights()
+    {
+        if ($this->equalMediaWidth == 0 && $this->equalMediaHeight == 0) {
+
+            // container
+            $pageContainer = self::getPageContainer($this->pageContainer);
+            if (str_contains($pageContainer, 'container-fluid')) {
+                $bsMaxGridWidth = !empty($_COOKIE['viewportWidth']) ? (int)$_COOKIE['viewportWidth'] : 1920;
+                $bsMaxGridWidth = $bsMaxGridWidth - self::gridGutterWidth;
+            } else {
+                $bsMaxGridWidth = self::maxGalleryWidth;
+            }
+
+            // row width
+            if (is_int($this->rowWidth)) {
+                $rowWidth = $this->rowWidth;
+            } elseif ($this->rowWidth != 'none' && is_string($this->rowWidth)) {
+                $rowWidth = (int) end(explode('-', $this->rowWidth));
+            } else {
+                $rowWidth = 100;
+            }
+            if ($this->cType == 't3sbs_gallery') {
+                $rowWidth = 100;
+            }
+
+            if ($this->colPos == 0
+                || $this->colPos == 1
+                || $this->colPos == 2
+                || ($this->colPos > 199 && $this->processedParentData['colPos'] < 3)
+            ) {
+                if ($this->processorConfiguration['overrideSmallColumns']) {
+                    $defaultSmallColumns = $this->processorConfiguration['overrideSmallColumns'];
+                } else {
+                    $defaultSmallColumns = 0;
+                }
+                $smallColumns = $defaultSmallColumns ?: self::getFrontendController()->page['tx_t3sbootstrap_smallColumns'];
+
+                if ($this->beLayout == 'OneCol') {
+                    $bsGridWidth = $bsMaxGridWidth;
+                } elseif ($this->beLayout == 'ThreeCol') {
+
+                    // Three columns
+                    $bsMaxGridWidth = $bsMaxGridWidth + self::gridGutterWidth;
+                    $bsAsideGridWidth = $bsMaxGridWidth / self::gridColumns * (int) $smallColumns;
+                    $bsMainGridWidth = $bsMaxGridWidth - $bsAsideGridWidth * 2;
+
+                    // Main
+                    if ($this->colPos === 0 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 0)) {
+                        $bsGridWidth = $bsMainGridWidth;
+                    // Aside
+                    } elseif ($this->colPos === 1 || $this->colPos === 2
+                     || ($this->colPos > 199 && $this->processedParentData['colPos'] === 1)
+                     || ($this->colPos > 199 && $this->processedParentData['colPos'] === 2)) {
+                        $bsGridWidth = $bsAsideGridWidth;
+                    }
+                } else {
+
+                    // Two columns
+                    $bsMaxGridWidth = $bsMaxGridWidth + self::gridGutterWidth;
+                    $bsAsideGridWidth = $bsMaxGridWidth / self::gridColumns * (int) $smallColumns;
+                    $bsMainGridWidth = $bsMaxGridWidth - $bsAsideGridWidth;
+
+                    // Main
+                    if ($this->colPos === 0 || ($this->colPos > 199 && $this->processedParentData['colPos'] === 0)) {
+                        $bsGridWidth = $bsMainGridWidth;
+                    // Aside
+                    } elseif ($this->colPos === 1 || $this->colPos === 2
+                     || ($this->colPos > 199 && $this->processedParentData['colPos'] === 1)
+                     || ($this->colPos > 199 && $this->processedParentData['colPos'] === 2)) {
+                        $bsGridWidth = $bsAsideGridWidth;
+                    }
+                }
+            }
+
+            // Jumbotron, footer && expanded content
+            if ($this->colPos == 3
+                || $this->colPos == 4
+                || $this->colPos == 20
+                || $this->colPos == 21
+                || (($this->colPos > 199) && ($this->processedParentData['colPos'] > 2))
+            ) {
+                $bsGridWidth = $bsMaxGridWidth;
+            }
+
+            // Modal - INFO: https://getbootstrap.com/docs/5.3/components/modal/#optional-sizes
+            if (isset($this->processedParentData['CType']) && $this->processedParentData['CType'] == 'modal') {
+                $size = $this->parentflexconf['size'];
+
+                if ($size == 'modal-fullscreen') {
+                    $bsGridWidth = $bsMaxGridWidth;
+                } elseif ($size == 'modal-xl') {
+                    $bsGridWidth = 1140;
+                } elseif ($size == 'modal-lg') {
+                    $bsGridWidth = 800;
+                } elseif ($size == 'modal-sm') {
+                    $bsGridWidth = 300;
+                } else {
+                    $bsGridWidth = 500;
+                }
+            }
+
+            if (isset($this->processedParentData['CType']) && $this->processedParentData['CType'] == 'collapsible_accordion') {
+                $bsGridWidth = $bsGridWidth - self::gridGutterWidth - 17;
+            }
+
+            // Child of grid container
+            if (!empty($this->processedParentData['CType']) && ($this->processedParentData['CType'] == 'two_columns'
+             || $this->processedParentData['CType'] == 'three_columns'
+             || $this->processedParentData['CType'] == 'four_columns'
+             || $this->processedParentData['CType'] == 'six_columns')) {
+                $bsGridWidth = $bsGridWidth + self::gridGutterWidth;
+                $bsGridWidth = self::getCalculatedGridWidth($bsGridWidth);
+            } else {
+                if ($this->beLayout == 'OneCol') {
+                    $bsGridWidth = $bsGridWidth + self::gridGutterWidth;
+                }
+            }
+
+            $rowWidth = $rowWidth ? $rowWidth : 100;
+
+            $galleryWidth = $bsGridWidth / 100 * $rowWidth;
+
+            // Card Wrapper
+            if ($this->cType == 't3sbs_card' && $this->processedData['data']['tx_container_parent']
+                         && $this->processedParentData['CType'] == 'card_wrapper') {
+                $galleryWidth = $galleryWidth - self::gridGutterWidth;
+                if ($this->parentflexconf['card_wrapper'] === 'group' || $this->parentflexconf['card_wrapper'] === 'columns') {
+                    $this->processedData['data']['tx_t3sbootstrap_gutters'] = '';
+                    $this->galleryData['count']['columns'] = -1;
+                    // Masonry (columns)
+                    if ($this->parentflexconf['card_wrapper'] === 'columns' && str_contains($this->parentflexconf['colclass'], 'col-lg-')) {
+                        foreach (explode(' ', $this->parentflexconf['colclass']) as $class) {
+                            if (str_contains($class, 'col-lg-')) {
+                                $countChildren = 12 / (int)end(explode('-', $class));
+                            }
+                        }
+                        $galleryWidth = $galleryWidth + self::gridGutterWidth - self::gridGutterWidth * $countChildren;
+                    } else {
+                        // Group
+                        $countChildren = self::countContentRecord($this->processedData['data']['tx_container_parent'], 'tt_content', 'tx_container_parent');
+                    }
+                    $galleryWidth = $galleryWidth / $countChildren;
+                } elseif ($this->parentflexconf['card_wrapper'] === 'slider') {
+                    // Slider
+                    $this->galleryData['count']['columns'] = -1;
+                    $this->processedData['data']['tx_t3sbootstrap_gutters'] = '';
+                } elseif ($this->parentflexconf['card_wrapper'] === 'flipper') {
+                    // Flipper
+                    $this->galleryData['count']['columns'] = -1;
+                    $this->processedData['data']['tx_t3sbootstrap_gutters'] = '';
+                } else {
+                    $gutter = !empty($this->parentflexconf['gutter']) ? $this->parentflexconf['gutter'] : 0;
+                    $visibleCards = !empty($this->parentflexconf['visibleCards']) ? $this->parentflexconf['visibleCards'] : 1;
+                    $this->processedData['data']['tx_t3sbootstrap_gutters'] = 'gx-'.$gutter;
+                    $this->galleryData['count']['columns'] = $visibleCards;
+                }
+            }
+        }
+
+
+
+        // User entered a predefined width
+        if ($this->equalMediaWidth) {
+            $mediaWidth = self::checkMediaWidth($this->equalMediaWidth);
+
+            // User entered a predefined width & height
+            if ($this->equalMediaHeight) {
+                // Set the corrected dimensions for each media element
+                foreach ($this->fileObjects as $key => $fileObject) {
+                    if ($this->ratioWithHeight) {
+                        $ratio = $this->equalMediaWidth .':'. $this->equalMediaHeight;
+                        $mediaHeight = '';
+                    } else {
+                        $ratio = '';
+                        if ($fileObject instanceof \TYPO3\CMS\Core\Resource\FileReference) {
+                            $mediaHeight = $this->getCroppedDimensionalProperty($fileObject, 'height')
+                             * ($mediaWidth / max($this->getCroppedDimensionalProperty($fileObject, 'width'), 1));
+                        }
+                    }
+
+                    $mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
+                    $this->mediaDimensions[$key] = [
+                        'width' => floor($mediaWidth),
+                        'height' => $mediaHeight,
+                        'ratio' => $ratio
+                    ];
+                }
+            } else {
+                // Set the corrected dimensions for each media element
+                foreach ($this->fileObjects as $key => $fileObject) {
+                    if (is_array($fileObject)) {
+                        foreach ($fileObject as $fO) {
+                            $fileObject = $fO;
+                        }
+                    }
+                    $mediaHeight = $this->getCroppedDimensionalProperty($fileObject, 'height')
+                     * ($mediaWidth / max($this->getCroppedDimensionalProperty($fileObject, 'width'), 1));
+
+                    $mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
+                    $this->mediaDimensions[$key] = [
+                        'width' => floor($mediaWidth),
+                        'height' => $mediaHeight,
+                        'ratio' => ''
+                    ];
+                }
+            }
+
+            // User entered a predefined height only
+        } elseif ($this->equalMediaHeight) {
+
+            // Set the corrected dimensions for each media element
+            foreach ($this->fileObjects as $key => $fileObject) {
+                $mediaHeight = $this->equalMediaHeight;
+                if (is_array($fileObject)) {
+                    $fileObject = $fileObject[0];
+                }
+                if ($fileObject instanceof \TYPO3\CMS\Core\Resource\FileReference) {
+                    $mediaWidth = $this->getCroppedDimensionalProperty($fileObject, 'width')
+                     * ($mediaHeight / max($this->getCroppedDimensionalProperty($fileObject, 'height'), 1));
+                }
+                $mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
+                $this->mediaDimensions[$key] = [
+                    'width' => floor($mediaWidth),
+                    'height' => $mediaHeight,
+                    'ratio' => ''
+                ];
+            }
+
+            // Automatic setting of width and height
+        } else {
+            $gutterWidth = 0;
+            $ratio = 0;
+
+            if (!empty($this->processedData['data']['tx_t3sbootstrap_gutters'])) {
+                // margin rem in px (base 16px)
+                $gx = [ 'gx-0' => 0, 'gx-1' => 4, 'gx-2' => 8, 'gx-3' => 16, 'gx-4' => 24, 'gx-5' => 48 ];
+                $gutterWidth = $gx[$this->processedData['data']['tx_t3sbootstrap_gutters']];
+                if (!empty($this->parentflexconf['noGutters'])) {
+                    $gutterWidth = 0;
+                }
+            }
+
+
+            if ($this->processedData['data']['CType'] === 't3sbs_gallery') {
+                $galleryWidth = $galleryWidth - self::gridGutterWidth + $gutterWidth;
+                $gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
+                $mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
+            } else {
+                if ($this->galleryData['count']['columns'] > 1) {
+                    if ($this->galleryData['position']['noWrap']) {
+                        # imageorient 25 & 26
+                        if ($this->processedData['data']['tx_t3sbootstrap_gutters'] ==  'gx-0') {
+                            $galleryWidth = $galleryWidth - self::gridGutterWidth;
+                        } else {
+                            $galleryWidth = $galleryWidth - $gutterWidth * $this->galleryData['count']['columns'];
+                        }
+                        $mediaWidth = ceil($galleryWidth / $this->galleryData['count']['columns']);
+                    } else {
+                        if ($this->galleryData['position']['alignCenter']) {
+                            # imageorient 66 & 77
+                            if ($this->processedData['data']['tx_t3sbootstrap_gutters'] ==	'gx-0') {
+                                $galleryWidth = $galleryWidth - self::gridGutterWidth;
+                            } else {
+                                $galleryWidth = $galleryWidth + self::gridGutterWidth;
+                            }
+                            $gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
+                            $mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
+                        } else {
+                            if ($this->galleryData['position']['vertical'] === 'above' || $this->galleryData['position']['vertical'] === 'below') {
+                                # imageorient 0 - 10
+                                $galleryWidth = $galleryWidth - self::gridGutterWidth + $gutterWidth;
+                                $gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
+                                $mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
+                            } else {
+                                # imageorient 17 & 18
+                                if ($this->processedData['data']['tx_t3sbootstrap_gutters'] ==	 'gx-0') {
+                                    $galleryWidth = $galleryWidth - self::gridGutterWidth / 2;
+                                    $mediaWidth = ceil($galleryWidth / $this->galleryData['count']['columns']);
+                                } else {
+                                    $galleryWidth = $galleryWidth - self::gridGutterWidth / 2 + $gutterWidth;
+                                    $gutterWidth = $gutterWidth * $this->galleryData['count']['columns'];
+                                    $mediaWidth = ceil(($galleryWidth - $gutterWidth) / $this->galleryData['count']['columns']);
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    if ($this->galleryData['count']['columns'] === -1 && $this->parentflexconf['card_wrapper'] !== 'slider') {
+                        $mediaWidth = $galleryWidth;
+                    } elseif ($this->mediaOrientation === 17 || $this->mediaOrientation === 18) {
+                        // workaround
+                        $mediaWidth = $galleryWidth - 7;
+                    } elseif (!empty($this->parentflexconf) && isset($this->parentflexconf['card_wrapper']) && $this->parentflexconf['card_wrapper'] === 'slider') {
+                        $mediaWidth = ($galleryWidth - (int)$this->parentflexconf['spaceBetween']) / (int)$this->parentflexconf['breakpoints992'];
+                        $ratio = $this->parentflexconf['ratio'];
+                    } else {
+                        $mediaWidth = $galleryWidth - self::gridGutterWidth;
+                    }
+                }
+            }
+
+            $mediaWidth = self::checkMediaWidth($mediaWidth);
+
+            // Set the corrected dimensions for each media element
+            foreach ($this->fileObjects as $key => $fileObject) {
+                if (is_array($fileObject)) {
+                    $fileObject = $fileObject[0];
+                }
+                if ($fileObject instanceof \TYPO3\CMS\Core\Resource\FileReference) {
+                    $mediaHeight = $this->getCroppedDimensionalProperty($fileObject, 'height')
+                     * ($mediaWidth / max($this->getCroppedDimensionalProperty($fileObject, 'width'), 1));
+                }
+                $mediaHeight = !empty($mediaHeight) ? floor($mediaHeight) : '';
+                $this->mediaDimensions[$key] = [
+                    'width' => floor($mediaWidth),
+                    'height' => $mediaHeight,
+                    'ratio' => $ratio
+                ];
+            }
+        }
+
+        $this->galleryData['width'] = (int) ceil($mediaWidth);
+    }
+
+
+    /**
+     * When retrieving the height or width for a media file
+     * a possible cropping needs to be taken into account.
+     */
+    protected function getCroppedDimensionalProperty(FileInterface $fileObject, string $dimensionalProperty): int|array
+    {
+        if (!$fileObject->hasProperty('crop') || empty($fileObject->getProperty('crop'))) {
+            return $fileObject->getProperty($dimensionalProperty);
+        }
+
+        $croppingConfiguration = $fileObject->getProperty('crop');
+        $cropVariantCollection = CropVariantCollection::create((string)$croppingConfiguration);
+        return (int) $cropVariantCollection->getCropArea($this->cropVariant)->makeAbsoluteBasedOnFile($fileObject)->asArray()[$dimensionalProperty];
+    }
+
+
+    /**
+     * Prepare the gallery data
+     *
+     * Make an array for rows, columns and configuration
+     */
+    protected function prepareGalleryData(): void
+    {
+        for ($row = 1; $row <= $this->galleryData['count']['rows']; $row++) {
+            $this->galleryData['count']['columns'] = $this->galleryData['count']['columns'] === -1 ? 3 : $this->galleryData['count']['columns'];
+            for ($column = 1; $column <= $this->galleryData['count']['columns']; $column++) {
+                $fileKey = (($row - 1) * $this->galleryData['count']['columns']) + $column - 1;
+                $this->galleryData['rows'][$row]['columns'][$column] = [
+                    'media' => $this->fileObjects[$fileKey] ?? null,
+                    'dimensions' => [
+                        'width' => $this->mediaDimensions[$fileKey]['width'] ?? null,
+                        'height' => $this->mediaDimensions[$fileKey]['height'] ?? null,
+                        'ratio' => $this->mediaDimensions[$fileKey]['ratio'] ?? null
+                    ]
+                ];
+            }
+        }
+    }
+
+
+    /**
+     * Returns the page container
+     *
+     * @param string $pageContainer
+     * @return string
+     */
+    protected function getPageContainer($pageContainer): string
+    {
+        if ($this->processedData['data']['tx_container_parent'] && !$pageContainer) {
+            if ($this->processedParentData['tx_t3sbootstrap_container']) {
+                $pageContainer = $this->processedParentData['tx_t3sbootstrap_container'];
+            } else {
+                if ($this->processedParentData['tx_container_parent']) {
+                    $grandParent = self::getContentRecord($this->processedParentData['tx_container_parent']);
+                    if ($grandParent['tx_t3sbootstrap_container']) {
+                        $pageContainer = $grandParent['tx_t3sbootstrap_container'];
+                    }
+                }
+            }
+        }
+
+        // Container if Jumbotron, footer OR expanded content
+        if ($this->colPos == 3
+            || $this->colPos == 4
+            || $this->colPos == 20
+            || $this->colPos == 21
+            || ($this->colPos > 199 && $this->processedParentData['colPos'] > 2)
+            || ($this->colPos > 199 && $this->processedData['data']['CType'] == 'background_wrapper')
+        ) {
+            $t3sbconfig = self::getContentRecord((int)$this->getConfigurationValue('configuid'), 'tx_t3sbootstrap_domain_model_config');
+
+            $jumbotronContainer = $t3sbconfig['jumbotron_container'];
+            $footerContainer = $t3sbconfig['footer_container'];
+            $expandedcontentTopContainer = $t3sbconfig['expandedcontent_containertop'];
+            $expandedcontentBottomContainer = $t3sbconfig['expandedcontent_containerbottom'];
+
+            switch ($this->colPos) {
+                case 3: // jumbotron
+                    $pageContainer = $jumbotronContainer;
+                    break;
+                case 4: // Footer
+                    $pageContainer = $footerContainer;
+                    break;
+                case 20: // Expanded content Top Container
+                    $pageContainer = $expandedcontentTopContainer;
+                    break;
+                case 21: // Expanded content Bottom Container
+                    $pageContainer = $expandedcontentBottomContainer;
+                    break;
+                default:
+                    if ($this->colPos > 199) {
+                        if ($this->processedParentData['colPos'] == 3) {
+                            $pageContainer = $jumbotronContainer;
+                        } elseif ($this->processedParentData['colPos'] == 4) {
+                            $pageContainer = $footerContainer;
+                        } elseif ($this->processedParentData['colPos'] == 20) {
+                            $pageContainer = $expandedcontentTopContainer;
+                        } elseif ($this->processedParentData['colPos'] == 21) {
+                            $pageContainer = $expandedcontentBottomContainer;
+                        }
+                    }
+                    break;
+            }
+
+            if (!$footerContainer && $t3sbconfig['footer_pid'] && $this->colPos > 199 && $this->processedParentData['colPos'] == 0
+             && $this->processedData['data']['CType'] == 'background_wrapper') {
+                $pageContainer = $this->processedParentData['data']['tx_t3sbootstrap_container'];
+            }
+        }
+
+        return !empty($this->processorConfiguration['overrideContainer']) ? $this->processorConfiguration['overrideContainer'] : $pageContainer;
+    }
+
+
+    /**
+     * Returns content record
+     *
+     * @param int $uid
+     * @param string $table
+     * @param string $equal
+     *
+     * @return array $result
+     */
+    protected function getContentRecord($uid, $table='tt_content', $equal='uid'): array
+    {
+        return BackendUtility::getRecord($table, $uid, '*');
+    }
+
+
+    /**
+     * Returns content record
+     *
+     * @param int $uid
+     * @param string $table
+     * @param string $equal
+     *
+     * @return int $result
+     */
+    protected function countContentRecord($uid, $table='tt_content', $equal='uid'): int
+    {
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
+        $result = $queryBuilder
+             ->count('uid')
+             ->from($table)
+             ->where(
+                 $queryBuilder->expr()->eq($equal, $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+             )
+             ->executeQuery()->fetchOne();
+
+        return $result;
+    }
+
+
+    /**
+     * Returns calculated grid width
+     *
+     * @param int $bsGridWidth
+     *
+     * @return int $gridWidth
+     */
+    protected function getCalculatedGridWidth($bsGridWidth): int
+    {
+        switch ($this->processedParentData['CType']) {
+            case 'two_columns':
+                if ($this->processedData['data']['colPos'] === 221) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'one');
+                } else {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'two');
+                }
+                break;
+            case 'three_columns':
+                if ($this->processedData['data']['colPos'] === 231) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'one');
+                } elseif ($this->processedData['data']['colPos'] === 232) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'two');
+                } else {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'three');
+                }
+                break;
+            case 'four_columns':
+                if ($this->processedData['data']['colPos'] === 241) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'one');
+                } elseif ($this->processedData['data']['colPos'] === 242) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'two');
+                } elseif ($this->processedData['data']['colPos'] === 243) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'three');
+                } else {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'four');
+                }
+                break;
+            case 'six_columns':
+                if ($this->processedData['data']['colPos'] === 261) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'one');
+                } elseif ($this->processedData['data']['colPos'] === 262) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'two');
+                } elseif ($this->processedData['data']['colPos'] === 263) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'three');
+                } elseif ($this->processedData['data']['colPos'] === 264) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'four');
+                } elseif ($this->processedData['data']['colPos'] === 265) {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'five');
+                } else {
+                    $gridWidth = self::getGridWidth($bsGridWidth, 'six');
+                }
+                break;
+        }
+
+        return $gridWidth;
+    }
+
+
+    /**
+     * Returns $ mediaWidth if there is a parent grid element
+     *
+     * @param int $bsGridWidth
+     * @param string $suffix
+     *
+     * @return int $gridWidth
+     */
+    protected function getGridWidth($bsGridWidth, $suffix): int
+    {
+        if (!empty($this->parentflexconf['sm_'.$suffix])) {
+            $gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['sm_'.$suffix];
+        } elseif (!empty($this->parentflexconf['md_'.$suffix])) {
+            $gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['md_'.$suffix];
+        } elseif (!empty($this->parentflexconf['lg_'.$suffix])) {
+            $gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['lg_'.$suffix];
+        } elseif (!empty($this->parentflexconf['xl_'.$suffix])) {
+            $gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['xl_'.$suffix];
+        } elseif (!empty($this->parentflexconf['xxl_'.$suffix])) {
+            $gridWidth = $bsGridWidth / self::gridColumns * (int) $this->parentflexconf['xxl_'.$suffix];
+        } else {
+            $gridWidth = $bsGridWidth / self::gridColumns * ($this->numberOfColumns);
+        }
+
+        return $gridWidth;
+    }
+
+
+    /**
+     * Returns $mediaWidth and check some conditions
+     *
+     * @param int $mediaWidth
+     *
+     * @return int $mediaWidth
+     */
+    protected function checkMediaWidth($mediaWidth): int
+    {
+        if ($this->minimumWidth && $mediaWidth < self::minimumWidth) {
+            // set to 575px and therefore 100% wide on mobile (constant: minimumWidth=1)
+            $mediaWidth = self::minimumWidth;
+        }
+        // t3sbs_mediaobject
+        if ($this->cType == 't3sbs_mediaobject' && $this->maxWidthMediaObject < $mediaWidth) {
+            $mediaWidth = $this->maxWidthMediaObject;
+        }
+        // t3sbs_toast
+        if ($this->cType == 't3sbs_toast' && $this->maxWidthToast < $mediaWidth) {
+            $mediaWidth = $this->maxWidthToast;
+        }
+        // card slider
+        if (!empty($this->parentflexconf['width']) && !empty($this->parentflexconf['card_wrapper']) && $this->parentflexconf['card_wrapper'] === 'slider') {
+            $mediaWidth = (int)$this->parentflexconf['width'];
+        }
+        // masonry_wrapper
+        if (!empty($this->processedParentData['CType']) && $this->processedParentData['CType'] == 'masonry_wrapper') {
+            $classPrefix = 'col-lg-';
+            $mediaWidth = $this->getMansoryColumns($classPrefix);
+            if (!$mediaWidth) {
+                $classPrefix = 'col-xl-';
+                $mediaWidth = $this->getMansoryColumns($classPrefix);
+            }
+            if (!$mediaWidth) {
+                $classPrefix = 'col-xxl-';
+                $mediaWidth = $this->getMansoryColumns($classPrefix);
+            }
+            if (!$mediaWidth) {
+                $classPrefix = 'col-sm-';
+                $mediaWidth = $this->getMansoryColumns($classPrefix);
+            }
+            if (!$mediaWidth) {
+                $mediaWidth = self::bsMaxGridWidth / 2;
+            }
+        }
+
+        return (int) $mediaWidth;
+    }
+
+
+    /**
+     * Returns mansory columns
+     *
+     * @param string $classPrefix
+     *
+     * @return int $mediaWidth
+     */
+    protected function getMansoryColumns($classPrefix): int
+    {
+        # 2 columns
+        $pos = strpos($this->parentflexconf['colclass'], $classPrefix.'6');
+        if ($pos !== false) {
+            $mediaWidth = self::bsMaxGridWidth / 2 - self::gridGutterWidth;
+        }
+        # 3 columns
+        $pos = strpos($this->parentflexconf['colclass'], $classPrefix.'4');
+        if ($pos !== false) {
+            $mediaWidth = self::bsMaxGridWidth / 3 - self::gridGutterWidth;
+        }
+        # 4 columns
+        $pos = strpos($this->parentflexconf['colclass'], $classPrefix.'3');
+        if ($pos !== false) {
+            $mediaWidth = self::bsMaxGridWidth / 4 - self::gridGutterWidth;
+        }
+        # 6 columns
+        $pos = strpos($this->parentflexconf['colclass'], $classPrefix.'2');
+        if ($pos !== false) {
+            $mediaWidth = self::bsMaxGridWidth / 6 - self::gridGutterWidth;
+        }
+
+        return (int) $mediaWidth;
+    }
+
+
+    /**
+     * Returns the frontend controller
+     */
+    protected function getFrontendController(): TypoScriptFrontendController
+    {
+        return $GLOBALS['TSFE'];
+    }
 }
diff --git a/Classes/DataProcessing/LastModifiedProcessor.php b/Classes/DataProcessing/LastModifiedProcessor.php
index 4d46f0dd..4c9ede7d 100644
--- a/Classes/DataProcessing/LastModifiedProcessor.php
+++ b/Classes/DataProcessing/LastModifiedProcessor.php
@@ -1,4 +1,5 @@
 getRecords('tt_content', $processorConfiguration);
-
-			foreach ( $records as $record ) {
-				$lmc[] = $record['tstamp'];
-			}
-
-			if (!empty($lmc)) {
-				rsort($lmc,SORT_NUMERIC);
-			} else {
-				$lmc[0] = '';
-			}
-
-			$processedData['lastModifiedContentElement'] = $lmc[0];
-		}
-
-		if (!empty($processorConfiguration['recentlyUpdatedContentElements'])) {
-
-			$setMaxResults = !empty($processorConfiguration['setMaxResults']) ? $processorConfiguration['setMaxResults'] : 10;
-			if (self::isMenuRecentlyUpdatedOnPage()) {
-				$processedData['recentlyUpdatedContentElements'] = self::getRecentlyUpdated((int) $setMaxResults);
-			}
-		}
-
-		return $processedData;
-	}
-
-
-	/**
-	 * Returns true if is page w/ content.cType == menu_recently_updated
-	 *
-	 * @return bool $mdtm
-	 */
-	protected function isMenuRecentlyUpdatedOnPage(): bool
-	{
-		$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
-		$sysLanguageUid = $languageAspect->getContentId() ?: 0;
-		$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
-		$result = $queryBuilder
-			 ->select('uid')
-			 ->from('tt_content')
-			 ->where(
-				$queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($sysLanguageUid, \PDO::PARAM_INT)),
-				$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(self::getCurrentUid(), \PDO::PARAM_INT)),
-				$queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('menu_recently_updated'))
-			 )
-			 ->executeQuery()
-			 ->fetchAll();
-
-		return empty($result) ? FALSE : TRUE;
-	}
-
-
-	/**
-	 * Returns $mdtm
-	 *
-	 * @param int $setMaxResults
-	 * @return array $mdtm
-	 */
-	protected function getRecentlyUpdated($setMaxResults): array
-	{
-		$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
-		$sysLanguageUid = $languageAspect->getContentId() ?: 0;
-		$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
-		$result = $queryBuilder
-			 ->select('uid','pid','header', 'tstamp')
-			 ->from('tt_content')
-			 ->orderBy('tstamp', 'DESC')
-			 ->where(
-				$queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($sysLanguageUid, \PDO::PARAM_INT)),
-				$queryBuilder->expr()->neq('pid', $queryBuilder->createNamedParameter(self::getCurrentUid(), \PDO::PARAM_INT))
-			 )
-			 ->setMaxResults($setMaxResults)
-			 ->executeQuery()
-			 ->fetchAll();
-
-		$mdtm = [];
-
-		if (!empty($result)) {
-			foreach ( $result as $ce ) {
-				$pageTitle = self::getPageTitle($ce['pid']);
-				if ($pageTitle) {
-					$mdtm[$ce['uid']][$pageTitle] = $ce;
-				}
-			}
-		}
-
-		return $mdtm;
-	}
-
-
-	/**
-	 * Returns $pageTitle
-	 *
-	 * @param int $uid
-	 * @return string page title
-	 */
-	protected function getPageTitle($uid): string
-	{
-		$pageTitle = '';
-
-		if ($uid) {
-			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
-			$result = $queryBuilder
-				 ->select('uid', 'title', 'nav_title')
-				 ->from('pages')
-				 ->where(
-					$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)),
-					$queryBuilder->expr()->eq('doktype', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
-				 )
-				 ->executeQuery()
-				 ->fetch();
-
-				$pageTitle = !empty($result['nav_title']) ? $result['nav_title'] : '';
-		}
-
-		return (string)$pageTitle;
-	}
-
-
-	/**
-	 * Returns $id int
-	 *
-	 * @return int
-	 */
-	protected function getCurrentUid(): int
-	{
-		return (int) $GLOBALS['TSFE']->id;
-	}
-
-
+    /**
+     * Fetches records from the database as an array
+     *
+     * @param ContentObjectRenderer $cObj The content object renderer, which contains data of the content element
+     * @param array $contentObjectConfiguration The configuration of Content Object
+     * @param array $processorConfiguration The configuration of this processor
+     * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
+     *
+     * @return mixed processedData
+     */
+    public function process(ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData)
+    {
+        if (!empty($processorConfiguration['lastModifiedContentElement'])) {
+            $processorConfiguration = [];
+            $processorConfiguration['pidInList'] = self::getCurrentUid();
+            $records = $cObj->getRecords('tt_content', $processorConfiguration);
+
+            foreach ($records as $record) {
+                $lmc[] = $record['tstamp'];
+            }
+
+            if (!empty($lmc)) {
+                rsort($lmc, SORT_NUMERIC);
+            } else {
+                $lmc[0] = '';
+            }
+
+            $processedData['lastModifiedContentElement'] = $lmc[0];
+        }
+
+        if (!empty($processorConfiguration['recentlyUpdatedContentElements'])) {
+            $setMaxResults = !empty($processorConfiguration['setMaxResults']) ? $processorConfiguration['setMaxResults'] : 10;
+            if (self::isMenuRecentlyUpdatedOnPage()) {
+                $processedData['recentlyUpdatedContentElements'] = self::getRecentlyUpdated((int) $setMaxResults);
+            }
+        }
+
+        return $processedData;
+    }
+
+
+    /**
+     * Returns true if is page w/ content.cType == menu_recently_updated
+     *
+     * @return bool $mdtm
+     */
+    protected function isMenuRecentlyUpdatedOnPage(): bool
+    {
+        $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
+        $sysLanguageUid = $languageAspect->getContentId() ?: 0;
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+        $result = $queryBuilder
+             ->select('uid')
+             ->from('tt_content')
+             ->where(
+                 $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($sysLanguageUid, \PDO::PARAM_INT)),
+                 $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(self::getCurrentUid(), \PDO::PARAM_INT)),
+                 $queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('menu_recently_updated'))
+             )
+             ->executeQuery()
+             ->fetchAllAssociative();
+
+        return empty($result) ? false : true;
+    }
+
+
+    /**
+     * Returns $mdtm
+     *
+     * @param int $setMaxResults
+     * @return array $mdtm
+     */
+    protected function getRecentlyUpdated($setMaxResults): array
+    {
+        $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
+        $sysLanguageUid = $languageAspect->getContentId() ?: 0;
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+        $result = $queryBuilder
+             ->select('uid', 'pid', 'header', 'tstamp')
+             ->from('tt_content')
+             ->orderBy('tstamp', 'DESC')
+             ->where(
+                 $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($sysLanguageUid, \PDO::PARAM_INT)),
+                 $queryBuilder->expr()->neq('pid', $queryBuilder->createNamedParameter(self::getCurrentUid(), \PDO::PARAM_INT))
+             )
+             ->setMaxResults($setMaxResults)
+             ->executeQuery()
+             ->fetchAllAssociative();
+
+        $mdtm = [];
+
+        if (!empty($result)) {
+            foreach ($result as $ce) {
+                $pageTitle = self::getPageTitle($ce['pid']);
+                if ($pageTitle) {
+                    $mdtm[$ce['uid']][$pageTitle] = $ce;
+                }
+            }
+        }
+
+        return $mdtm;
+    }
+
+
+    /**
+     * Returns $pageTitle
+     *
+     * @param int $uid
+     * @return string page title
+     */
+    protected function getPageTitle($uid): string
+    {
+        $pageTitle = '';
+
+        if ($uid) {
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
+            $result = $queryBuilder
+                 ->select('uid', 'title', 'nav_title')
+                 ->from('pages')
+                 ->where(
+                     $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)),
+                     $queryBuilder->expr()->eq('doktype', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT))
+                 )
+                 ->executeQuery()
+                 ->fetch();
+
+            $pageTitle = !empty($result['nav_title']) ? $result['nav_title'] : '';
+        }
+
+        return (string)$pageTitle;
+    }
+
+
+    /**
+     * Returns $id int
+     *
+     * @return int
+     */
+    protected function getCurrentUid(): int
+    {
+        return (int) $GLOBALS['TSFE']->id;
+    }
 }
diff --git a/Classes/ExpressionLanguage/T3sbConditionFunctionsProvider.php b/Classes/ExpressionLanguage/T3sbConditionFunctionsProvider.php
index 9f1add02..0d92be5b 100644
--- a/Classes/ExpressionLanguage/T3sbConditionFunctionsProvider.php
+++ b/Classes/ExpressionLanguage/T3sbConditionFunctionsProvider.php
@@ -1,4 +1,5 @@
 getExtconf(),
-			$this->getBrowser(),
-			$this->getColPosList(),
-			$this->getExtensionLoaded(),
-		];
-	}
-
-	protected function getExtconf(): ExpressionFunction
-	{
-		return new ExpressionFunction('t3sbootstrap', function ($str) {
-			// Not implemented
-		}, function ($arguments, $str) {
-
-			$extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap');
-
-			return $extConf[$str];
-
-		});
-	}
-
-	protected function getBrowser(): ExpressionFunction
-	{
-	  return new ExpressionFunction('browser', function ($str) {
-		 // Not implemented
-	  }, function ($arguments, $str) {
-
-		$user_agent = GeneralUtility::getIndpEnv('HTTP_USER_AGENT');
-		$browser = 'Other';
-
-		if (strpos($user_agent, 'Opera') || strpos($user_agent, 'OPR/')) $browser = 'Opera';
-		elseif (strpos($user_agent, 'Edge')) $browser = 'Edge';
-		elseif (strpos($user_agent, 'Chrome')) $browser = 'Chrome';
-		elseif (strpos($user_agent, 'Safari')) $browser = 'Safari';
-		elseif (strpos($user_agent, 'Firefox')) $browser = 'Firefox';
-		elseif (strpos($user_agent, 'MSIE') || strpos($user_agent, 'Trident/7')) $browser = 'Internet Explorer';
-
-		return $str === $browser;
-	  });
-
-	}
-
-	protected function getColPosList(): ExpressionFunction
-	{
-		return new ExpressionFunction('colPosList', function ($str) {
-			// Not implemented
-		}, function ($arguments, $str) {
-
-			$result = FALSE;
-
-			if ( $_GET['id'] ?? 0 && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend() ) {
-
-				$pid = (int)$_GET['id'];
-				$configRepository = GeneralUtility::makeInstance(ConfigRepository::class);
-				$config = $configRepository->findOneByPid($pid);
-
-				if ( empty($config) ) {
-					$rootLineIdsArray = array_reverse($arguments['tree']->rootLineIds);
-					unset($rootLineIdsArray[count($rootLineIdsArray)-1]);
-					unset($rootLineIdsArray[0]);
-
-					foreach ($rootLineIdsArray as $id) {
-						$config = $configRepository->findOneByPid($id);
-						if ( !empty($config) ) break;
-					}
-				}
-
-				if ( !empty($config) ) {
-
-					if ( $config->getJumbotronEnable() ) {
-						if ( $config->getFooterEnable() ) {
-							// Content, Jumbotron & Footer
-							if ( $config->getExpandedcontentEnabletop() ) {
-								if ($str == 'AllandTop') {
-										 $result = TRUE;
-								}
-							}
-							if ( $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'AllandBottom') {
-										 $result = TRUE;
-								}
-							}
-							if ( $config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'AllandTopBottom') {
-										 $result = TRUE;
-								}
-							}
-							if ( !$config->getExpandedcontentEnabletop() && !$config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'All') {
-										 $result = TRUE;
-								}
-							}
-						} else {
-							// Content & Jumbotron
-							if ($str == 'Jumbotron') {
-									 $result = TRUE;
-							}
-							if ( $config->getExpandedcontentEnabletop() ) {
-								if ($str == 'JumbotronandTop') {
-										 $result = TRUE;
-								}
-							}
-							if ( $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'JumbotronandBottom') {
-										 $result = TRUE;
-								}
-							}
-							if ( $config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'JumbotronandTopBottom') {
-										 $result = TRUE;
-								}
-							}
-						}
-					} else {
-						if ( $config->getFooterEnable() ) {
-							// Content & Footer
-							if ($str == 'Footer') {
-									 $result = TRUE;
-							}
-							if ( $config->getExpandedcontentEnabletop() ) {
-								if ($str == 'FooterandTop') {
-										 $result = TRUE;
-								}
-							}
-							if ( $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'FooterandBottom') {
-										 $result = TRUE;
-								}
-							}
-
-							if ( $config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'FooterandTopBottom') {
-										 $result = TRUE;
-								}
-							}
-						} else {
-							// Content only (no Jumbotron & no Footer)
-							if ($str == 'Content') {
-									 $result = TRUE;
-							}
-							if ( $config->getExpandedcontentEnabletop() ) {
-								if ($str == 'ContentandTop') {
-										 $result = TRUE;
-								}
-							}
-							if ( $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'ContentandBottom') {
-										 $result = TRUE;
-								}
-							}
-							if ( $config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom() ) {
-								if ($str == 'ContentandTopBottom') {
-										 $result = TRUE;
-								}
-							}
-						}
-					}
-				}
-			}
-
-			return $result;
-
-		});
-	}
-
-	protected function getExtensionLoaded(): ExpressionFunction
-	{
-		return new ExpressionFunction('loaded', function () {
-			// Not implemented, we only use the evaluator
-		}, function ($arguments, $extKey) {
-
-			return ExtensionManagementUtility::isLoaded($extKey);
-		});
-	}
-
+class T3sbConditionFunctionsProvider implements ExpressionFunctionProviderInterface
+{
+    /**
+     * @return array
+     */
+    public function getFunctions(): array
+    {
+        return [
+            $this->getExtconf(),
+            $this->getBrowser(),
+            $this->getColPosList(),
+            $this->getExtensionLoaded(),
+        ];
+    }
+
+    protected function getExtconf(): ExpressionFunction
+    {
+        return new ExpressionFunction('t3sbootstrap', function ($str) {
+            // Not implemented
+        }, function ($arguments, $str) {
+            $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap');
+
+            return $extConf[$str];
+        });
+    }
+
+    protected function getBrowser(): ExpressionFunction
+    {
+        return new ExpressionFunction('browser', function ($str) {
+            // Not implemented
+        }, function ($arguments, $str) {
+            $user_agent = GeneralUtility::getIndpEnv('HTTP_USER_AGENT');
+            $browser = 'Other';
+
+            if (strpos($user_agent, 'Opera') || strpos($user_agent, 'OPR/')) {
+                $browser = 'Opera';
+            } elseif (strpos($user_agent, 'Edge')) {
+                $browser = 'Edge';
+            } elseif (strpos($user_agent, 'Chrome')) {
+                $browser = 'Chrome';
+            } elseif (strpos($user_agent, 'Safari')) {
+                $browser = 'Safari';
+            } elseif (strpos($user_agent, 'Firefox')) {
+                $browser = 'Firefox';
+            } elseif (strpos($user_agent, 'MSIE') || strpos($user_agent, 'Trident/7')) {
+                $browser = 'Internet Explorer';
+            }
+
+            return $str === $browser;
+        });
+    }
+
+    protected function getColPosList(): ExpressionFunction
+    {
+        return new ExpressionFunction('colPosList', function ($str) {
+            // Not implemented
+        }, function ($arguments, $str) {
+            $result = false;
+
+            if ($_GET['id'] ?? 0 && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend()) {
+                $pid = (int)$_GET['id'];
+                $configRepository = GeneralUtility::makeInstance(ConfigRepository::class);
+                $config = $configRepository->findOneByPid($pid);
+
+                if (empty($config)) {
+                    $rootLineIdsArray = array_reverse($arguments['tree']->rootLineIds);
+                    unset($rootLineIdsArray[count($rootLineIdsArray)-1]);
+                    unset($rootLineIdsArray[0]);
+
+                    foreach ($rootLineIdsArray as $id) {
+                        $config = $configRepository->findOneByPid($id);
+                        if (!empty($config)) {
+                            break;
+                        }
+                    }
+                }
+
+                if (!empty($config)) {
+                    if ($config->getJumbotronEnable()) {
+                        if ($config->getFooterEnable()) {
+                            // Content, Jumbotron & Footer
+                            if ($config->getExpandedcontentEnabletop()) {
+                                if ($str == 'AllandTop') {
+                                    $result = true;
+                                }
+                            }
+                            if ($config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'AllandBottom') {
+                                    $result = true;
+                                }
+                            }
+                            if ($config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'AllandTopBottom') {
+                                    $result = true;
+                                }
+                            }
+                            if (!$config->getExpandedcontentEnabletop() && !$config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'All') {
+                                    $result = true;
+                                }
+                            }
+                        } else {
+                            // Content & Jumbotron
+                            if ($str == 'Jumbotron') {
+                                $result = true;
+                            }
+                            if ($config->getExpandedcontentEnabletop()) {
+                                if ($str == 'JumbotronandTop') {
+                                    $result = true;
+                                }
+                            }
+                            if ($config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'JumbotronandBottom') {
+                                    $result = true;
+                                }
+                            }
+                            if ($config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'JumbotronandTopBottom') {
+                                    $result = true;
+                                }
+                            }
+                        }
+                    } else {
+                        if ($config->getFooterEnable()) {
+                            // Content & Footer
+                            if ($str == 'Footer') {
+                                $result = true;
+                            }
+                            if ($config->getExpandedcontentEnabletop()) {
+                                if ($str == 'FooterandTop') {
+                                    $result = true;
+                                }
+                            }
+                            if ($config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'FooterandBottom') {
+                                    $result = true;
+                                }
+                            }
+
+                            if ($config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'FooterandTopBottom') {
+                                    $result = true;
+                                }
+                            }
+                        } else {
+                            // Content only (no Jumbotron & no Footer)
+                            if ($str == 'Content') {
+                                $result = true;
+                            }
+                            if ($config->getExpandedcontentEnabletop()) {
+                                if ($str == 'ContentandTop') {
+                                    $result = true;
+                                }
+                            }
+                            if ($config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'ContentandBottom') {
+                                    $result = true;
+                                }
+                            }
+                            if ($config->getExpandedcontentEnabletop() && $config->getExpandedcontentEnablebottom()) {
+                                if ($str == 'ContentandTopBottom') {
+                                    $result = true;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            return $result;
+        });
+    }
+
+    protected function getExtensionLoaded(): ExpressionFunction
+    {
+        return new ExpressionFunction('loaded', function () {
+            // Not implemented, we only use the evaluator
+        }, function ($arguments, $extKey) {
+            return ExtensionManagementUtility::isLoaded($extKey);
+        });
+    }
 }
diff --git a/Classes/Helper/StyleHelper.php b/Classes/Helper/StyleHelper.php
index 8aa10349..5580dcf9 100644
--- a/Classes/Helper/StyleHelper.php
+++ b/Classes/Helper/StyleHelper.php
@@ -1,4 +1,5 @@
 > 0x10);
-			$rgbArray['green'] = 0xFF & ($colorVal >> 0x8);
-			$rgbArray['blue'] = 0xFF & $colorVal;
-		} elseif (strlen($hexStr) == 3) { //if shorthand notation, need some string manipulations
-			$rgbArray['red'] = hexdec(str_repeat(substr($hexStr, 0, 1), 2));
-			$rgbArray['green'] = hexdec(str_repeat(substr($hexStr, 1, 1), 2));
-			$rgbArray['blue'] = hexdec(str_repeat(substr($hexStr, 2, 1), 2));
-		} else {
-			return false; //Invalid hex color code
-		}
-		return implode($seperator, $rgbArray);
-	}
-
+    /**
+     * Returns background color
+     */
+    public function getBgColor(array $data, bool $hexdec=true): string
+    {
+        $color = '';
+
+
+        if ($data['tx_t3sbootstrap_bgcolor']
+         && !$data['tx_t3sbootstrap_contextcolor']) {
+            if ($data['tx_t3sbootstrap_bgopacity'] && $data['tx_t3sbootstrap_bgopacity'] != 1) {
+                // if opacity
+                $rgba = self::hex2RGB($data['tx_t3sbootstrap_bgcolor']).','.$data['tx_t3sbootstrap_bgopacity'];
+                $color = 'background-color: rgba('.$rgba.');';
+            } elseif ($hexdec) {
+                $color = 'background-color: '.$data['tx_t3sbootstrap_bgcolor'].';';
+            }
+        } elseif (!empty($data['tx_t3sbootstrap_contextcolor'])) {
+            if ($data['tx_t3sbootstrap_bgopacity'] < 1 && $data['tx_t3sbootstrap_bgopacity'] > 0) {
+                $color = '--bs-bg-opacity: '.$data['tx_t3sbootstrap_bgopacity'].';';
+            }
+        }
+
+        return $color;
+    }
+
+
+    /**
+    * Convert a hexa decimal color code to its RGB equivalent
+    */
+    public function hex2RGB(string $hexStr, string $seperator = ','): string
+    {
+        $hexStr = preg_replace("/[^0-9A-Fa-f]/", '', $hexStr); // Gets a proper hex string
+        $rgbArray = array();
+        if (strlen($hexStr) == 6) { //If a proper hex code, convert using bitwise operation. No overhead... faster
+            $colorVal = hexdec($hexStr);
+            $rgbArray['red'] = 0xFF & ($colorVal >> 0x10);
+            $rgbArray['green'] = 0xFF & ($colorVal >> 0x8);
+            $rgbArray['blue'] = 0xFF & $colorVal;
+        } elseif (strlen($hexStr) == 3) { //if shorthand notation, need some string manipulations
+            $rgbArray['red'] = hexdec(str_repeat(substr($hexStr, 0, 1), 2));
+            $rgbArray['green'] = hexdec(str_repeat(substr($hexStr, 1, 1), 2));
+            $rgbArray['blue'] = hexdec(str_repeat(substr($hexStr, 2, 1), 2));
+        } else {
+            return false; //Invalid hex color code
+        }
+        return implode($seperator, $rgbArray);
+    }
 }
diff --git a/Classes/Hooks/PageRenderer/PreProcessHook.php b/Classes/Hooks/PageRenderer/PreProcessHook.php
index 7db4f26a..5df30e73 100644
--- a/Classes/Hooks/PageRenderer/PreProcessHook.php
+++ b/Classes/Hooks/PageRenderer/PreProcessHook.php
@@ -18,47 +18,47 @@
  */
 class PreProcessHook
 {
-	/**
-	 * @var \T3SBS\T3sbootstrap\Service\CompileService
-	 */
-	protected $compileService;
+    /**
+     * @var \T3SBS\T3sbootstrap\Service\CompileService
+     */
+    protected $compileService;
 
-	/**
-	 * @param array $params
-	 * @param PageRenderer $pagerenderer
-	 */
-	public function execute(&$params, &$pagerenderer): void
-	{
-		if (!($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface ||
-			!ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()) {
-			return;
-		}
+    /**
+     * @param array $params
+     * @param PageRenderer $pagerenderer
+     */
+    public function execute(&$params, &$pagerenderer): void
+    {
+        if (!($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface ||
+            !ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()) {
+            return;
+        }
 
-		foreach (['cssLibs', 'cssFiles'] as $key) {
-			$files = [];
-			if (is_array($params[$key])) {
-				foreach ($params[$key] as $file => $settings) {
-					$compiledFile = $this->getCompileService()->getCompiledFile($file);
-					if ($compiledFile !== null) {
-						$settings['file'] = $compiledFile;
-						$files[$compiledFile] = $settings;
-					} else {
-						$files[$file] = $settings;
-					}
-				}
-				$params[$key] = $files;
-			}
-		}
-	}
+        foreach (['cssLibs', 'cssFiles'] as $key) {
+            $files = [];
+            if (is_array($params[$key])) {
+                foreach ($params[$key] as $file => $settings) {
+                    $compiledFile = $this->getCompileService()->getCompiledFile($file);
+                    if ($compiledFile !== null) {
+                        $settings['file'] = $compiledFile;
+                        $files[$compiledFile] = $settings;
+                    } else {
+                        $files[$file] = $settings;
+                    }
+                }
+                $params[$key] = $files;
+            }
+        }
+    }
 
-	/**
-	 * Get the compile service
-	 */
-	protected function getCompileService(): CompileService
-	{
-		if ($this->compileService === null) {
-			$this->compileService = GeneralUtility::makeInstance(CompileService::class);
-		}
-		return $this->compileService;
-	}
+    /**
+     * Get the compile service
+     */
+    protected function getCompileService(): CompileService
+    {
+        if ($this->compileService === null) {
+            $this->compileService = GeneralUtility::makeInstance(CompileService::class);
+        }
+        return $this->compileService;
+    }
 }
diff --git a/Classes/Layouts/TwoColumns.php b/Classes/Layouts/TwoColumns.php
index 40161d68..3d666b86 100644
--- a/Classes/Layouts/TwoColumns.php
+++ b/Classes/Layouts/TwoColumns.php
@@ -1,4 +1,5 @@
 getGutters($processedData, $flexconf);
+        $processedData = GeneralUtility::makeInstance(Grid::class)->getGrid($processedData, $flexconf);
 
-	/**
-	 * Returns the $processedData
-	 */
-	public function getProcessedData(array $processedData, array $flexconf, string $bgMediaQueries='2560,1920,1200,992,768,576'): array
-	{
-		$processedData = GeneralUtility::makeInstance(Gutters::class)->getGutters($processedData, $flexconf);
-		$processedData = GeneralUtility::makeInstance(Grid::class)->getGrid($processedData, $flexconf);
+        $isTiling = false;
+        $flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
+        $flexconf = $flexFormService->convertFlexFormContentToArray($processedData['data']['tx_t3sbootstrap_flexform']);
 
-		$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
-		foreach ($processedData as $key=>$data) {
-			if ($key == 'col_221' || $key == 'col_222') {
-				if (is_array($data) && !empty($data[0]['tx_t3sbootstrap_flexform'])) {
-					$flexconf = $flexFormService->convertFlexFormContentToArray($data[0]['tx_t3sbootstrap_flexform']);
-					if (!empty($flexconf['tiling']['enable'])) {
-						// cards with tiling enabled inside
-						$processedData['gutters'] = ' gx-0 gy-0';
-						break;
-					}
-				}	
-			}
-		}
+        foreach ($processedData as $key=>$data) {
+            if ($key == 'col_221' || $key == 'col_222') {
+                if (is_array($data) && !empty($data[0]['tx_t3sbootstrap_flexform'])) {
+                    $flexconfChild = $flexFormService->convertFlexFormContentToArray($data[0]['tx_t3sbootstrap_flexform']);
+                    if (!empty($flexconfChild['tiling']['enable']) && !empty($data[0]['assets'])) {
+                        // cards with tiling enabled inside
+                        $isTiling = true;
 
-		$processedData['style'] .= !empty($flexconf['colHeight']) ? ' min-height: '.$flexconf['colHeight'].'px;' : '';
-		$processedData['verticalAlign'] = !empty($flexconf['colHeight'])
-		 && !empty($flexconf['verticalAlign']) ? ' d-flex align-items-' . $flexconf['verticalAlign'] : '';
-		$processedData['bgimages'] = '';
-		$processedData['bgimagePosition'] = '';
-		if ( !empty($flexconf['bgimages']) ) {
-			$bgimages = GeneralUtility::makeInstance(BackgroundImageUtility::class)
-				->getBgImage($processedData['data']['uid'], 'tt_content', FALSE, FALSE,
-				 $flexconf, FALSE, $processedData['data']['uid'], $bgMediaQueries);
-			if ($bgimages) {
-				$processedData['bgimages'] = $bgimages;
-				$processedData['bgimagePosition'] = $flexconf['bgimagePosition'];
-				$processedData['class'] .= ' col-image';
-			}
-		}
-		$processedData['equalHeight'] = !empty($flexconf['equalHeight']) ? ' d-flex align-items-stretch' : '';
+                        $processedData['gutters'] = ' gx-0 gy-0';
+                        break;
+                    }
+                }
+            }
+        }
 
-		return $processedData;
-	}
+        if ($isTiling) {
+            $flexconf = $flexconfChild;
+            $processedData['style'] .= !empty($flexconf['colHeight']) ? ' min-height: '.$flexconf['colHeight'].'px;' : '';
+            $processedData['verticalAlign'] = !empty($flexconf['colHeight'])
+                 && !empty($flexconf['verticalAlign']) ? ' d-flex align-items-' . $flexconf['verticalAlign'] : '';
+            $processedData['bgimages'] = '';
+            $processedData['bgimagePosition'] = '';
+            if (!empty($flexconf['bgimages'])) {
+                $bgimages = GeneralUtility::makeInstance(BackgroundImageUtility::class)
+                ->getBgImage(
+                    $processedData['data']['uid'],
+                    'tt_content',
+                    false,
+                    false,
+                    $flexconf,
+                    false,
+                    $processedData['data']['uid'],
+                    $bgMediaQueries
+                );
+                if ($bgimages) {
+                    $processedData['bgimages'] = $bgimages;
+                    $processedData['bgimagePosition'] = $flexconf['bgimagePosition'];
+                    $processedData['class'] .= ' col-image';
+                }
+            }
+            $processedData['equalHeight'] = !empty($flexconf['equalHeight']) ? ' d-flex align-items-stretch' : '';
+        } else {
+            $processedData['style'] .= !empty($flexconf['colHeight']) ? ' min-height: '.$flexconf['colHeight'].'px;' : '';
+            $processedData['verticalAlign'] = !empty($flexconf['colHeight'])
+                 && !empty($flexconf['verticalAlign']) ? ' d-flex align-items-' . $flexconf['verticalAlign'] : '';
+            $processedData['bgimages'] = '';
+            $processedData['bgimagePosition'] = '';
+            if (!empty($flexconf['bgimages'])) {
+                $bgimages = GeneralUtility::makeInstance(BackgroundImageUtility::class)
+                ->getBgImage(
+                    $processedData['data']['uid'],
+                    'tt_content',
+                    false,
+                    false,
+                    $flexconf,
+                    false,
+                    $processedData['data']['uid'],
+                    $bgMediaQueries
+                );
+                if ($bgimages) {
+                    $processedData['bgimages'] = $bgimages;
+                    $processedData['bgimagePosition'] = $flexconf['bgimagePosition'];
+                    $processedData['class'] .= ' col-image';
+                }
+            }
+            $processedData['equalHeight'] = !empty($flexconf['equalHeight']) ? ' d-flex align-items-stretch' : '';
+        }
 
+        return $processedData;
+    }
 }
diff --git a/Classes/Parser/AbstractParser.php b/Classes/Parser/AbstractParser.php
index 464060e7..cd1cb16b 100644
--- a/Classes/Parser/AbstractParser.php
+++ b/Classes/Parser/AbstractParser.php
@@ -1,4 +1,5 @@
-addImportPath(Environment::getExtensionsPath());
 
-		// Make paths in url() statements relative to site root
-		$absoluteFilePath = dirname($absoluteFilename);
-		$relativeFilePath = PathUtility::getAbsoluteWebPath($absoluteFilePath);
-
-		$scss->registerFunction(
-			'url',
-			function ($args) use (
-				$scss,
-				$absoluteFilePath,
-				$relativeFilePath
-			) : string {
-				$marker = $args[0][1];
-				$args[0][1] = '';
-				$result = $scss->compileValue($args[0]);
-				if (substr_compare($result, 'data:', 0, 5, true) !== 0) {
-					if (is_file(PathUtility::getCanonicalPath($absoluteFilePath . '/' . $result))) {
-						$result = PathUtility::getCanonicalPath($relativeFilePath . '/' . $result);
-					}
-					$result = str_starts_with($result, '/') ? substr($result, 1) : $result;
-				}
-				return 'url(' . $marker . $result . $marker . ')';
-			}
-		);
+        // Make paths in url() statements relative to site root
+        $absoluteFilePath = dirname($absoluteFilename);
+        $relativeFilePath = PathUtility::getAbsoluteWebPath($absoluteFilePath);
+
+        $scss->registerFunction(
+            'url',
+            function ($args) use (
+                $scss,
+                $absoluteFilePath,
+                $relativeFilePath
+            ): string {
+                $marker = $args[0][1];
+                $args[0][1] = '';
+                $result = $scss->compileValue($args[0]);
+                if (substr_compare($result, 'data:', 0, 5, true) !== 0) {
+                    if (is_file(PathUtility::getCanonicalPath($absoluteFilePath . '/' . $result))) {
+                        $result = PathUtility::getCanonicalPath($relativeFilePath . '/' . $result);
+                    }
+                    $result = str_starts_with($result, '/') ? substr($result, 1) : $result;
+                }
+                return 'url(' . $marker . $result . $marker . ')';
+            }
+        );
 
         // Compile file
         $compilationResult = $scss->compileString('@import "' . $absoluteFilename . '"');
diff --git a/Classes/Service/CompileService.php b/Classes/Service/CompileService.php
index 79dca1e1..06b50c79 100644
--- a/Classes/Service/CompileService.php
+++ b/Classes/Service/CompileService.php
@@ -1,4 +1,5 @@
 tmpl->setup['plugin.']['tx_t3sbootstrap.']['settings.'] ?? [];
-
-		// Ensure cache directory exists
-		if (!file_exists(Environment::getPublicPath() . '/' . $this->tempDirectory)) {
-			GeneralUtility::mkdir_deep(Environment::getPublicPath() . '/' . $this->tempDirectory);
-		}
-
-		// Settings
-		$settings = [
-			'file' => [
-				'absolute' => $absoluteFile,
-				'relative' => $file,
-				'info' => pathinfo($absoluteFile)
-			],
-			'cache' => [
-				'tempDirectory' => $this->tempDirectory,
-				'tempDirectoryRelativeToRoot' => $this->tempDirectoryRelativeToRoot,
-			],
-			'options' => [
-				'override' => !empty($configuration['overrideParserVariables']) ? true: false,
-				'sourceMap' => !empty($configuration['cssSourceMapping']) ? true : false,
-				'compress' => true
-			],
-			'variables' => []
-		];
-
-		// Parser
-		if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3sbootstrap/css']['parser'])
-			&& is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3sbootstrap/css']['parser'])
-		) {
-			foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3sbootstrap/css']['parser'] as $className) {
-				$parser = GeneralUtility::makeInstance($className);
-				if ($parser instanceof ParserInterface
-					&& !empty($settings['file']['info']['extension'])
-					&& $parser->supports($settings['file']['info']['extension'])
-				) {
-					if (!empty($configuration['overrideParserVariables'])) {
-						$settings['variables'] = $this->getVariablesFromConstants($settings['file']['info']['extension']);
-					}
-					try {
-						return $parser->compile($file, $settings);
-					} catch (\Exception $e) {
-						$this->clearCompilerCaches();
-						throw $e;
-					}
-				}
-			}
-		}
-
-		return null;
-	}
-
-	protected function getVariablesFromConstants(string $extension): array
-	{
-		$constants = $this->getConstants();
-		$extension = strtolower($extension);
-		$variables = [];
-
-		// Fetch Google Font
-		$variables['google-webfont'] = 'sans-serif';
-		if (!empty($constants['page.theme.googleFont.enable'])
-			&& (bool) $constants['page.theme.googleFont.enable']
-			&& !empty($constants['page.theme.googleFont.font'])
-			&& $constants['page.theme.googleFont.font'] !== ''
-		) {
-			$variables['google-webfont'] = $constants['page.theme.googleFont.font'];
-		}
-
-		// Fetch settings
-		$prefix = 'plugin.t3sbootstrap.settings.' . $extension . '.';
-		foreach ($constants as $constant => $value) {
-			if (strpos($constant, $prefix) === 0) {
-				$variables[substr($constant, strlen($prefix))] = $value;
-			}
-		}
-
-		return $variables;
-	}
-
-	protected function getConstants(): array
-	{
-		if ($GLOBALS['TSFE']->tmpl->flatSetup === null
-		|| !is_array($GLOBALS['TSFE']->tmpl->flatSetup)
-		|| count($GLOBALS['TSFE']->tmpl->flatSetup) === 0) {
-			$GLOBALS['TSFE']->tmpl->generateConfig();
-		}
-		return $GLOBALS['TSFE']->tmpl->flatSetup;
-	}
-
-	/**
-	 * Clear all caches for the compiler.
-	 */
-	protected function clearCompilerCaches(): void
-	{
-		GeneralUtility::rmdir(Environment::getPublicPath() . '/' . $this->tempDirectory, true);
-	}
+    /**
+     * @var string
+     */
+    protected $tempDirectory = 'typo3temp/assets/t3sbootstrap/css/';
+
+    /**
+     * @var string
+     */
+    protected $tempDirectoryRelativeToRoot = '../../../../';
+
+    /**
+     * @throws \Exception
+     */
+    public function getCompiledFile(string $file): ?string
+    {
+        $absoluteFile = GeneralUtility::getFileAbsFileName($file);
+        $configuration = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_t3sbootstrap.']['settings.'] ?? [];
+
+        // Ensure cache directory exists
+        if (!file_exists(Environment::getPublicPath() . '/' . $this->tempDirectory)) {
+            GeneralUtility::mkdir_deep(Environment::getPublicPath() . '/' . $this->tempDirectory);
+        }
+
+        // Settings
+        $settings = [
+            'file' => [
+                'absolute' => $absoluteFile,
+                'relative' => $file,
+                'info' => pathinfo($absoluteFile)
+            ],
+            'cache' => [
+                'tempDirectory' => $this->tempDirectory,
+                'tempDirectoryRelativeToRoot' => $this->tempDirectoryRelativeToRoot,
+            ],
+            'options' => [
+                'override' => !empty($configuration['overrideParserVariables']) ? true : false,
+                'sourceMap' => !empty($configuration['cssSourceMapping']) ? true : false,
+                'compress' => true
+            ],
+            'variables' => []
+        ];
+
+        // Parser
+        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3sbootstrap/css']['parser'])
+            && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3sbootstrap/css']['parser'])
+        ) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3sbootstrap/css']['parser'] as $className) {
+                $parser = GeneralUtility::makeInstance($className);
+                if ($parser instanceof ParserInterface
+                    && !empty($settings['file']['info']['extension'])
+                    && $parser->supports($settings['file']['info']['extension'])
+                ) {
+                    if (!empty($configuration['overrideParserVariables'])) {
+                        $settings['variables'] = $this->getVariablesFromConstants($settings['file']['info']['extension']);
+                    }
+                    try {
+                        return $parser->compile($file, $settings);
+                    } catch (\Exception $e) {
+                        $this->clearCompilerCaches();
+                        throw $e;
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    protected function getVariablesFromConstants(string $extension): array
+    {
+        $constants = $this->getConstants();
+        $extension = strtolower($extension);
+        $variables = [];
+
+        // Fetch Google Font
+        $variables['google-webfont'] = 'sans-serif';
+        if (!empty($constants['page.theme.googleFont.enable'])
+            && (bool) $constants['page.theme.googleFont.enable']
+            && !empty($constants['page.theme.googleFont.font'])
+            && $constants['page.theme.googleFont.font'] !== ''
+        ) {
+            $variables['google-webfont'] = $constants['page.theme.googleFont.font'];
+        }
+
+        // Fetch settings
+        $prefix = 'plugin.t3sbootstrap.settings.' . $extension . '.';
+        foreach ($constants as $constant => $value) {
+            if (strpos($constant, $prefix) === 0) {
+                $variables[substr($constant, strlen($prefix))] = $value;
+            }
+        }
+
+        return $variables;
+    }
+
+    protected function getConstants(): array
+    {
+        if ($GLOBALS['TSFE']->tmpl->flatSetup === null
+        || !is_array($GLOBALS['TSFE']->tmpl->flatSetup)
+        || count($GLOBALS['TSFE']->tmpl->flatSetup) === 0) {
+            $GLOBALS['TSFE']->tmpl->generateConfig();
+        }
+        return $GLOBALS['TSFE']->tmpl->flatSetup;
+    }
+
+    /**
+     * Clear all caches for the compiler.
+     */
+    protected function clearCompilerCaches(): void
+    {
+        GeneralUtility::rmdir(Environment::getPublicPath() . '/' . $this->tempDirectory, true);
+    }
 }
diff --git a/Classes/Updates/BgOpacityUpgradeWizard.php b/Classes/Updates/BgOpacityUpgradeWizard.php
new file mode 100644
index 00000000..2bce3097
--- /dev/null
+++ b/Classes/Updates/BgOpacityUpgradeWizard.php
@@ -0,0 +1,123 @@
+getQueryBuilderForTable('tt_content');
+        $statements = $queryBuilder
+                 ->select('uid', 'tx_t3sbootstrap_bgopacity')
+                 ->from('tt_content')
+                 ->executeQuery()
+                 ->fetchAllAssociative();
+
+        $erg = '';
+        foreach ($statements as $key=>$statement) {
+            $recordId = (int)$statement['uid'];
+            if ($statement['tx_t3sbootstrap_bgopacity'] > '1' && $statement['tx_t3sbootstrap_bgopacity'] != '') {
+                $arrA[$key]['uid'] = $statement['uid'];
+                $arrA[$key]['tx_t3sbootstrap_bgopacity'] = $statement['tx_t3sbootstrap_bgopacity'] / 100;
+                $erg = $statement['tx_t3sbootstrap_bgopacity'] / 100;
+                $queryBuilder
+                        ->update('tt_content')
+                        ->where(
+                            $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($recordId, \PDO::PARAM_INT))
+                        )
+                     ->set('tx_t3sbootstrap_bgopacity', $erg)
+                     ->executeStatement();
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Is an update necessary?
+     *
+     * Is used to determine whether a wizard needs to be run.
+     * Check if data for migration exists.
+     *
+     * @return bool Whether an update is required (TRUE) or not (FALSE)
+     */
+    public function updateNecessary(): bool
+    {
+        $updateNeeded = false;
+        // Check if the database table even exists
+        if ($this->checkIfWizardIsRequired()) {
+            $updateNeeded = true;
+        }
+
+        return $updateNeeded;
+    }
+
+    /**
+     * Returns an array of class names of prerequisite classes
+     *
+     * This way a wizard can define dependencies like "database up-to-date" or
+     * "reference index updated"
+     *
+     * @return string[]
+     */
+    public function getPrerequisites(): array
+    {
+        return '';
+    }
+
+    /**
+     * Check if there are record within database table with an empty "compress" field.
+     *
+     * @return bool
+     * @throws \InvalidArgumentException
+     */
+    protected function checkIfWizardIsRequired(): bool
+    {
+        $required = false;
+        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
+        $queryBuilder = $connectionPool->getQueryBuilderForTable('tt_content');
+        $numberOfEntries = $queryBuilder
+             ->count('uid')
+             ->from('tt_content')
+             ->where(
+                 $queryBuilder->expr()->gt('tx_t3sbootstrap_bgopacity', '1')
+             )
+            ->executeQuery()
+            ->fetchOne();
+
+        if (!empty($numberOfEntries)) {
+            $required = true;
+        }
+
+        return $required;
+    }
+}
diff --git a/Classes/UserFunction/TcaMatcher.php b/Classes/UserFunction/TcaMatcher.php
index 1319e643..00ab4730 100644
--- a/Classes/UserFunction/TcaMatcher.php
+++ b/Classes/UserFunction/TcaMatcher.php
@@ -1,4 +1,5 @@
 getQueryBuilderForTable('tt_content');
-			$result = $queryBuilder
-				  ->select('*')
-				  ->from('tt_content')
-				  ->where(
-					 $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
-				  )
-				  ->executeQuery();
-			$parent_rec = $result->fetch();
-
-			if ( !empty($parent_rec['CType']) && $parent_rec['CType'] == 'autoLayout_row' ) {
-				$parent = true;
-			}
-		}
-
-		return $parent;
-	}
-
-	/**
-	 * buttonParent
-	 */
-	public function buttonParent(array $arguments): bool
-	{
-		$parent = true;
-		if ( !empty($arguments['record']['tx_container_parent'][0]) ) {
-			$uid = (int)$arguments['record']['tx_container_parent'][0];
-			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
-			$result = $queryBuilder
-				  ->select('*')
-				  ->from('tt_content')
-				  ->where(
-					 $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
-				  )
-				  ->executeQuery();
-			$parent_rec = $result->fetch();
-
-			if ( !empty($parent_rec['CType']) && $parent_rec['CType'] == 'button_group' ) {
-				$parent = false;
-			}
-		}
-
-		return $parent;
-	}
-
-	/**
-	 * buttonGroup
-	 */
-	public function buttonGroup(array $arguments): bool
-	{
-		$group = false;
-		if ( !empty($arguments['record']['tx_container_parent'][0]) ) {
-			$group = true;
-		}
-
-		return $group;
-	}
-
-	/**
-	 * cardWrapperParent
-	 */
-	public function cardWrapperParent(array $arguments): bool
-	{
-		$parent = true;
-		if ( !empty($arguments['record']['tx_container_parent'][0]) ) {
-			$uid = (int)$arguments['record']['tx_container_parent'][0];
-			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
-			$result = $queryBuilder
-				  ->select('*')
-				  ->from('tt_content')
-				  ->where(
-					 $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
-				  )
-				  ->executeQuery();
-			$parent_rec = $result->fetch();
-
-			if ( !empty($parent_rec['CType']) && $parent_rec['CType'] == 'card_wrapper' ) {
-				$parent = false;
-			}
-		}
-
-		return $parent;
-	}
-
-	/**
-	 * container_1 ($_EXTCONF['container'] in tt_content.php)
-	 */
-	public function container_1(array $arguments): bool
-	{
-		return true;
-	}
-
-	/**
-	 * container_0 ($_EXTCONF['container'] in tt_content.php)
-	 */
-	public function container_0(array $arguments): bool
-	{
-		return false;
-	}
-
-	/**
-	 * spacing_1 ($_EXTCONF['spacing'] in tt_content.php)
-	 */
-	public function spacing_1(array $arguments): bool
-	{
-		return true;
-	}
-
-	/**
-	 * ratio ($_EXTCONF['ratio'] in tt_content.php)
-	 */
-	public function ratio_0(array $arguments): bool
-	{
-		return false;
-	}
-
-
-	/**
-	 * ratio ($_EXTCONF['ratio'] in tt_content.php)
-	 */
-	public function ratio_1(array $arguments): bool
-	{
-		return true;
-	}
-
-
-	/**
-	 * spacing_0 ($_EXTCONF['spacing'] in tt_content.php)
-	 */
-	public function spacing_0(array $arguments): bool
-	{
-		return false;
-	}
-
-	/**
-	 * color_1 ($_EXTCONF['color'] in tt_content.php)
-	 */
-	public function color_1(array $arguments): bool
-	{
-		if (!empty($arguments['record']['CType']) && !empty($arguments['record']['CType'][0])) {
-			if ( $arguments['record']['CType'][0] == 'parallax_wrapper' ) {
-					return false;
-			} else {
-					return true;
-			}
-		} else {
-			return true;
-		}
-
-	}
-
-	/**
-	 * color_0 ($_EXTCONF['color'] in tt_content.php)
-	 */
-	public function color_0(array $arguments): bool
-	{
-		return false;
-	}
-
-	/**
-	 * is child of flex-container
-	 */
-	public function flexContainerParent(array $arguments): bool
-	{
-		$parent = false;
-
-		$flexformService = GeneralUtility::makeInstance(FlexFormService::class);
-
-		if ( !empty($arguments['record']['tx_container_parent'][0]) ) {
-			$uid = (int)$arguments['record']['tx_container_parent'][0];
-			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
-			$result = $queryBuilder
-				  ->select('*')
-				  ->from('tt_content')
-				  ->where(
-					 $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
-				  )
-				  ->executeQuery();
-			$parent_rec = $result->fetch();
-
-			if (!empty($parent_rec)) {
-				$parent_flexconf = $flexformService->convertFlexFormContentToArray($parent_rec['tx_t3sbootstrap_flexform']);
-
-				if ( !empty($parent_rec['CType']) && $parent_rec['CType'] == 'container' && $parent_flexconf['flexContainer'] ) {
-					$parent = true;
-				}
-			}
-		}
-
-		return $parent;
-	}
-
-	/**
-	 * isButton
-	 */
-	public function isButton(array $arguments): bool
-	{
-		$button = false;
-		$flexformService = GeneralUtility::makeInstance(FlexFormService::class);
-
-		if ( !empty($arguments['record']['tx_container_parent'][0]) ) {
-			$uid = (int)$arguments['record']['tx_container_parent'][0];
-			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
-			$result = $queryBuilder
-				  ->select('tx_t3sbootstrap_flexform')
-				  ->from('tt_content')
-				  ->where(
-					 $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
-				  )
-				  ->executeQuery();
-			$parent_rec = $result->fetchAll();
-			if (!empty($parent_rec)) {
-				$flexconf = $flexformService->convertFlexFormContentToArray($parent_rec[0]['tx_t3sbootstrap_flexform']);
-				if ($flexconf['appearance'] == 'button' ) {
-					$button = true;
-				}
-			}
-		}
-
-		return $button;
-	}
-
-	/**
-	 * isMenu
-	 */
-	public function isMenu(array $arguments): bool
-	{
-		$menu = false;
-		if (!empty($arguments['record']['CType']) && !empty($arguments['record']['CType'][0])) {
-			if ( substr($arguments['record']['CType'][0], 0, 4) == 'menu' ) {
-				$menu = true;
-			}
-		}
-
-		return $menu;
-	}
-
-	/**
-	 * animateCss
-	 */
-	public function animateCss(array $arguments): bool
-	{
-		$animateCss = false;
-		$extconf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap');
-		if ( $extconf['animateCss'] ) {
-			$animateCss = true;
-		}
-
-		return $animateCss;
-	}
-
-	/**
-	 * isYoutube
-	 */
-	public function isYoutube(array $arguments): bool
-	{
-		$youtube = false;
-
-		if (is_int($arguments['record']['uid'])) {
-
-			$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
-			$fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
-			$file = !empty($fileObjects[0]) ? $fileObjects[0] : FALSE;
-
-			if (!empty($file)) {
-				if ( $file->getType() === 4 && ( $file->getMimeType() === 'video/youtube' || $file->getExtension() === 'youtube' ) ) {
-					$youtube = true;
-				}
-			}
-		}
-
-		return $youtube;
-	}
-
-
-	/**
-	 * isVimeo
-	 */
-	public function isVimeo(array $arguments): bool
-	{
-		$vimeo = false;
-
-		if (is_int($arguments['record']['uid'])) {
-
-			$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
-			$fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
-			$file = !empty($fileObjects[0]) ? $fileObjects[0] : FALSE;
-
-			if (!empty($file)) {
-				if ( $file->getType() === 4 && ( $file->getMimeType() === 'video/vimeo' || $file->getExtension() === 'vimeo' ) ) {
-					$vimeo = true;
-				}
-			}
-		}
-
-		return $vimeo;
-	}
-
-	/**
-	 * isLocalVideo
-	 */
-	public function isLocalVideo(array $arguments): bool
-	{
-		$video = false;
-
-		if (is_int($arguments['record']['uid'])) {
-
-			$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
-			$fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
-			$file = !empty($fileObjects[0]) ? $fileObjects[0] : FALSE;
-
-			if (!empty($file)) {
-				if ( $file->getType() === 4 ) {
-					if ( ( $file->getMimeType() === 'video/youtube' || $file->getExtension() === 'youtube' )
-					 || $file->getMimeType() === 'video/vimeo' || $file->getExtension() === 'vimeo' ) {
-						$video = false;
-					} else {
-						$video = true;
-					}
-				}
-			}
-		}
-
-		return $video;
-	}
-
-	/**
-	 * isNoMedia
-	 */
-	public function isNoMedia(array $arguments): bool
-	{
-		$media = false;
-
-		if (is_int($arguments['record']['uid'])) {
-
-			$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
-			$fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
-			$file = !empty($fileObjects[0]) ? $fileObjects[0] : FALSE;
-
-			if (!$file) {
-				$media = true;
-			} else {
-				if ( $file->getProperties()['hidden'] ) {
-					$media = true;
-				}
-			}
-		}
-
-		return $media;
-	}
-
-	/**
-	 * isImage
-	 */
-	public function isImage(array $arguments): bool
-	{
-		$image = false;
-
-		if (is_int($arguments['record']['uid'])) {
-
-			$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
-			$fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
-			$file = !empty($fileObjects[0]) ? $fileObjects[0] : FALSE;
-			if ($file) {
-				if ( $file->getType() === 2 && !$file->getProperties()['hidden'] ) {
-					$image = true;
-				}
-			}
-		}
-
-		return $image;
-	}
-
-
-	/**
-	 * isDropdownMenu
-	 */
-	public function isDropdownMenu(array $arguments): bool
-	{
-		$level = false;
-		$pageRepository = GeneralUtility::makeInstance(PageRepository::class);
-		$parentPage = $pageRepository->getPage($arguments['record']['pid']);
-		if (!empty($parentPage['is_siteroot'])) {
-			$level = true;
-		}
-
-		return $level;
-	}
-
-	/**
-	 * toastContainerParent
-	 */
-	public function toastContainerParent($arguments): bool
-	{
-		$parent = true;
-		if ( !empty($arguments['record']['tx_container_parent'][0]) ) {
-			$uid = (int)$arguments['record']['tx_container_parent'][0];
-			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
-			$result = $queryBuilder
-				  ->select('*')
-				  ->from('tt_content')
-				  ->where(
-					 $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
-				  )
-				  ->executeQuery();
-			$parent_rec = $result->fetch();
-			if ( $parent_rec['CType'] == 'toast_container' ) {
-				$parent = false;
-			}
-		}
-
-		return $parent;
-	}
-
+    /**
+     * autoLayoutParent
+     */
+    public function autoLayoutParent(array $arguments): bool
+    {
+        $parent = false;
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $uid = (int)$arguments['record']['tx_container_parent'][0];
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+            $result = $queryBuilder
+                  ->select('*')
+                  ->from('tt_content')
+                  ->where(
+                      $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                  )
+                  ->executeQuery();
+            $parent_rec = $result->fetch();
+
+            if (!empty($parent_rec['CType']) && $parent_rec['CType'] == 'autoLayout_row') {
+                $parent = true;
+            }
+        }
+
+        return $parent;
+    }
+
+    /**
+     * buttonParent
+     */
+    public function buttonParent(array $arguments): bool
+    {
+        $parent = true;
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $uid = (int)$arguments['record']['tx_container_parent'][0];
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+            $result = $queryBuilder
+                  ->select('*')
+                  ->from('tt_content')
+                  ->where(
+                      $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                  )
+                  ->executeQuery();
+            $parent_rec = $result->fetch();
+
+            if (!empty($parent_rec['CType']) && $parent_rec['CType'] == 'button_group') {
+                $parent = false;
+            }
+        }
+
+        return $parent;
+    }
+
+    /**
+     * buttonGroup
+     */
+    public function buttonGroup(array $arguments): bool
+    {
+        $group = false;
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $group = true;
+        }
+
+        return $group;
+    }
+
+    /**
+     * cardWrapperParent
+     */
+    public function cardWrapperParent(array $arguments): bool
+    {
+        $parent = true;
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $uid = (int)$arguments['record']['tx_container_parent'][0];
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+            $result = $queryBuilder
+                  ->select('*')
+                  ->from('tt_content')
+                  ->where(
+                      $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                  )
+                  ->executeQuery();
+            $parent_rec = $result->fetch();
+
+            if (!empty($parent_rec['CType']) && $parent_rec['CType'] == 'card_wrapper') {
+                $parent = false;
+            }
+        }
+
+        return $parent;
+    }
+
+
+    /**
+     * twoColumnsrParent
+     */
+    public function twoColumnsParent(array $arguments): bool
+    {
+        $parent = false;
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $uid = (int)$arguments['record']['tx_container_parent'][0];
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+            $result = $queryBuilder
+                  ->select('*')
+                  ->from('tt_content')
+                  ->where(
+                      $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                  )
+                  ->executeQuery();
+            $parent_rec = $result->fetch();
+
+            if (!empty($parent_rec['CType']) && $parent_rec['CType'] == 'two_columns') {
+                $parent = true;
+            }
+        }
+
+        return $parent;
+    }
+
+
+    /**
+     * container_1 ($_EXTCONF['container'] in tt_content.php)
+     */
+    public function container_1(array $arguments): bool
+    {
+        return true;
+    }
+
+    /**
+     * container_0 ($_EXTCONF['container'] in tt_content.php)
+     */
+    public function container_0(array $arguments): bool
+    {
+        return false;
+    }
+
+    /**
+     * spacing_1 ($_EXTCONF['spacing'] in tt_content.php)
+     */
+    public function spacing_1(array $arguments): bool
+    {
+        return true;
+    }
+
+    /**
+     * ratio ($_EXTCONF['ratio'] in tt_content.php)
+     */
+    public function ratio_0(array $arguments): bool
+    {
+        return false;
+    }
+
+
+    /**
+     * ratio ($_EXTCONF['ratio'] in tt_content.php)
+     */
+    public function ratio_1(array $arguments): bool
+    {
+        return true;
+    }
+
+
+    /**
+     * spacing_0 ($_EXTCONF['spacing'] in tt_content.php)
+     */
+    public function spacing_0(array $arguments): bool
+    {
+        return false;
+    }
+
+    /**
+     * color_1 ($_EXTCONF['color'] in tt_content.php)
+     */
+    public function color_1(array $arguments): bool
+    {
+        if (!empty($arguments['record']['CType']) && !empty($arguments['record']['CType'][0])) {
+            if ($arguments['record']['CType'][0] == 'parallax_wrapper') {
+                return false;
+            } else {
+                return true;
+            }
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * color_0 ($_EXTCONF['color'] in tt_content.php)
+     */
+    public function color_0(array $arguments): bool
+    {
+        return false;
+    }
+
+    /**
+     * is child of flex-container
+     */
+    public function flexContainerParent(array $arguments): bool
+    {
+        $parent = false;
+
+        $flexformService = GeneralUtility::makeInstance(FlexFormService::class);
+
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $uid = (int)$arguments['record']['tx_container_parent'][0];
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+            $result = $queryBuilder
+                  ->select('*')
+                  ->from('tt_content')
+                  ->where(
+                      $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                  )
+                  ->executeQuery();
+            $parent_rec = $result->fetch();
+
+            if (!empty($parent_rec)) {
+                $parent_flexconf = $flexformService->convertFlexFormContentToArray($parent_rec['tx_t3sbootstrap_flexform']);
+
+                if (!empty($parent_rec['CType']) && $parent_rec['CType'] == 'container' && $parent_flexconf['flexContainer']) {
+                    $parent = true;
+                }
+            }
+        }
+
+        return $parent;
+    }
+
+    /**
+     * isButton
+     */
+    public function isButton(array $arguments): bool
+    {
+        $button = false;
+        $flexformService = GeneralUtility::makeInstance(FlexFormService::class);
+
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $uid = (int)$arguments['record']['tx_container_parent'][0];
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+            $result = $queryBuilder
+                  ->select('tx_t3sbootstrap_flexform')
+                  ->from('tt_content')
+                  ->where(
+                      $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                  )
+                  ->executeQuery();
+            $parent_rec = $result->fetchAllAssociative();
+            if (!empty($parent_rec)) {
+                $flexconf = $flexformService->convertFlexFormContentToArray($parent_rec[0]['tx_t3sbootstrap_flexform']);
+                if ($flexconf['appearance'] == 'button') {
+                    $button = true;
+                }
+            }
+        }
+
+        return $button;
+    }
+
+    /**
+     * isMenu
+     */
+    public function isMenu(array $arguments): bool
+    {
+        $menu = false;
+        if (!empty($arguments['record']['CType']) && !empty($arguments['record']['CType'][0])) {
+            if (substr($arguments['record']['CType'][0], 0, 4) == 'menu') {
+                $menu = true;
+            }
+        }
+
+        return $menu;
+    }
+
+    /**
+     * animateCss
+     */
+    public function animateCss(array $arguments): bool
+    {
+        $animateCss = false;
+        $extconf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap');
+        if ($extconf['animateCss']) {
+            $animateCss = true;
+        }
+
+        return $animateCss;
+    }
+
+    /**
+     * isYoutube
+     */
+    public function isYoutube(array $arguments): bool
+    {
+        $youtube = false;
+
+        if (is_int($arguments['record']['uid'])) {
+            $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+            $fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
+            $file = !empty($fileObjects[0]) ? $fileObjects[0] : false;
+
+            if (!empty($file)) {
+                if ($file->getType() === 4 && ($file->getMimeType() === 'video/youtube' || $file->getExtension() === 'youtube')) {
+                    $youtube = true;
+                }
+            }
+        }
+
+        return $youtube;
+    }
+
+
+    /**
+     * isVimeo
+     */
+    public function isVimeo(array $arguments): bool
+    {
+        $vimeo = false;
+
+        if (is_int($arguments['record']['uid'])) {
+            $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+            $fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
+            $file = !empty($fileObjects[0]) ? $fileObjects[0] : false;
+
+            if (!empty($file)) {
+                if ($file->getType() === 4 && ($file->getMimeType() === 'video/vimeo' || $file->getExtension() === 'vimeo')) {
+                    $vimeo = true;
+                }
+            }
+        }
+
+        return $vimeo;
+    }
+
+    /**
+     * isLocalVideo
+     */
+    public function isLocalVideo(array $arguments): bool
+    {
+        $video = false;
+
+        if (is_int($arguments['record']['uid'])) {
+            $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+            $fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
+            $file = !empty($fileObjects[0]) ? $fileObjects[0] : false;
+
+            if (!empty($file)) {
+                if ($file->getType() === 4) {
+                    if (($file->getMimeType() === 'video/youtube' || $file->getExtension() === 'youtube')
+                     || $file->getMimeType() === 'video/vimeo' || $file->getExtension() === 'vimeo') {
+                        $video = false;
+                    } else {
+                        $video = true;
+                    }
+                }
+            }
+        }
+
+        return $video;
+    }
+
+    /**
+     * isNoMedia
+     */
+    public function isNoMedia(array $arguments): bool
+    {
+        $media = false;
+
+        if (is_int($arguments['record']['uid'])) {
+            $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+            $fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
+            $file = !empty($fileObjects[0]) ? $fileObjects[0] : false;
+
+            if (!$file) {
+                $media = true;
+            } else {
+                if ($file->getProperties()['hidden']) {
+                    $media = true;
+                }
+            }
+        }
+
+        return $media;
+    }
+
+    /**
+     * isImage
+     */
+    public function isImage(array $arguments): bool
+    {
+        $image = false;
+
+        if (is_int($arguments['record']['uid'])) {
+            $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+            $fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $arguments['record']['uid']);
+            $file = !empty($fileObjects[0]) ? $fileObjects[0] : false;
+            if ($file) {
+                if ($file->getType() === 2 && !$file->getProperties()['hidden']) {
+                    $image = true;
+                }
+            }
+        }
+
+        return $image;
+    }
+
+
+    /**
+     * isDropdownMenu
+     */
+    public function isDropdownMenu(array $arguments): bool
+    {
+        $level = false;
+        $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
+        $parentPage = $pageRepository->getPage($arguments['record']['pid']);
+        if (!empty($parentPage['is_siteroot'])) {
+            $level = true;
+        }
+
+        return $level;
+    }
+
+    /**
+     * toastContainerParent
+     */
+    public function toastContainerParent($arguments): bool
+    {
+        $parent = true;
+        if (!empty($arguments['record']['tx_container_parent'][0])) {
+            $uid = (int)$arguments['record']['tx_container_parent'][0];
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
+            $result = $queryBuilder
+                  ->select('*')
+                  ->from('tt_content')
+                  ->where(
+                      $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
+                  )
+                  ->executeQuery();
+            $parent_rec = $result->fetch();
+            if ($parent_rec['CType'] == 'toast_container') {
+                $parent = false;
+            }
+        }
+
+        return $parent;
+    }
 }
diff --git a/Classes/Utility/BackgroundImageUtility.php b/Classes/Utility/BackgroundImageUtility.php
index 8b1b4c01..3c6ca52b 100644
--- a/Classes/Utility/BackgroundImageUtility.php
+++ b/Classes/Utility/BackgroundImageUtility.php
@@ -1,4 +1,5 @@
 imageService = $imageService;
-	}
-
-	/**
-	 * Writes a css file with the background images
-	 *
-	 * return mixed
-	 */
-	public function getBgImage(
-		int $uid,
-		string $table='tt_content',
-		bool $jumbotron=FALSE,
-		bool $bgColorOnly=FALSE,
-		array $flexconf=[],
-		bool $body=FALSE,
-		int $currentUid=0,
-		string $bgMediaQueries='2560,1920,1200,992,768,576'
-	)
-	{
-		$request = $GLOBALS['TYPO3_REQUEST'];
-		$frontendController = $request->getAttribute('frontend.controller');
-		if (!$frontendController) {
-			$frontendController = self::getFrontendController();
-		}
-		$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
-		$filesFromRepository = $fileRepository->findByRelation($table, 'assets', $uid);
-		if ( empty($filesFromRepository) ) {
-			$filesFromRepository = $fileRepository->findByRelation($table, 'media', $uid);
-		}
-
-		$css = '';
-		$webp = false;
-		if ( ExtensionManagementUtility::isLoaded('webp') ) {
-			$webp = true;
-		}
-		
-		if ( count($filesFromRepository) > 1 && $body == FALSE ) {
-			if ( !empty($flexconf['bgimagePosition']) && ( $flexconf['bgimagePosition'] == 1 || $flexconf['bgimagePosition'] == 2 ) ) {
-				// bg-images in two-columns
-				// in the case if two images available but only one is selected in the flexform
-				$file = $filesFromRepository[0];
-				$image = $this->imageService->getImage($file->getOriginalFile()->getUid(), $file->getOriginalFile(), 1);
-				$bgImages = $this->generateSrcsetImages($file, $image);
-				$imageUri_mobile = $webp ? $bgImages[576].'.webp' : $bgImages[576];
-				$css .= $this->generateCss('s'.$uid.'-'.$flexconf['bgimagePosition'], $file, $image, $webp, $flexconf, FALSE, $bgMediaQueries);
-
-			} else {
-				// slider in jumbotron or two bg-images in two-columns
-				if ($jumbotron === true){
-					$uid = $frontendController->id;
-				}
-				foreach($filesFromRepository as $fileKey=>$file) {
-					$fileKey = $fileKey+1;
-					$image[$fileKey] = $this->imageService->getImage((string)$file->getOriginalFile()->getUid(), $file->getOriginalFile(), true);
-					$bgImages[$fileKey] = $this->generateSrcsetImages($file, $image[$fileKey]);
-					$imageUri_mobile[$fileKey] = $webp ? $bgImages[$fileKey][576].'.webp' : $bgImages[$fileKey][576];
-					$css .= $this->generateCss('s'.$uid.'-'.$fileKey, $file, $image[$fileKey], $webp, $flexconf, FALSE, $bgMediaQueries);
-				}
-			}
-		} else {
-			// background-image
-			if (!empty($filesFromRepository) ) {
-				$file = $filesFromRepository[0];
-				$image = $this->imageService->getImage((string)$file->getOriginalFile()->getUid(), $file->getOriginalFile(), true);
-				$uid = $currentUid ?: $uid;
-				if ( !empty($flexconf['bgimagePosition']) ) {
-					$uid = $uid . '-' . $flexconf['bgimagePosition'];
-				}
-				if ($jumbotron) {
-					$css = $this->generateCss('s'.$uid, $file, $image, $webp, $flexconf, FALSE, $bgMediaQueries);
-				} elseif ($body) {
-					$css = $this->generateCss('page-'.$uid, $file, $image, $webp, $flexconf, TRUE, $bgMediaQueries);
-				} else {
-					if ( !empty($flexconf['enableAutoheight']) ) {
-						if ( $flexconf['addHeight'] ) {
-							$inline = '"'.$uid.'":"'.$flexconf['addHeight'].'",';
-							if($inline)
-							GeneralUtility::makeInstance(AssetCollector::class)
-								  ->addInlineJavaScript('addheight-'.$uid, $inline);
-						}
-						$css = $this->generateCss('bg-img-'.$uid, $file, $image, $webp, $flexconf, FALSE, $bgMediaQueries);
-					} else {
-						$css = $this->generateCss('s'.$uid, $file, $image, $webp, $flexconf, FALSE, $bgMediaQueries);
-					}
-				}
-				$bgImages = $this->generateSrcsetImages($file, $image);
-				$imageUri_mobile = $webp ? $bgImages[576].'.webp' : $bgImages[576];
-
-			} else {
-				$imageUri_mobile = '';
-				if ($bgColorOnly) {
-					if ( $flexconf['enableAutoheight'] ) {
-						if ( $flexconf['addHeight'] ) {
-							$inline = '"'.$uid.'":"'.$flexconf['addHeight'].'",';
-							if($inline)
-							GeneralUtility::makeInstance(AssetCollector::class)
-								  ->addInlineJavaScript('addheight-'.$uid, $inline);
-						}
-					}
-				}
-			}
-		}
-		if($css)
-		GeneralUtility::makeInstance(AssetCollector::class)
-			 ->addInlineStyleSheet('bgimgutility-'.$uid, $css,[],['priority' => true]);
-
-		return $imageUri_mobile;
-	}
-
-
-	/**
-	 * generate CSS
-	 */
-	private function generateCss(
-		string $uid,
-		FileReference $file,
-		File $image,
-		bool $webp,
-		array $flexconf=[],
-		bool $body=FALSE,
-		string $bgMediaQueries='2560,1920,1200,992,768,576'
-	): string
-	{
-		$imageRaster = !empty($flexconf['imageRaster']) ? 'url(/typo3conf/ext/t3sbootstrap/Resources/Public/Images/raster.png), ' : '';
-		$processingInstructions = ['crop' => $file instanceof FileReference ? $file->getReferenceProperty('crop') : null];
-		$cropVariantCollection = CropVariantCollection::create((string) $processingInstructions['crop']);
-
-		$css = '';
-		$mediaQueries = explode(',', $bgMediaQueries);
-		$minWidth = (int)$mediaQueries[0];
-
-		foreach ($mediaQueries as $querie) {
-			$querie = (int)$querie;
-			if ($querie == 576) {
-				$cropVariant = 'mobile';
-			} elseif ($querie == 768) {
-				$cropVariant = 'tablet';
-			} else {
-				$cropVariant = 'default';
-			}
-			$cropArea = $cropVariantCollection->getCropArea($cropVariant);
-
-			$processingInstructions = [
-				'width' => (int)$querie,
-				'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image),
-			];
-			$processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
-			$css .= '@media (max-width: '.$querie.'px) {';
-			if ($webp) {
-				if ($body) {
-					$css .= '#'.$uid.'.no-webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
-					$css .= '#'.$uid.'.webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
-				} else {
-					$css .= '.no-webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
-					$css .= '.webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
-				}
-			} else {
-				$css .= '#'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
-			}
-			$css .= '}';
-
-			if ( $minWidth == $querie) {
-				$minQuerie = $querie +1;
-				$css .= '@media (min-width: '.$minQuerie.'px) {';
-				if ($webp) {
-					if ($body) {
-						$css .= '#'.$uid.'.no-webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
-						$css .= '#'.$uid.'.webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
-					} else {
-						$css .= '.no-webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
-						$css .= '.webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
-					}
-				} else {
-					$css .= '#'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
-				}
-				$css .= '}';
-			}
-		}
-
-		return $css;
-	}
-
-
-	/**
-	 * generateSrcsetImages
-	 */
-	private function generateSrcsetImages( $file, $image ): array
-	{
-		$processingInstructions = ['crop' => $file instanceof FileReference ? $file->getReferenceProperty('crop') : null];
-		$cropVariantCollection = CropVariantCollection::create((string) $processingInstructions['crop']);
-		$cropVariant = 'mobile';
-		$cropArea = $cropVariantCollection->getCropArea($cropVariant);
-		$processingInstructions = [
-			'width' => 576,
-			'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image),
-		];
-		$processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
-		$bgImages[576] = $this->imageService->getImageUri($processedImage);
-
-		return $bgImages;
-	}
-
-
-	/**
-	 * Returns $typoScriptFrontendController TypoScriptFrontendController
-	 *
-	 * @return TypoScriptFrontendController
-	 */
-	protected function getFrontendController(): TypoScriptFrontendController
-	{
-		return $GLOBALS['TSFE'];
-	}
-
+    protected $imageService;
+
+    public function __construct(
+        ImageService $imageService
+    ) {
+        $this->imageService = $imageService;
+    }
+
+    /**
+     * Writes a css file with the background images
+     *
+     * return mixed
+     */
+    public function getBgImage(
+        int $uid,
+        string $table='tt_content',
+        bool $jumbotron=false,
+        bool $bgColorOnly=false,
+        array $flexconf=[],
+        bool $body=false,
+        int $currentUid=0,
+        string $bgMediaQueries='2560,1920,1200,992,768,576'
+    ) {
+        $request = $GLOBALS['TYPO3_REQUEST'];
+        $frontendController = $request->getAttribute('frontend.controller');
+        if (!$frontendController) {
+            $frontendController = self::getFrontendController();
+        }
+        $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+        $filesFromRepository = $fileRepository->findByRelation($table, 'assets', $uid);
+        if (empty($filesFromRepository)) {
+            $filesFromRepository = $fileRepository->findByRelation($table, 'media', $uid);
+        }
+
+        $css = '';
+        $webp = false;
+        if (ExtensionManagementUtility::isLoaded('webp')) {
+            $webp = true;
+        }
+
+        if (count($filesFromRepository) > 1 && $body == false) {
+            if (!empty($flexconf['bgimagePosition']) && ($flexconf['bgimagePosition'] == 1 || $flexconf['bgimagePosition'] == 2)) {
+                // bg-images in two-columns
+                // in the case if two images available but only one is selected in the flexform
+                $file = $filesFromRepository[0];
+                $image = $this->imageService->getImage($file->getOriginalFile()->getUid(), $file->getOriginalFile(), 1);
+                $bgImages = $this->generateSrcsetImages($file, $image);
+                $imageUri_mobile = $webp ? $bgImages[576].'.webp' : $bgImages[576];
+                $css .= $this->generateCss('s'.$uid.'-'.$flexconf['bgimagePosition'], $file, $image, $webp, $flexconf, false, $bgMediaQueries);
+            } else {
+                // slider in jumbotron or two bg-images in two-columns
+                if ($jumbotron === true) {
+                    $uid = $frontendController->id;
+                }
+                foreach ($filesFromRepository as $fileKey=>$file) {
+                    $fileKey = $fileKey+1;
+                    $image[$fileKey] = $this->imageService->getImage((string)$file->getOriginalFile()->getUid(), $file->getOriginalFile(), true);
+                    $bgImages[$fileKey] = $this->generateSrcsetImages($file, $image[$fileKey]);
+                    $imageUri_mobile[$fileKey] = $webp ? $bgImages[$fileKey][576].'.webp' : $bgImages[$fileKey][576];
+                    $css .= $this->generateCss('s'.$uid.'-'.$fileKey, $file, $image[$fileKey], $webp, $flexconf, false, $bgMediaQueries);
+                }
+            }
+        } else {
+            // background-image
+            if (!empty($filesFromRepository)) {
+                $file = $filesFromRepository[0];
+                $image = $this->imageService->getImage((string)$file->getOriginalFile()->getUid(), $file->getOriginalFile(), true);
+                $uid = $currentUid ?: $uid;
+                if (!empty($flexconf['bgimagePosition'])) {
+                    $uid = $uid . '-' . $flexconf['bgimagePosition'];
+                }
+                if ($jumbotron) {
+                    $css = $this->generateCss('s'.$uid, $file, $image, $webp, $flexconf, false, $bgMediaQueries);
+                } elseif ($body) {
+                    $css = $this->generateCss('page-'.$uid, $file, $image, $webp, $flexconf, true, $bgMediaQueries);
+                } else {
+                    if (!empty($flexconf['enableAutoheight'])) {
+                        if ($flexconf['addHeight']) {
+                            $inline = '"'.$uid.'":"'.$flexconf['addHeight'].'",';
+                            if ($inline) {
+                                GeneralUtility::makeInstance(AssetCollector::class)
+                                  ->addInlineJavaScript('addheight-'.$uid, $inline);
+                            }
+                        }
+                        $css = $this->generateCss('bg-img-'.$uid, $file, $image, $webp, $flexconf, false, $bgMediaQueries);
+                    } else {
+                        $css = $this->generateCss('s'.$uid, $file, $image, $webp, $flexconf, false, $bgMediaQueries);
+                    }
+                }
+                $bgImages = $this->generateSrcsetImages($file, $image);
+                $imageUri_mobile = $webp ? $bgImages[576].'.webp' : $bgImages[576];
+            } else {
+                $imageUri_mobile = '';
+                if ($bgColorOnly) {
+                    if ($flexconf['enableAutoheight']) {
+                        if ($flexconf['addHeight']) {
+                            $inline = '"'.$uid.'":"'.$flexconf['addHeight'].'",';
+                            if ($inline) {
+                                GeneralUtility::makeInstance(AssetCollector::class)
+                                  ->addInlineJavaScript('addheight-'.$uid, $inline);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if ($css) {
+            GeneralUtility::makeInstance(AssetCollector::class)
+             ->addInlineStyleSheet('bgimgutility-'.$uid, $css, [], ['priority' => true]);
+        }
+
+        return $imageUri_mobile;
+    }
+
+
+    /**
+     * generate CSS
+     */
+    private function generateCss(
+        string $uid,
+        FileReference $file,
+        File $image,
+        bool $webp,
+        array $flexconf=[],
+        bool $body=false,
+        string $bgMediaQueries='2560,1920,1200,992,768,576'
+    ): string {
+        $imageRaster = !empty($flexconf['imageRaster']) ? 'url(/typo3conf/ext/t3sbootstrap/Resources/Public/Images/raster.png), ' : '';
+        $processingInstructions = ['crop' => $file instanceof FileReference ? $file->getReferenceProperty('crop') : null];
+        $cropVariantCollection = CropVariantCollection::create((string) $processingInstructions['crop']);
+
+        $css = '';
+        $mediaQueries = explode(',', $bgMediaQueries);
+        $minWidth = (int)$mediaQueries[0];
+
+        foreach ($mediaQueries as $querie) {
+            $querie = (int)$querie;
+            if ($querie == 576) {
+                $cropVariant = 'mobile';
+            } elseif ($querie == 768) {
+                $cropVariant = 'tablet';
+            } else {
+                $cropVariant = 'default';
+            }
+            $cropArea = $cropVariantCollection->getCropArea($cropVariant);
+
+            $processingInstructions = [
+                'width' => (int)$querie,
+                'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image),
+            ];
+            $processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
+            $css .= '@media (max-width: '.$querie.'px) {';
+            if ($webp) {
+                if ($body) {
+                    $css .= '#'.$uid.'.no-webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
+                    $css .= '#'.$uid.'.webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
+                } else {
+                    $css .= '.no-webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
+                    $css .= '.webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
+                }
+            } else {
+                $css .= '#'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
+            }
+            $css .= '}';
+
+            if ($minWidth == $querie) {
+                $minQuerie = $querie +1;
+                $css .= '@media (min-width: '.$minQuerie.'px) {';
+                if ($webp) {
+                    if ($body) {
+                        $css .= '#'.$uid.'.no-webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
+                        $css .= '#'.$uid.'.webp {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
+                    } else {
+                        $css .= '.no-webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
+                        $css .= '.webp #'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'.webp") !important;}';
+                    }
+                } else {
+                    $css .= '#'.$uid.' {background-image:'.$imageRaster.' url("'.$this->imageService->getImageUri($processedImage).'") !important;}';
+                }
+                $css .= '}';
+            }
+        }
+
+        return $css;
+    }
+
+
+    /**
+     * generateSrcsetImages
+     */
+    private function generateSrcsetImages($file, $image): array
+    {
+        $processingInstructions = ['crop' => $file instanceof FileReference ? $file->getReferenceProperty('crop') : null];
+        $cropVariantCollection = CropVariantCollection::create((string) $processingInstructions['crop']);
+        $cropVariant = 'mobile';
+        $cropArea = $cropVariantCollection->getCropArea($cropVariant);
+        $processingInstructions = [
+            'width' => 576,
+            'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image),
+        ];
+        $processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
+        $bgImages[576] = $this->imageService->getImageUri($processedImage);
+
+        return $bgImages;
+    }
+
+
+    /**
+     * Returns $typoScriptFrontendController TypoScriptFrontendController
+     *
+     * @return TypoScriptFrontendController
+     */
+    protected function getFrontendController(): TypoScriptFrontendController
+    {
+        return $GLOBALS['TSFE'];
+    }
 }
diff --git a/Classes/ViewHelpers/IntvalViewHelper.php b/Classes/ViewHelpers/IntvalViewHelper.php
deleted file mode 100644
index 08d97c24..00000000
--- a/Classes/ViewHelpers/IntvalViewHelper.php
+++ /dev/null
@@ -1,34 +0,0 @@
-registerArgument('number', 'string', 'return integer', true);
-	}
-
-	public static function renderStatic(
-		array $arguments,
-		\Closure $renderChildrenClosure,
-		RenderingContextInterface $renderingContext
-	) {
-
-		return $arguments['number'] ? (int)$arguments['number'] : 0;
-	}
-}
diff --git a/Classes/ViewHelpers/MediaViewHelper.php b/Classes/ViewHelpers/MediaViewHelper.php
index 23f10560..7476603c 100644
--- a/Classes/ViewHelpers/MediaViewHelper.php
+++ b/Classes/ViewHelpers/MediaViewHelper.php
@@ -67,12 +67,8 @@ public function injectConfigurationManager(ConfigurationManager $configurationMa
 	 */
 	public function initializeArguments()
 	{
-/*#		parent::initializeArguments();
+#		parent::initializeArguments();
 
-Undeclared arguments passed to ViewHelper T3SBS\T3sbootstrap\ViewHelpers\MediaViewHelper: class, style. 
-Valid arguments are: file, additionalConfig, width, height, cropVariant, fileExtension, loading, decoding, srcset, sizes, breakpoints, imgtag, picturefill, lazyload, ratio, mobileNoRatio, shift, columns, placeholderSize, placeholderInline, ignoreFileExtensions
-*/
-# new
         $this->registerUniversalTagAttributes();
         $this->registerTagAttribute('alt', 'string', 'Specifies an alternate text for an image', false);
         $this->registerArgument('file', 'object', 'File', true);
diff --git a/Classes/ViewHelpers/TrimViewHelper.php b/Classes/ViewHelpers/TrimViewHelper.php
deleted file mode 100644
index cbc435a6..00000000
--- a/Classes/ViewHelpers/TrimViewHelper.php
+++ /dev/null
@@ -1,33 +0,0 @@
-registerArgument('string', 'string', 'return integer', true);
-	}
-
-	public static function renderStatic(
-		array $arguments,
-		\Closure $renderChildrenClosure,
-		RenderingContextInterface $renderingContext
-	) {
-
-		return $arguments['string'] ? trim($arguments['string']) : '';
-	}
-}
diff --git a/Classes/Wrapper/BackgroundWrapper.php b/Classes/Wrapper/BackgroundWrapper.php
index 240b4d21..5519debb 100644
--- a/Classes/Wrapper/BackgroundWrapper.php
+++ b/Classes/Wrapper/BackgroundWrapper.php
@@ -136,7 +136,6 @@ public function getProcessedData(array $processedData, array $flexconf, string $
 				$filter = !empty($flexconf['imgGrayscale']) ? ' grayscale('.$flexconf['imgGrayscale'].'%) ' : '';
 				$filter .= !empty($flexconf['imgSepia']) ? ' sepia('.$flexconf['imgSepia'].'%) ' : '';
 				$filter .= !empty($flexconf['imgOpacity']) && $flexconf['imgOpacity'] != 100 ? ' opacity('.$flexconf['imgOpacity'].'%) ' : '';
-
 				if ($filter)
 				$processedData['style'] .= 'filter: '.trim($filter).';';
 
diff --git a/Classes/Wrapper/ButtonGroup.php b/Classes/Wrapper/ButtonGroup.php
index 38a3ca2e..726623a2 100644
--- a/Classes/Wrapper/ButtonGroup.php
+++ b/Classes/Wrapper/ButtonGroup.php
@@ -1,4 +1,5 @@
 getQueryBuilderForTable('tt_content');
-		$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
-		$children = $queryBuilder
-			->select('*')
-			->from('tt_content')
-			->where(
-				$queryBuilder->expr()->eq('tx_container_parent', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT)),
-				$queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($processedData['data']['sys_language_uid'], \PDO::PARAM_INT))
-			)
-			->orderBy('sorting')
-			->executeQuery()
-			->fetchAll();
-
-		$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
-		$processedData['colclass'] = !empty($flexconf['colclass']) ? $flexconf['colclass'] : '';
-		$processedData['cropMaxCharacters'] = $flexconf['cropMaxCharacters'];
-
-		if (count($children)) {
+        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
+        $queryBuilder = $connectionPool->getQueryBuilderForTable('tt_content');
+        $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
+        $children = $queryBuilder
+            ->select('*')
+            ->from('tt_content')
+            ->where(
+                $queryBuilder->expr()->eq('tx_container_parent', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT)),
+                $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter($processedData['data']['sys_language_uid'], \PDO::PARAM_INT))
+            )
+            ->orderBy('sorting')
+            ->executeQuery()
+            ->fetchAllAssociative();
 
-			$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+        $flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
+        $processedData['colclass'] = !empty($flexconf['colclass']) ? $flexconf['colclass'] : '';
+        $processedData['cropMaxCharacters'] = $flexconf['cropMaxCharacters'];
 
-			// Flipper defaults
-			if ($flexconf['card_wrapper'] == 'flipper') {
-				switch ( count($children) ) {
-					 case 1:
-						$processedData['flipper']['class'] = 'col-xs-12 col-sm-12 col-md-12';
-						$processedData['flipper']['width'] = 1294;
-					break;
-					 case 2:
-						$processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-6';
-						$processedData['flipper']['width'] = 634;
-					break;
-					 case 3:
-						$processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-4';
-						$processedData['flipper']['width'] = 414;
-					break;
-					 case 4:
-						$processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-3';
-						$processedData['flipper']['width'] = 304;
-					break;
-					 case 6:
-						$processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-2';
-						$processedData['flipper']['width'] = 175;
-					break;
-					 default:
-						$processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-4';
-						$processedData['flipper']['width'] = 576;
-				}
-			}
+        if (count($children)) {
+            $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
 
-			foreach ( $children as $key=>$child ) {
-				$fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $child['uid']);
-				if (!empty($processedData['flipper']) && isset($processedData['flipper']['width'])) {
-					$flipperWidth = $processedData['flipper']['width'];
-				} else {
-					$flipperWidth = 0;
-				}
-				$children[$key]['imgwidth'] = !empty($child['imagewidth']) ? $child['imagewidth'] : $flipperWidth;
-				if (!empty($fileObjects)) {
-					if ($flexconf['card_wrapper'] == 'flipper'){
-						$children[$key]['hFa'] = $child['tx_t3sbootstrap_header_fontawesome']
-						 ? ' ' : '';
-						$children[$key]['file'] = $fileObjects;
-						$children[$key]['backheader'] = $child['tx_t3sbootstrap_cardheader'];
-						$children[$key]['header'] = $child['header'];
-					} else {
-						$children[$key]['file'] = $fileObjects[0];
-						$children[$key]['header'] = $child['header'];
-					}
-				}
-				$children[$key]['ratio'] = $child['tx_t3sbootstrap_image_ratio'] ?: '0';
-				$children[$key]['uid'] = $child['uid'];
-				$children[$key]['subheader'] = $child['subheader'];
-				$children[$key]['header_link'] = $child['header_link'];
-				$children[$key]['header_position'] = $child['header_position'] ? ' text-'.$child['header_position'] :'';
-				$children[$key]['tx_t3sbootstrap_header_display'] = $child['tx_t3sbootstrap_header_display'];
-				$children[$key]['tx_t3sbootstrap_header_class'] = $child['tx_t3sbootstrap_header_class'];
-				$children[$key]['tx_t3sbootstrap_header_fontawesome'] = $child['tx_t3sbootstrap_header_fontawesome'];
-				$children[$key]['celink'] = $child['tx_t3sbootstrap_header_celink'];
+            // Flipper defaults
+            if ($flexconf['card_wrapper'] == 'flipper') {
+                switch (count($children)) {
+                     case 1:
+                        $processedData['flipper']['class'] = 'col-xs-12 col-sm-12 col-md-12';
+                        $processedData['flipper']['width'] = 1294;
+                    break;
+                     case 2:
+                        $processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-6';
+                        $processedData['flipper']['width'] = 634;
+                    break;
+                     case 3:
+                        $processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-4';
+                        $processedData['flipper']['width'] = 414;
+                    break;
+                     case 4:
+                        $processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-3';
+                        $processedData['flipper']['width'] = 304;
+                    break;
+                     case 6:
+                        $processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-2';
+                        $processedData['flipper']['width'] = 175;
+                    break;
+                     default:
+                        $processedData['flipper']['class'] = 'col-xs-12 col-sm-6 col-md-4';
+                        $processedData['flipper']['width'] = 576;
+                }
+            }
 
-				$children[$key]['settings'] = $flexFormService->convertFlexFormContentToArray($child['tx_t3sbootstrap_flexform']);
-			}
-			$processedData['cards'] = $children;
+            foreach ($children as $key=>$child) {
+                $fileObjects = $fileRepository->findByRelation('tt_content', 'assets', $child['uid']);
+                if (!empty($processedData['flipper']) && isset($processedData['flipper']['width'])) {
+                    $flipperWidth = $processedData['flipper']['width'];
+                } else {
+                    $flipperWidth = 0;
+                }
+                $children[$key]['imgwidth'] = !empty($child['imagewidth']) ? $child['imagewidth'] : $flipperWidth;
+                if (!empty($fileObjects)) {
+                    if ($flexconf['card_wrapper'] == 'flipper') {
+                        $children[$key]['hFa'] = $child['tx_t3sbootstrap_header_fontawesome']
+                         ? ' ' : '';
+                        $children[$key]['file'] = $fileObjects;
+                        $children[$key]['backheader'] = $child['tx_t3sbootstrap_cardheader'];
+                        $children[$key]['header'] = $child['header'];
+                    } else {
+                        $children[$key]['file'] = $fileObjects[0];
+                        $children[$key]['header'] = $child['header'];
+                    }
+                }
+                $children[$key]['ratio'] = $child['tx_t3sbootstrap_image_ratio'] ?: '0';
+                $children[$key]['uid'] = $child['uid'];
+                $children[$key]['subheader'] = $child['subheader'];
+                $children[$key]['header_link'] = $child['header_link'];
+                $children[$key]['header_position'] = $child['header_position'] ? ' text-'.$child['header_position'] : '';
+                $children[$key]['tx_t3sbootstrap_header_display'] = $child['tx_t3sbootstrap_header_display'];
+                $children[$key]['tx_t3sbootstrap_header_class'] = $child['tx_t3sbootstrap_header_class'];
+                $children[$key]['tx_t3sbootstrap_header_fontawesome'] = $child['tx_t3sbootstrap_header_fontawesome'];
+                $children[$key]['celink'] = $child['tx_t3sbootstrap_header_celink'];
+                $children[$key]['settings'] = $flexFormService->convertFlexFormContentToArray($child['tx_t3sbootstrap_flexform']);
+            }
+            $processedData['cards'] = $children;
 
-			// swiperjs
-			if ($flexconf['card_wrapper'] == 'slider') {
-				$processedData['visibleCards'] = !empty($flexconf['visibleCards']) ? (int)$flexconf['visibleCards'] : 3;
-				$processedData['cols'] = floor(12 / $processedData['visibleCards']);
-				$processedData['width'] = $flexconf['width'];
-				$processedData['ratio'] = $flexconf['ratio'];
-				$processedData['slidesPerView'] = (int)$flexconf['slidesPerView'] ?: 0;
-				$processedData['breakpoints10'] = !empty($flexconf['breakpoints10']) ? (int)$flexconf['breakpoints10'] : 1;
-				$processedData['breakpoints576'] = (int)$flexconf['breakpoints576'] ?: 2;
-				$processedData['breakpoints768'] = (int)$flexconf['breakpoints768'] ?: 3;
-				$processedData['breakpoints992'] = (int)$flexconf['breakpoints992'] ?: 4;
-				$processedData['slidesPerGroup'] = (int)$flexconf['slidesPerGroup'] ?: 1;
-				$processedData['spaceBetween'] = (int)$flexconf['spaceBetween'];
-				$processedData['loop'] = (int)$flexconf['loop'];
-				$processedData['navigation'] = (int)$flexconf['navigation'];
-				$processedData['pagination'] = (int)$flexconf['pagination'];
-				$processedData['autoplay'] = (int)$flexconf['autoplay'];
-				$processedData['delay'] = $flexconf['autoplay'] ? (int)$flexconf['delay'] : 99999999;
-			}
-            		$processedData['visibleCards'] = !empty($flexconf['visibleCards']) ? (int)$flexconf['visibleCards'] : 3;
-		}
+            // swiperjs
+            if ($flexconf['card_wrapper'] == 'slider') {
+                $processedData['visibleCards'] = !empty($flexconf['visibleCards']) ? (int)$flexconf['visibleCards'] : 3;
+                $processedData['cols'] = floor(12 / $processedData['visibleCards']);
+                $processedData['width'] = $flexconf['width'];
+                $processedData['ratio'] = $flexconf['ratio'];
+                $processedData['slidesPerView'] = (int)$flexconf['slidesPerView'] ?: 0;
+                $processedData['breakpoints10'] = !empty($flexconf['breakpoints10']) ? (int)$flexconf['breakpoints10'] : 1;
+                $processedData['breakpoints576'] = (int)$flexconf['breakpoints576'] ?: 2;
+                $processedData['breakpoints768'] = (int)$flexconf['breakpoints768'] ?: 3;
+                $processedData['breakpoints992'] = (int)$flexconf['breakpoints992'] ?: 4;
+                $processedData['slidesPerGroup'] = (int)$flexconf['slidesPerGroup'] ?: 1;
+                $processedData['spaceBetween'] = (int)$flexconf['spaceBetween'];
+                $processedData['loop'] = (int)$flexconf['loop'];
+                $processedData['navigation'] = (int)$flexconf['navigation'];
+                $processedData['pagination'] = (int)$flexconf['pagination'];
+                $processedData['autoplay'] = (int)$flexconf['autoplay'];
+                $processedData['delay'] = $flexconf['autoplay'] ? (int)$flexconf['delay'] : 99999999;
+            }
 
-		$processedData['card_wrapper_layout'] = $flexconf['card_wrapper'] ?: '';
+            $processedData['visibleCards'] = !empty($flexconf['visibleCards']) ? (int)$flexconf['visibleCards'] : 3;
+        }
 
-		return $processedData;
-	}
+        $processedData['card_wrapper_layout'] = $flexconf['card_wrapper'] ?: '';
 
+        return $processedData;
+    }
 }
diff --git a/Classes/Wrapper/CarouselContainer.php b/Classes/Wrapper/CarouselContainer.php
index 0fe81e75..e2612357 100644
--- a/Classes/Wrapper/CarouselContainer.php
+++ b/Classes/Wrapper/CarouselContainer.php
@@ -1,4 +1,5 @@
 getQueryBuilderForTable('tt_content');
-		$statement = $queryBuilder
-			->select('uid')
-			->from('tt_content')
-			->where(
-				$queryBuilder->expr()->eq('tx_container_parent', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT))
-			)
-			->executeQuery()
-			->fetchAll();
-
-		$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
-		$carouselSlides = [];
-		foreach($statement as $element) {
-			$file = $fileRepository->findByRelation('tt_content', 'assets', $element['uid']);
-			if ( !empty($file) ) {
-				if ($file[0]->getMimeType() == 'video/mp4' || $file[0]->getMimeType() == 'video/webm' || $file[0]->getMimeType() == 'video/wav'
-				 || $file[0]->getMimeType() == 'video/ogg' || $file[0]->getMimeType() == 'video/flac' || $file[0]->getMimeType() == 'video/opus') {
-					$processedData['containsVideo'] = TRUE;
-				}
-			}
-			if (!empty($file[0])) {
-				$carouselSlides[$element['uid']] = $file[0];
-			} else {
-				$carouselSlides[$element['uid']] = '';				
-			}
-		}
+        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
+        $queryBuilder = $connectionPool->getQueryBuilderForTable('tt_content');
+        $statement = $queryBuilder
+            ->select('uid')
+            ->from('tt_content')
+            ->where(
+                $queryBuilder->expr()->eq('tx_container_parent', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT))
+            )
+            ->executeQuery()
+            ->fetchAllAssociative();
 
-		$processedData['carouselSlides'] = !empty($carouselSlides) ? $carouselSlides : '';
+        $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+        $carouselSlides = [];
+        foreach ($statement as $element) {
+            $file = $fileRepository->findByRelation('tt_content', 'assets', $element['uid']);
+            if (!empty($file)) {
+                if ($file[0]->getMimeType() == 'video/mp4' || $file[0]->getMimeType() == 'video/webm' || $file[0]->getMimeType() == 'video/wav'
+                 || $file[0]->getMimeType() == 'video/ogg' || $file[0]->getMimeType() == 'video/flac' || $file[0]->getMimeType() == 'video/opus') {
+                    $processedData['containsVideo'] = true;
+                }
+            }
+            if (!empty($file[0])) {
+                $carouselSlides[$element['uid']] = $file[0];
+            } else {
+                $carouselSlides[$element['uid']] = '';
+            }
+        }
 
-		return $processedData;
-	}
+        $processedData['carouselSlides'] = !empty($carouselSlides) ? $carouselSlides : '';
 
+        return $processedData;
+    }
 }
diff --git a/Classes/Wrapper/CollapsibleContainer.php b/Classes/Wrapper/CollapsibleContainer.php
index 4124ff5c..27a65684 100644
--- a/Classes/Wrapper/CollapsibleContainer.php
+++ b/Classes/Wrapper/CollapsibleContainer.php
@@ -1,4 +1,5 @@
 getQueryBuilderForTable('tt_content');
+        $statements = $queryBuilder
+            ->select('tx_t3sbootstrap_flexform', 'tx_t3sbootstrap_header_fontawesome', 'tx_t3sbootstrap_header_class')
+            ->from('tt_content')
+            ->where(
+                $queryBuilder->expr()->eq('tx_container_parent', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT))
+            )
+            ->executeQuery()
+            ->fetchAllAssociative();
 
-	/**
-	 * Returns the $processedData
-	 */
-	public function getProcessedData(array $processedData, array $flexconf): array
-	{
-		$processedData['appearance'] = $flexconf['appearance'];
-		if ($flexconf['appearance'] == 'accordion') {
-			$processedData['flush'] = !empty($flexconf['flush']) ? ' accordion-flush' : '';
-		}
-		$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
-		$queryBuilder = $connectionPool->getQueryBuilderForTable('tt_content');
-		$statements = $queryBuilder
-			->select('tx_t3sbootstrap_flexform', 'tx_t3sbootstrap_header_fontawesome', 'tx_t3sbootstrap_header_class')
-			->from('tt_content')
-			->where(
-				$queryBuilder->expr()->eq('tx_container_parent', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT))
-			)
-			->executeQuery()
-			->fetchAll();
-
-		$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
-		$flexformArr = [];
-		$headerExtraClassArr = [];
-		$headerFontawesomeArr = [];
-		foreach ($statements as $key=>$statement) {
-			$flexformArr[$key] = $flexFormService->convertFlexFormContentToArray($statement['tx_t3sbootstrap_flexform']);
-			$headerExtraClassArr[$key] = !empty($statement['tx_t3sbootstrap_header_class']) ? $statement['tx_t3sbootstrap_header_class'] : '';
-			$headerFontawesomeArr[$key] = !empty($statement['tx_t3sbootstrap_header_fontawesome'])
-			 ? ' ' : '';
-		}
-		$processedData['flexformArr'] = $flexformArr;
-		$processedData['headerExtraClassArr'] = $headerExtraClassArr;
-		$processedData['headerFontawesomeArr'] = $headerFontawesomeArr;
-
-		return $processedData;
-	}
+        $flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
+        $flexformArr = [];
+        $headerExtraClassArr = [];
+        $headerFontawesomeArr = [];
+        foreach ($statements as $key=>$statement) {
+            $flexformArr[$key] = $flexFormService->convertFlexFormContentToArray($statement['tx_t3sbootstrap_flexform']);
+            $headerExtraClassArr[$key] = !empty($statement['tx_t3sbootstrap_header_class']) ? $statement['tx_t3sbootstrap_header_class'] : '';
+            $headerFontawesomeArr[$key] = !empty($statement['tx_t3sbootstrap_header_fontawesome'])
+             ? ' ' : '';
+        }
+        $processedData['flexformArr'] = $flexformArr;
+        $processedData['headerExtraClassArr'] = $headerExtraClassArr;
+        $processedData['headerFontawesomeArr'] = $headerFontawesomeArr;
 
+        return $processedData;
+    }
 }
diff --git a/Classes/Wrapper/SwiperContainer.php b/Classes/Wrapper/SwiperContainer.php
index fcbbcde0..36599079 100644
--- a/Classes/Wrapper/SwiperContainer.php
+++ b/Classes/Wrapper/SwiperContainer.php
@@ -25,13 +25,13 @@ public function getProcessedData(array $processedData, array $flexconf): array
         $filesFromRepository = [];
 
         $processedData['swiperCss'] = !empty($flexconf['swiperCss']) ? $flexconf['swiperCss'] : '';
-        $processedData['swiperJs'] = $flexconf['swiperJs'] ?? '';
-        $processedData['customSwiperJs'] = $flexconf['customSwiperJs'] ?? '';
-        $processedData['useCustomSwiperJs'] = $flexconf['useCustomSwiperJs'] ?? false;
+        $processedData['swiperJs'] = !empty($flexconf['swiperJs']) ? $flexconf['swiperJs'] : '';
+        $processedData['customSwiperJs'] = !empty($flexconf['customSwiperJs']) ? $flexconf['customSwiperJs'] : '';
+        $processedData['useCustomSwiperJs'] = !empty($flexconf['useCustomSwiperJs']) ? $flexconf['useCustomSwiperJs'] : false;
         $processedData['sliderStyle'] = $flexconf['sliderStyle'];
         $processedData['width'] = $flexconf['width'];
         $processedData['ratio'] = $flexconf['ratio'];
-        $processedData['slidesPerView'] = (int)$flexconf['slidesPerView'] ?: 0;
+        $processedData['slidesPerView'] = !empty($flexconf['slidesPerView']) ? (int)$flexconf['slidesPerView'] : 0;
         $processedData['breakpoints10'] = !empty($flexconf['breakpoints10']) ? (int)$flexconf['breakpoints10'] : 1;
         $processedData['breakpoints576'] = (int)$flexconf['breakpoints576'] ?: 2;
         $processedData['breakpoints768'] = (int)$flexconf['breakpoints768'] ?: 3;
@@ -43,8 +43,11 @@ public function getProcessedData(array $processedData, array $flexconf): array
         $processedData['navigation'] = (int)$flexconf['navigation'];
         $processedData['pagination'] = (int)$flexconf['pagination'];
         $processedData['autoplay'] = (int)$flexconf['autoplay'];
-        $processedData['delay'] = !empty($flexconf['autoplay']) ? (int)$flexconf['delay'] : 99999999;
         $processedData['origImage'] = !empty($flexconf['origImage']) ? $flexconf['origImage'] : '';
+        $processedData['delay'] = 0;
+        if (!empty($flexconf['delay'])) {
+            $processedData['delay'] = !empty($flexconf['autoplay']) ? (int)$flexconf['delay'] : 99999999;
+        }
 
         $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
         $queryBuilder = $connectionPool->getQueryBuilderForTable('tt_content');
@@ -55,7 +58,7 @@ public function getProcessedData(array $processedData, array $flexconf): array
                 $queryBuilder->expr()->eq('tx_container_parent', $queryBuilder->createNamedParameter($processedData['data']['uid'], \PDO::PARAM_INT))
             )
             ->executeQuery()
-            ->fetchAll();
+            ->fetchAllAssociative();
 
         $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
         foreach ($statement as $element) {
diff --git a/Configuration/FlexForms/CardSetting.xml b/Configuration/FlexForms/CardSetting.xml
index 68be8ba5..431e8c7a 100644
--- a/Configuration/FlexForms/CardSetting.xml
+++ b/Configuration/FlexForms/CardSetting.xml
@@ -8,6 +8,7 @@
 					
 						
 						FIELD:sDEF.tiling.enable:=:0
+						reload
 						
 							select
 							selectSingle
@@ -24,6 +25,64 @@
 							0
 						
 					
+
+					
+						
+						
+							
+								FIELD:sDEF.tiling.enable:=:0
+								FIELD:sDEF.effect:=:one
+							
+						
+						
+							select
+							selectSingle
+							
+								
+									LLL:EXT:t3sbootstrap/Resources/Private/Language/locallang_be.xlf:secondary
+									secondary
+								
+								
+									LLL:EXT:t3sbootstrap/Resources/Private/Language/locallang_be.xlf:primary
+									primary
+								
+								
+									LLL:EXT:t3sbootstrap/Resources/Private/Language/locallang_be.xlf:success
+									success
+								
+								
+									LLL:EXT:t3sbootstrap/Resources/Private/Language/locallang_be.xlf:info
+									info
+								
+								
+									LLL:EXT:t3sbootstrap/Resources/Private/Language/locallang_be.xlf:warning
+									warning
+								
+								
+									LLL:EXT:t3sbootstrap/Resources/Private/Language/locallang_be.xlf:danger
+									danger
+								
+								
+									light
+									light
+								
+								
+									dark
+									dark
+								
+								
+									white
+									white
+								
+								
+									none
+									0
+								
+							
+							primary
+						
+					
+
 					
 						
 						
@@ -269,11 +328,14 @@
 					
 						
 						Best in 2 columns with the following setting "col-lg-6 col-md-12 col-12"
+						USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->twoColumnsParent
 						reload
 						
 							check
+							0	
 						
 					
+
 					
 						
 						FIELD:sDEF.tiling.enable:=:1
diff --git a/Configuration/JavaScriptModules.php b/Configuration/JavaScriptModules.php
deleted file mode 100644
index c00aa99c..00000000
--- a/Configuration/JavaScriptModules.php
+++ /dev/null
@@ -1,11 +0,0 @@
- ['backend'],
-#    'tags' => [
-#        'backend.form',
-#    ],
-#    'imports' => [
-#        '@t3sbs/t3sbootstrap/timestamp-plugin.js' => 'EXT:t3sbootstrap/Resources/Public/JavaScript/Ckeditor/timestamp-plugin.js',
-#    ],
-];
diff --git a/Configuration/RTE/Codesnippet.yaml b/Configuration/RTE/Codesnippet.yaml
deleted file mode 100644
index d2af1c17..00000000
--- a/Configuration/RTE/Codesnippet.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-imports:
-    - { resource: "EXT:t3sbootstrap/Configuration/RTE/Default.yaml" }
-
-editor:
-    
-      config:
-        extraPlugins:
-          - codesnippet
diff --git a/Configuration/RTE/Default.yaml b/Configuration/RTE/Default.yaml
index 6a9ada0c..9eedb9ca 100644
--- a/Configuration/RTE/Default.yaml
+++ b/Configuration/RTE/Default.yaml
@@ -4,22 +4,15 @@ imports:
     - { resource: 'EXT:rte_ckeditor/Configuration/RTE/Editor/Base.yaml' }
     - { resource: 'EXT:rte_ckeditor/Configuration/RTE/Editor/Plugins.yaml' }
 
+
 # Add configuration for the editor
 # For complete documentation see https://ckeditor.com/docs/ckeditor5/latest/features/index.html
 editor:
 
-  editing:
-    view:
-      change:
-        - ( writer => {const viewEditableRoot = editor.editing.view.document.getRoot();
-          writer.setAttribute( 'div', 'value', viewEditableRoot )
-
   config:
-
-#    importModules:
-#      - '@t3sbs/t3sbootstrap/timestamp-plugin.js'
-
-    contentsCss: 'EXT:t3sbootstrap/Resources/Public/Backend/RTE/t3sbootstrap.css'
+   
+    contentsCss: 
+      - 'EXT:t3sbootstrap/Resources/Public/Backend/RTE/t3sbootstrap.css'
 
     toolbar:
       items:
@@ -54,20 +47,19 @@ editor:
         - findAndReplace
         - insertTable
         - specialCharacters
-#        - '|'
-#        - timestamp
+
 
     heading:
       options:
         - { model: 'paragraph', title: 'Paragraph' }
         - { model: 'heading2', view: 'h2', title: 'Heading 2' }
-        - { model: 'heading2 - primary', view: 'h2', title: 'Heading 2' }
         - { model: 'heading3', view: 'h3', title: 'Heading 3' }
         - { model: 'heading4', view: 'h4', title: 'Heading 4' }
         - { model: 'heading5', view: 'h5', title: 'Heading 5' }
         - { model: 'heading6', view: 'h6', title: 'Heading 6' }
         - { model: 'formatted', view: 'pre', title: 'Pre-Formatted Text' }
 
+
     style:
       definitions:
         # Blockstile
@@ -79,27 +71,27 @@ editor:
         - { name: 'Color info ', element: 'p', classes: ['text-info'], isBlock: 'true' }
         - { name: 'Color danger ', element: 'p', classes: ['text-danger'], isBlock: 'true' }
         - { name: 'Color warning ', element: 'p', classes: ['text-warning'], isBlock: 'true' }
-
-        # Blockstile - Alert
-#        - { name: 'Alert Primary', element: 'div', 'classes': ['alert alert-primary'], isBlock: 'true' }
-#        - { name: 'Alert Secondary', element: 'div', classes': ['alert alert-secondary'], isBlock: 'true' }
-#        - { name: 'Alert Success', element: 'div', 'classes': ['alert alert-success'], isBlock: 'true' }
-#        - { name: 'Alert Danger', element: 'div', 'classes': ['alert alert-danger'], isBlock: 'true' }
-#        - { name: 'Alert Warning', element: 'div', 'classes': ['alert alert-warning'], isBlock: 'true' }
-#        - { name: 'Alert Info', element: 'div', 'classes': ['alert alert-info'], isBlock: 'true' }
-#        - { name: 'Alert Light', element: 'div', 'classes': ['alert alert-light'], isBlock: 'true' }
-#        - { name: 'Alert Dark', element: 'div', 'classes': ['alert alert-dark'], isBlock: 'true' }
-
         - { name: 'Lowercase', element: 'p', 'classes': ['text-lowercase'], isBlock: 'true' }
         - { name: 'Uppercase', element: 'p', 'classes': ['text-uppercase'], isBlock: 'true' }
         - { name: 'Capitalize', element: 'p', 'classes': ['text-capitalize'], isBlock: 'true' }
 
+
+        # Blockstile - Alert (div)
+ #       - { name: 'Alert Primary', element: 'div', 'classes': ['alert', 'alert-primary'], isBlock: 'true' }
+ #       - { name: 'Alert Secondary', element: 'div', classes': ['alert', 'alert-secondary'], isBlock: 'true' }
+ #       - { name: 'Alert Success', element: 'div', 'classes': ['alert', 'alert-success'], isBlock: 'true' }
+ #       - { name: 'Alert Danger', element: 'div', 'classes': ['alert', 'alert-danger'], isBlock: 'true' }
+ #       - { name: 'Alert Warning', element: 'div', 'classes': ['alert', 'alert-warning'], isBlock: 'true' }
+ #       - { name: 'Alert Info', element: 'div', 'classes': ['alert', 'alert-info'], isBlock: 'true' }
+ #       - { name: 'Alert Light', element: 'div', 'classes': ['alert', 'alert-light'], isBlock: 'true' }
+ #       - { name: 'Alert Dark', element: 'div', 'classes': ['alert', 'alert-dark'], isBlock: 'true' }
+
         # Textstile
         - { name: 'Mark', element: 'span', classes: ['mark'] }
 
         - { name: 'Del', element: 'del', classes: ['del'] }
         - { name: 'Ins', element: 'ins', classes: ['ins'] }
-        - { name: 'Code', element: 'code', classes: ['code'] }
+        - { name: 'Code', element: 'code', classes: [''] }
 
         - { name: 'Lead', element: 'span', classes: ['lead'] }
         - { name: 'Small', element: 'span', classes: ['small'] }
@@ -115,21 +107,16 @@ editor:
 
 
         # Textstile - Buttons
-#        - { name: 'Button Primary', element: 'a', 'classes': ['btn btn-primary'] } 
-#        - { name: 'Button Secondary', element: 'a', 'classes': ['btn btn-secondary'] } 
-#        - { name: 'Button Success', element: 'a', 'classes': ['btn btn-success'] } 
-#        - { name: 'Button Danger', element: 'a', 'classes': ['btn btn-danger'] } 
-#        - { name: 'Button Warning', element: 'a', 'classes': ['btn btn-warning'] } 
-#        - { name: 'Button Info', element: 'a', 'classes': ['btn btn-info'] } 
-#        - { name: 'Button Light', element: 'a', 'classes': ['btn btn-light'] } 
-#        - { name: 'Button Dark', element: 'a', 'classes': ['btn btn-dark'] } 
-
-
+        - { name: 'Button Primary', element: 'a', 'classes': ['btn btn-primary'] } 
+        - { name: 'Button Secondary', element: 'a', 'classes': ['btn btn-secondary'] } 
+        - { name: 'Button Success', element: 'a', 'classes': ['btn btn-success'] } 
+        - { name: 'Button Danger', element: 'a', 'classes': ['btn btn-danger'] } 
+        - { name: 'Button Warning', element: 'a', 'classes': ['btn btn-warning'] } 
+        - { name: 'Button Info', element: 'a', 'classes': ['btn btn-info'] } 
+        - { name: 'Button Light', element: 'a', 'classes': ['btn btn-light'] } 
+        - { name: 'Button Dark', element: 'a', 'classes': ['btn btn-dark'] } 
 
 
-
-
-        
         # Textstile - Badges
         - { name: 'Badge Primary', element: 'span', 'classes': ['badge', 'text-bg-primary'] } 
         - { name: 'Badge Secondary', element: 'span', 'classes': ['badge text-bg-secondary'] } 
diff --git a/Configuration/RTE/DefaultFa6.yaml b/Configuration/RTE/DefaultFa6.yaml
deleted file mode 100644
index 9fd35a85..00000000
--- a/Configuration/RTE/DefaultFa6.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-imports:
-    - { resource: "EXT:t3sbootstrap/Configuration/RTE/Default.yaml" }
-    - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6.yaml" }
diff --git a/Configuration/RTE/CodesnippetFa6.yaml b/Configuration/RTE/Fa6.yaml
similarity index 100%
rename from Configuration/RTE/CodesnippetFa6.yaml
rename to Configuration/RTE/Fa6.yaml
diff --git a/Configuration/RTE/CodesnippetFa6Pro.yaml b/Configuration/RTE/Fa6Pro.yaml
similarity index 55%
rename from Configuration/RTE/CodesnippetFa6Pro.yaml
rename to Configuration/RTE/Fa6Pro.yaml
index 511d1827..72c4d232 100644
--- a/Configuration/RTE/CodesnippetFa6Pro.yaml
+++ b/Configuration/RTE/Fa6Pro.yaml
@@ -3,8 +3,7 @@ imports:
     - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6Pro.yaml" }
 
 editor:
-
   config:
-    contentsCss:
-    - "EXT:t3sbootstrap/Resources/Public/Backend/t3sbootstrap.css"
-    - "../../../../../../fileadmin/T3SB/FA6Pro/css/all.min.css"
+    ui:
+      DPFontAwesome:
+        css: '../../../../../../fileadmin/T3SB/Resources/Public/FA6Pro/css/all.min.css'
diff --git a/Configuration/RTE/DefaultFa6Pro.yaml b/Configuration/RTE/Sitepackage/Fa6Pro.yaml
similarity index 55%
rename from Configuration/RTE/DefaultFa6Pro.yaml
rename to Configuration/RTE/Sitepackage/Fa6Pro.yaml
index 511d1827..16f417dd 100644
--- a/Configuration/RTE/DefaultFa6Pro.yaml
+++ b/Configuration/RTE/Sitepackage/Fa6Pro.yaml
@@ -3,8 +3,7 @@ imports:
     - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6Pro.yaml" }
 
 editor:
-
   config:
-    contentsCss:
-    - "EXT:t3sbootstrap/Resources/Public/Backend/t3sbootstrap.css"
-    - "../../../../../../fileadmin/T3SB/FA6Pro/css/all.min.css"
+    ui:
+      DPFontAwesome:
+        css: 'EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/all.min.css'
diff --git a/Configuration/RTE/Sitepackage/Fa6ProKit.yaml b/Configuration/RTE/Sitepackage/Fa6ProKit.yaml
new file mode 100644
index 00000000..16f417dd
--- /dev/null
+++ b/Configuration/RTE/Sitepackage/Fa6ProKit.yaml
@@ -0,0 +1,9 @@
+imports:
+    - { resource: "EXT:t3sbootstrap/Configuration/RTE/Default.yaml" }
+    - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6Pro.yaml" }
+
+editor:
+  config:
+    ui:
+      DPFontAwesome:
+        css: 'EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/all.min.css'
diff --git a/Configuration/TCA/Overrides/pages.php b/Configuration/TCA/Overrides/pages.php
index 5ad06703..398f5fad 100644
--- a/Configuration/TCA/Overrides/pages.php
+++ b/Configuration/TCA/Overrides/pages.php
@@ -6,384 +6,396 @@
 $extconf = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Configuration\ExtensionConfiguration::class)->get('t3sbootstrap');
 
 $tempPagesColumns = [
-	'tx_t3sbootstrap_smallColumns' => [
-		'label' => 'Aside columns width',
-		'exclude' => 1,
-		'description' => 'makes no sense for Backend Layout "1 Column"',
-		'config' => [
-			'type' => 'select',
-			'renderType' => 'selectSingle',
-			'items' => [
-				['label' => '1', 'value' => 1,],
-				['label' => '2', 'value' => 2,],
-				['label' => '3', 'value' => 3,],
-				['label' => '4', 'value' => 4,],
-				['label' => '5', 'value' => 5,],
-				['label' => '6', 'value' => 6,],
-			],
-			'default' => 3
-		]
-	],
-	'tx_t3sbootstrap_container' => [
-		'label' => 'Container (for the whole page)',
-		'exclude' => 1,
-		'config' => [
-			'type' => 'select',
-			'renderType' => 'selectSingle',
-			'items' => [
-				['label' => 'no container', 'value' => '0',],
-				['label' => 'container','value' => 'container',],
-				['label' => 'container-sm (< 576px)', 'value' => 'container-sm',],
-				['label' => 'container-md (≥ 576px)', 'value' => 'container-md',],
-				['label' => 'container-lg (≥ 768px)', 'value' => 'container-lg',],
-				['label' => 'container-xl (≥ 992px)', 'value' => 'container-xl',],
-				['label' => 'container-xxl (≥ 1200px)', 'value' => 'container-xxl',],
-				['label' => 'container-fluid (≥ 1400px)', 'value' => 'container-fluid',],
-			],
-			'default' => 'container'
-		]
-	],
-	'tx_t3sbootstrap_linkToTop' => [
-		'exclude' => 1,
-		'label' => 'Link to top',
-		'config' => [
-			'type' => 'check',
-			'default' => 1
-		]
-	],
-	'tx_t3sbootstrap_dropdownRight' => [
-		'exclude' => 1,
-		'label' => 'Dropdown menu right',
-		'config' => [
-			'type' => 'check',
-		]
-	],
-	'tx_t3sbootstrap_megamenu' => [
-		'exclude' => 1,
-		'label' => 'Mega menu',
-		'displayCond' => 'FIELD:doktype:=:4',
-		'config' => [
-			'type' => 'check',
-		]
-	],
-	'tx_t3sbootstrap_mobileOrder' => [
-		'label' => 'Aside order on mobile',
-		'exclude' => 1,
-		'config' => [
-			'type' => 'select',
-			'renderType' => 'selectSingle',
-			'items' => [
-				['label' => 'Default', 'value' => 'default',],
-				['label' => 'Top (both)', 'value' => 'top',],
-				['label' => 'Bottom (both)', 'value' => 'bottom',],
-				['label' => 'Left Aside Top', 'value' => 'leftTop',],
-				['label' => 'Left Aside Bottom', 'value' => 'leftBottom',],
-				['label' => 'Right Aside Top', 'value' => 'rightTop',],
-				['label' => 'Right Aside Bottom', 'value' => 'rightBottom',],
-			],
-			'default' => 'default'
-		]
-	],
-	'tx_t3sbootstrap_breakpoint' => [
-		'label' => 'Breakpoint',
-		'exclude' => 1,
-		'config' => [
-			'type' => 'select',
-			'renderType' => 'selectSingle',
-			'items' => [
-				['label' => 'Default', 'value' => 'md',],
-				['label' => 'sm', 'value' => 'sm',],
-				['label' => 'md', 'value' => 'md',],
-				['label' => 'lg', 'value' => 'lg',],
-				['label' => 'xl', 'value' => 'xl',],
-				['label' => 'xxl', 'value' => 'xxl',],
-			],
-			'default' => 'md'
-		]
-	],
-	'tx_t3sbootstrap_fontawesome_icon' => [
-		'exclude' => 1,
-		'label'	=> 'e.g.: fa-brands fa-typo3 fa-lg',
-		'config' => [
-			'type' => 'input',
-			'size' => 20,
-			'eval' => 'trim',
-			'valuePicker' => [
-				'items' => [
-					['typo3', 'fa-brands fa-typo3'],
-					['envelope', 'fa-solid fa-envelope'],
-					['circle-info', 'fa-solid fa-circle-info'],
-					['exclamation-circle', 'fa-solid fa-exclamation-circle'],
-					['circle-question', 'fa-solid fa-circle-question'],
-					['circle-check', 'fa-solid fa-circle-check'],
-					['circle-chevron-left', 'fa-solid fa-circle-chevron-left'],
-					['circle-chevron-right', 'fa-solid fa-circle-chevron-right'],
-					['youtube', 'fa-brands fa-youtube'],
-					['vimeo', 'fa-brands fa-vimeo-square'],
-				],
-			],
-		]
-	],
-	'tx_t3sbootstrap_icon_only' => [
-		'exclude' => 1,
-		'label' => 'Icon only',
-		'description' => 'for nav-item not for page title',
-		'config' => [
-			'type' => 'check',
-		]
-	],
-	'tx_t3sbootstrap_titlecolor' => [
-		'label' => 'Page Title Color',
-		'exclude' => 1,
-		'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
-		'config' => [
-			'type' => 'input',
-			'size' => 20,
-			'eval' => 'trim',
-			'valuePicker' => [
-				'items' => [
-					['var(--bs-primary)', 'var(--bs-primary)'],
-					['var(--bs-secondary)', 'var(--bs-secondary)'],
-					['var(--bs-success)', 'var(--bs-success)'],
-					['var(--bs-danger)', 'var(--bs-danger)'],
-					['var(--bs-warning)', 'var(--bs-warning)'],
-					['var(--bs-info)', 'var(--bs-info)']
-				],
-			],
-		],
-	],
-	'tx_t3sbootstrap_subtitlecolor' => [
-		'label' => 'Subtitle Color',
-		'exclude' => 1,
-		'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
-		'config' => [
-			'type' => 'input',
-			'size' => 20,
-			'eval' => 'trim',
-			'valuePicker' => [
-				'items' => [
-					['var(--bs-primary)', 'var(--bs-primary)'],
-					['var(--bs-secondary)', 'var(--bs-secondary)'],
-					['var(--bs-success)', 'var(--bs-success)'],
-					['var(--bs-danger)', 'var(--bs-danger)'],
-					['var(--bs-warning)', 'var(--bs-warning)'],
-					['var(--bs-info)', 'var(--bs-info)']
-				],
-			],
-		],
-	],
-	'tx_t3sbootstrap_navigationcolor' => [
-		'label' => 'Color',
-		'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
-		'exclude' => 1,
-		'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
-		'config' => [
-			'type' => 'input',
-			'size' => 20,
-			'eval' => 'trim',
-			'valuePicker' => [
-				'items' => [
-					['var(--bs-primary)', 'var(--bs-primary)'],
-					['var(--bs-secondary)', 'var(--bs-secondary)'],
-					['var(--bs-success)', 'var(--bs-success)'],
-					['var(--bs-danger)', 'var(--bs-danger)'],
-					['var(--bs-warning)', 'var(--bs-warning)'],
-					['var(--bs-info)', 'var(--bs-info)']
-				],
-			],
-		],
-	],
-	'tx_t3sbootstrap_navigationactivecolor' => [
-		'label' => 'Active Color',
-		'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
-		'exclude' => 1,
-		'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
-		'config' => [
-			'type' => 'input',
-			'size' => 20,
-			'eval' => 'trim',
-			'valuePicker' => [
-				'items' => [
-					['var(--bs-primary)', 'var(--bs-primary)'],
-					['var(--bs-secondary)', 'var(--bs-secondary)'],
-					['var(--bs-success)', 'var(--bs-success)'],
-					['var(--bs-danger)', 'var(--bs-danger)'],
-					['var(--bs-warning)', 'var(--bs-warning)'],
-					['var(--bs-info)', 'var(--bs-info)']
-				],
-			],
-		],
-	],
-	'tx_t3sbootstrap_navigationhover' => [
-		'label' => 'Hover Color',
-		'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
-		'exclude' => 1,
-		'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
-		'config' => [
-			'type' => 'input',
-			'size' => 20,
-			'eval' => 'trim',
-			'valuePicker' => [
-				'items' => [
-					['var(--bs-primary)', 'var(--bs-primary)'],
-					['var(--bs-secondary)', 'var(--bs-secondary)'],
-					['var(--bs-success)', 'var(--bs-success)'],
-					['var(--bs-danger)', 'var(--bs-danger)'],
-					['var(--bs-warning)', 'var(--bs-warning)'],
-					['var(--bs-info)', 'var(--bs-info)'],
-					['text-light', 'text-light'],
-					['text-dark', 'text-dark'],
-					['text-body', 'text-body'],
-					['text-muted', 'text-muted'],
-					['text-white', 'text-white'],
-					['text-black-50', 'text-black-50'],
-					['text-white-50', 'text-white-50'],
-					['text-uppercase', 'text-uppercase'],
-					['text-capitalize', 'text-capitalize'],
-					['text-left', 'text-start'],
-					['text-center', 'text-center'],
-					['text-right', 'text-end'],
-					['font-weight-bold', 'font-weight-bold'],
-					['font-weight-bolder', 'font-weight-bolder'],
-					['font-weight-normal', 'font-weight-normal'],
-					['font-weight-light', 'font-weight-light'],
-					['font-weight-lighter', 'font-weight-lighter'],
-					['font-italic', 'font-italic'],
-					['font-normal', 'font-normal'],
-					['display-1','display-1'],
-					['display-2','display-2'],
-					['display-3','display-3'],
-					['display-4','display-4'],
-					['display-5','display-5'],
-					['display-6','display-6']
-				],
-			],
-		],
-	],
-	'tx_t3sbootstrap_navigationbgcolor' => [
-		'label' => 'Background Active & Hover Color',
-		'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
-		'exclude' => 1,
-		'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
-		'config' => [
-			'type' => 'input',
-			'size' => 20,
-			'eval' => 'trim',
-			'valuePicker' => [
-				'items' => [
-					['var(--bs-primary)', 'var(--bs-primary)'],
-					['var(--bs-secondary)', 'var(--bs-secondary)'],
-					['var(--bs-success)', 'var(--bs-success)'],
-					['var(--bs-danger)', 'var(--bs-danger)'],
-					['var(--bs-warning)', 'var(--bs-warning)'],
-					['var(--bs-info)', 'var(--bs-info)'],
-					['text-light', 'text-light'],
-					['text-dark', 'text-dark'],
-					['text-body', 'text-body'],
-					['text-muted', 'text-muted'],
-					['text-white', 'text-white'],
-					['text-black-50', 'text-black-50'],
-					['text-white-50', 'text-white-50'],
-					['text-uppercase', 'text-uppercase'],
-					['text-capitalize', 'text-capitalize'],
-					['text-left', 'text-start'],
-					['text-center', 'text-center'],
-					['text-right', 'text-end'],
-					['font-weight-bold', 'font-weight-bold'],
-					['font-weight-bolder', 'font-weight-bolder'],
-					['font-weight-normal', 'font-weight-normal'],
-					['font-weight-light', 'font-weight-light'],
-					['font-weight-lighter', 'font-weight-lighter'],
-					['font-italic', 'font-italic'],
-					['font-normal', 'font-normal'],
-					['display-1','display-1'],
-					['display-2','display-2'],
-					['display-3','display-3'],
-					['display-4','display-4'],
-					['display-5','display-5'],
-					['display-6','display-6']
-				],
-			],
-		],
-	]
+    'tx_t3sbootstrap_smallColumns' => [
+        'label' => 'Aside columns width',
+        'exclude' => 1,
+        'description' => 'makes no sense for Backend Layout "1 Column"',
+        'config' => [
+            'type' => 'select',
+            'renderType' => 'selectSingle',
+            'items' => [
+                ['label' => '1', 'value' => 1,],
+                ['label' => '2', 'value' => 2,],
+                ['label' => '3', 'value' => 3,],
+                ['label' => '4', 'value' => 4,],
+                ['label' => '5', 'value' => 5,],
+                ['label' => '6', 'value' => 6,],
+            ],
+            'default' => 3
+        ]
+    ],
+    'tx_t3sbootstrap_container' => [
+        'label' => 'Container (for the whole page)',
+        'exclude' => 1,
+        'config' => [
+            'type' => 'select',
+            'renderType' => 'selectSingle',
+            'items' => [
+                ['label' => 'no container', 'value' => '0',],
+                ['label' => 'container','value' => 'container',],
+                ['label' => 'container-sm (< 576px)', 'value' => 'container-sm',],
+                ['label' => 'container-md (≥ 576px)', 'value' => 'container-md',],
+                ['label' => 'container-lg (≥ 768px)', 'value' => 'container-lg',],
+                ['label' => 'container-xl (≥ 992px)', 'value' => 'container-xl',],
+                ['label' => 'container-xxl (≥ 1200px)', 'value' => 'container-xxl',],
+                ['label' => 'container-fluid (≥ 1400px)', 'value' => 'container-fluid',],
+            ],
+            'default' => 'container'
+        ]
+    ],
+    'tx_t3sbootstrap_linkToTop' => [
+        'exclude' => 1,
+        'label' => 'Link to top',
+        'config' => [
+            'type' => 'check',
+            'default' => 1
+        ]
+    ],
+    'tx_t3sbootstrap_dropdownRight' => [
+        'exclude' => 1,
+        'label' => 'Dropdown menu right',
+        'config' => [
+            'type' => 'check',
+        ]
+    ],
+    'tx_t3sbootstrap_megamenu' => [
+        'exclude' => 1,
+        'label' => 'Mega menu',
+        'displayCond' => 'FIELD:doktype:=:4',
+        'config' => [
+            'type' => 'check',
+        ]
+    ],
+    'tx_t3sbootstrap_mobileOrder' => [
+        'label' => 'Aside order on mobile',
+        'exclude' => 1,
+        'config' => [
+            'type' => 'select',
+            'renderType' => 'selectSingle',
+            'items' => [
+                ['label' => 'Default', 'value' => 'default',],
+                ['label' => 'Top (both)', 'value' => 'top',],
+                ['label' => 'Bottom (both)', 'value' => 'bottom',],
+                ['label' => 'Left Aside Top', 'value' => 'leftTop',],
+                ['label' => 'Left Aside Bottom', 'value' => 'leftBottom',],
+                ['label' => 'Right Aside Top', 'value' => 'rightTop',],
+                ['label' => 'Right Aside Bottom', 'value' => 'rightBottom',],
+            ],
+            'default' => 'default'
+        ]
+    ],
+    'tx_t3sbootstrap_breakpoint' => [
+        'label' => 'Breakpoint',
+        'exclude' => 1,
+        'config' => [
+            'type' => 'select',
+            'renderType' => 'selectSingle',
+            'items' => [
+                ['label' => 'Default', 'value' => 'md',],
+                ['label' => 'sm', 'value' => 'sm',],
+                ['label' => 'md', 'value' => 'md',],
+                ['label' => 'lg', 'value' => 'lg',],
+                ['label' => 'xl', 'value' => 'xl',],
+                ['label' => 'xxl', 'value' => 'xxl',],
+            ],
+            'default' => 'md'
+        ]
+    ],
+    'tx_t3sbootstrap_fontawesome_icon' => [
+        'exclude' => 1,
+        'label'	=> 'e.g.: fa-brands fa-typo3 fa-lg',
+        'config' => [
+            'type' => 'input',
+            'size' => 20,
+            'eval' => 'trim',
+            'valuePicker' => [
+                'items' => [
+                    ['typo3', 'fa-brands fa-typo3'],
+                    ['envelope', 'fa-solid fa-envelope'],
+                    ['info-circle', 'fa-solid fa-circle-info'],
+                    ['exclamation-circle', 'fa-solid fa-circle-exclamation'],
+                    ['question-circle', 'fa-solid fa-circle-question'],
+                    ['check-circle', 'fa-solid fa-circle-check'],
+                    ['chevron-circle-left', 'fa-solid fa-circle-chevron-left'],
+                    ['chevron-circle-right', 'fa-solid fa-circle-chevron-right'],
+                    ['youtube', 'fa-brands fa-youtube'],
+                    ['vimeo', 'fa-brands fa-square-vimeo'],
+                ],
+            ],
+        ]
+    ],
+    'tx_t3sbootstrap_icon_only' => [
+        'exclude' => 1,
+        'label' => 'Icon only',
+        'description' => 'for nav-item not for page title',
+        'config' => [
+            'type' => 'check',
+        ]
+    ],
+    'tx_t3sbootstrap_titlecolor' => [
+        'label' => 'Page Title Color',
+        'exclude' => 1,
+        'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
+        'config' => [
+            'type' => 'input',
+            'size' => 20,
+            'eval' => 'trim',
+            'valuePicker' => [
+                'items' => [
+                    ['var(--bs-primary)', 'var(--bs-primary)'],
+                    ['var(--bs-secondary)', 'var(--bs-secondary)'],
+                    ['var(--bs-success)', 'var(--bs-success)'],
+                    ['var(--bs-danger)', 'var(--bs-danger)'],
+                    ['var(--bs-warning)', 'var(--bs-warning)'],
+                    ['var(--bs-info)', 'var(--bs-info)']
+                ],
+            ],
+        ],
+    ],
+    'tx_t3sbootstrap_subtitlecolor' => [
+        'label' => 'Subtitle Color',
+        'exclude' => 1,
+        'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
+        'config' => [
+            'type' => 'input',
+            'size' => 20,
+            'eval' => 'trim',
+            'valuePicker' => [
+                'items' => [
+                    ['var(--bs-primary)', 'var(--bs-primary)'],
+                    ['var(--bs-secondary)', 'var(--bs-secondary)'],
+                    ['var(--bs-success)', 'var(--bs-success)'],
+                    ['var(--bs-danger)', 'var(--bs-danger)'],
+                    ['var(--bs-warning)', 'var(--bs-warning)'],
+                    ['var(--bs-info)', 'var(--bs-info)']
+                ],
+            ],
+        ],
+    ],
+    'tx_t3sbootstrap_navigationcolor' => [
+        'label' => 'Color',
+        'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
+        'exclude' => 1,
+        'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
+        'config' => [
+            'type' => 'input',
+            'size' => 20,
+            'eval' => 'trim',
+            'valuePicker' => [
+                'items' => [
+                    ['var(--bs-primary)', 'var(--bs-primary)'],
+                    ['var(--bs-secondary)', 'var(--bs-secondary)'],
+                    ['var(--bs-success)', 'var(--bs-success)'],
+                    ['var(--bs-danger)', 'var(--bs-danger)'],
+                    ['var(--bs-warning)', 'var(--bs-warning)'],
+                    ['var(--bs-info)', 'var(--bs-info)']
+                ],
+            ],
+        ],
+    ],
+    'tx_t3sbootstrap_navigationactivecolor' => [
+        'label' => 'Active Color',
+        'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
+        'exclude' => 1,
+        'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
+        'config' => [
+            'type' => 'input',
+            'size' => 20,
+            'eval' => 'trim',
+            'valuePicker' => [
+                'items' => [
+                    ['var(--bs-primary)', 'var(--bs-primary)'],
+                    ['var(--bs-secondary)', 'var(--bs-secondary)'],
+                    ['var(--bs-success)', 'var(--bs-success)'],
+                    ['var(--bs-danger)', 'var(--bs-danger)'],
+                    ['var(--bs-warning)', 'var(--bs-warning)'],
+                    ['var(--bs-info)', 'var(--bs-info)']
+                ],
+            ],
+        ],
+    ],
+    'tx_t3sbootstrap_navigationhover' => [
+        'label' => 'Hover Color',
+        'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
+        'exclude' => 1,
+        'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
+        'config' => [
+            'type' => 'input',
+            'size' => 20,
+            'eval' => 'trim',
+            'valuePicker' => [
+                'items' => [
+                    ['var(--bs-primary)', 'var(--bs-primary)'],
+                    ['var(--bs-secondary)', 'var(--bs-secondary)'],
+                    ['var(--bs-success)', 'var(--bs-success)'],
+                    ['var(--bs-danger)', 'var(--bs-danger)'],
+                    ['var(--bs-warning)', 'var(--bs-warning)'],
+                    ['var(--bs-info)', 'var(--bs-info)'],
+                    ['text-light', 'text-light'],
+                    ['text-dark', 'text-dark'],
+                    ['text-body', 'text-body'],
+                    ['text-muted', 'text-muted'],
+                    ['text-white', 'text-white'],
+                    ['text-black-50', 'text-black-50'],
+                    ['text-white-50', 'text-white-50'],
+                    ['text-uppercase', 'text-uppercase'],
+                    ['text-capitalize', 'text-capitalize'],
+                    ['text-left', 'text-start'],
+                    ['text-center', 'text-center'],
+                    ['text-right', 'text-end'],
+                    ['font-weight-bold', 'font-weight-bold'],
+                    ['font-weight-bolder', 'font-weight-bolder'],
+                    ['font-weight-normal', 'font-weight-normal'],
+                    ['font-weight-light', 'font-weight-light'],
+                    ['font-weight-lighter', 'font-weight-lighter'],
+                    ['font-italic', 'font-italic'],
+                    ['font-normal', 'font-normal'],
+                    ['display-1','display-1'],
+                    ['display-2','display-2'],
+                    ['display-3','display-3'],
+                    ['display-4','display-4'],
+                    ['display-5','display-5'],
+                    ['display-6','display-6']
+                ],
+            ],
+        ],
+    ],
+    'tx_t3sbootstrap_navigationbgcolor' => [
+        'label' => 'Background Active & Hover Color',
+        'displayCond' => 'USER:T3SBS\\T3sbootstrap\\UserFunction\\TcaMatcher->isDropdownMenu',
+        'exclude' => 1,
+        'description' => 'Hex color codes, RGB or CSS variables e.g. var(--bs-primary)',
+        'config' => [
+            'type' => 'input',
+            'size' => 20,
+            'eval' => 'trim',
+            'valuePicker' => [
+                'items' => [
+                    ['var(--bs-primary)', 'var(--bs-primary)'],
+                    ['var(--bs-secondary)', 'var(--bs-secondary)'],
+                    ['var(--bs-success)', 'var(--bs-success)'],
+                    ['var(--bs-danger)', 'var(--bs-danger)'],
+                    ['var(--bs-warning)', 'var(--bs-warning)'],
+                    ['var(--bs-info)', 'var(--bs-info)'],
+                    ['text-light', 'text-light'],
+                    ['text-dark', 'text-dark'],
+                    ['text-body', 'text-body'],
+                    ['text-muted', 'text-muted'],
+                    ['text-white', 'text-white'],
+                    ['text-black-50', 'text-black-50'],
+                    ['text-white-50', 'text-white-50'],
+                    ['text-uppercase', 'text-uppercase'],
+                    ['text-capitalize', 'text-capitalize'],
+                    ['text-left', 'text-start'],
+                    ['text-center', 'text-center'],
+                    ['text-right', 'text-end'],
+                    ['font-weight-bold', 'font-weight-bold'],
+                    ['font-weight-bolder', 'font-weight-bolder'],
+                    ['font-weight-normal', 'font-weight-normal'],
+                    ['font-weight-light', 'font-weight-light'],
+                    ['font-weight-lighter', 'font-weight-lighter'],
+                    ['font-italic', 'font-italic'],
+                    ['font-normal', 'font-normal'],
+                    ['display-1','display-1'],
+                    ['display-2','display-2'],
+                    ['display-3','display-3'],
+                    ['display-4','display-4'],
+                    ['display-5','display-5'],
+                    ['display-6','display-6']
+                ],
+            ],
+        ],
+    ]
 ];
 
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('pages',$tempPagesColumns);
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('pages', $tempPagesColumns);
 unset($tempPagesColumns);
 
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'title','--linebreak--,tx_t3sbootstrap_titlecolor','after:title');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'title','--linebreak--,tx_t3sbootstrap_subtitlecolor','after:subtitle');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout','--linebreak--,tx_t3sbootstrap_smallColumns','after:backend_layout_next_level');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout','--linebreak--,tx_t3sbootstrap_mobileOrder','after:tx_t3sbootstrap_smallColumns');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout','--linebreak--,tx_t3sbootstrap_breakpoint','after:tx_t3sbootstrap_mobileOrder');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout','--linebreak--,tx_t3sbootstrap_dropdownRight','after:tx_t3sbootstrap_breakpoint');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout','--linebreak--,tx_t3sbootstrap_container','after:tx_t3sbootstrap_dropdownRight');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout','--linebreak--,tx_t3sbootstrap_linkToTop','after:tx_t3sbootstrap_container');
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout','--linebreak--,tx_t3sbootstrap_megamenu','after:tx_t3sbootstrap_linkToTop');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'title', '--linebreak--,tx_t3sbootstrap_titlecolor', 'after:title');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'title', '--linebreak--,tx_t3sbootstrap_subtitlecolor', 'after:subtitle');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout', '--linebreak--,tx_t3sbootstrap_smallColumns', 'after:backend_layout_next_level');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout', '--linebreak--,tx_t3sbootstrap_mobileOrder', 'after:tx_t3sbootstrap_smallColumns');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout', '--linebreak--,tx_t3sbootstrap_breakpoint', 'after:tx_t3sbootstrap_mobileOrder');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout', '--linebreak--,tx_t3sbootstrap_dropdownRight', 'after:tx_t3sbootstrap_breakpoint');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout', '--linebreak--,tx_t3sbootstrap_container', 'after:tx_t3sbootstrap_dropdownRight');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout', '--linebreak--,tx_t3sbootstrap_linkToTop', 'after:tx_t3sbootstrap_container');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette('pages', 'layout', '--linebreak--,tx_t3sbootstrap_megamenu', 'after:tx_t3sbootstrap_linkToTop');
 
 if (array_key_exists('navigationColor', $extconf) && $extconf['navigationColor'] === '1') {
-	# add palette Navigation Colors
-	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
-		'pages',
-		'--palette--; Navigation Colors for dropdown items;navColors',
-		'',
-		'after:title'
-	);
+    # add palette Navigation Colors
+    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
+        'pages',
+        '--palette--; Navigation Colors for dropdown items;navColors',
+        '',
+        'after:title'
+    );
 
-	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
-		'pages', 'navColors','--linebreak--,tx_t3sbootstrap_navigationcolor','after:tx_t3sbootstrap_subtitlecolor'
-	);
-	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
-		'pages', 'navColors','--linebreak--,tx_t3sbootstrap_navigationactivecolor','after:tx_t3sbootstrap_navigationcolor'
-	);
-	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
-		'pages', 'navColors','--linebreak--,tx_t3sbootstrap_navigationhover','after:tx_t3sbootstrap_navigationactivecolor'
-	);
-	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
-		'pages', 'navColors','--linebreak--,tx_t3sbootstrap_navigationbgcolor','after:tx_t3sbootstrap_navigationhover'
-	);
+    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
+        'pages',
+        'navColors',
+        '--linebreak--,tx_t3sbootstrap_navigationcolor',
+        'after:tx_t3sbootstrap_subtitlecolor'
+    );
+    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
+        'pages',
+        'navColors',
+        '--linebreak--,tx_t3sbootstrap_navigationactivecolor',
+        'after:tx_t3sbootstrap_navigationcolor'
+    );
+    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
+        'pages',
+        'navColors',
+        '--linebreak--,tx_t3sbootstrap_navigationhover',
+        'after:tx_t3sbootstrap_navigationactivecolor'
+    );
+    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
+        'pages',
+        'navColors',
+        '--linebreak--,tx_t3sbootstrap_navigationbgcolor',
+        'after:tx_t3sbootstrap_navigationhover'
+    );
 }
 
 if (array_key_exists('fontawesome', $extconf) && $extconf['fontawesome'] === '1') {
-	$GLOBALS['TCA']['pages']['palettes']['fontawesome'] = [
-		 'showitem' => 'tx_t3sbootstrap_fontawesome_icon,
+    $GLOBALS['TCA']['pages']['palettes']['fontawesome'] = [
+         'showitem' => 'tx_t3sbootstrap_fontawesome_icon,
 				tx_t3sbootstrap_icon_only',
-			 'canNotCollapse' => 1
-	];
+             'canNotCollapse' => 1
+    ];
 
-	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
-		'pages',
-		'--palette--;Fontawesome Icon;fontawesome',
-		'',
-		'after:title'
-	);
+    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
+        'pages',
+        '--palette--;Fontawesome Icon;fontawesome',
+        '',
+        'after:title'
+    );
 }
 
-   
+
 $menuheader = 198;
 
 // Add new page type as possible select item:
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem(
-	'pages',
-	'doktype',
-	[
-		'Dropdownmenu header',
-		$menuheader,
-		'content-header'
-	],
-	'2',
-	'after'
+    'pages',
+    'doktype',
+    [
+        'Dropdownmenu header',
+        $menuheader,
+        'content-header'
+    ],
+    '2',
+    'after'
 );
 
 // Add icon for new page type:
 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule(
-	$GLOBALS['TCA']['pages'],
-	[
-		'ctrl' => [
-			'typeicon_classes' => [
-				$menuheader => 'content-header',
-			],
-		],
+    $GLOBALS['TCA']['pages'],
+    [
+        'ctrl' => [
+            'typeicon_classes' => [
+                $menuheader => 'content-header',
+            ],
+        ],
 
        // add all page standard fields and tabs to your new page type
        'types' => [
@@ -391,7 +403,7 @@
                'showitem' => $GLOBALS['TCA']['pages']['types'][\TYPO3\CMS\Core\Domain\Repository\PageRepository::DOKTYPE_DEFAULT]['showitem']
            ]
        ]
-	]
+    ]
 );
 
 
@@ -400,27 +412,32 @@
  * Register PageTSConfig Files
 */
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
-	't3sbootstrap',
-	'Configuration/TSConfig/Registered/Textpic.tsconfig',
-	'Remove CType textpic'
+    't3sbootstrap',
+    'Configuration/TSConfig/Registered/Textpic.tsconfig',
+    'Remove CType textpic'
+);
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
+    't3sbootstrap',
+    'Configuration/TSConfig/Registered/Text.tsconfig',
+    'Remove CType text'
 );
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
-	't3sbootstrap',
-	'Configuration/TSConfig/Registered/Text.tsconfig',
-	'Remove CType text'
+    't3sbootstrap',
+    'Configuration/TSConfig/Registered/Image.tsconfig',
+    'Remove CType image'
 );
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
-	't3sbootstrap',
-	'Configuration/TSConfig/Registered/Image.tsconfig',
-	'Remove CType image'
+    't3sbootstrap',
+    'Configuration/TSConfig/Registered/Header.tsconfig',
+    'Remove CType header'
 );
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
-	't3sbootstrap',
-	'Configuration/TSConfig/Registered/Header.tsconfig',
-	'Remove CType header'
+    't3sbootstrap',
+    'Configuration/TSConfig/Registered/Callouts.tsconfig',
+    'Add BS-Callouts options in Layout field'
 );
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
-	't3sbootstrap',
-	'Configuration/TSConfig/Registered/Callouts.tsconfig',
-	'Add BS-Callouts options in Layout field'
+    't3sbootstrap',
+    'Configuration/TSConfig/Registered/Alerts.tsconfig',
+    'Add Alerts options in Layout field'
 );
diff --git a/Configuration/TCA/Overrides/tt_content_newCType.php b/Configuration/TCA/Overrides/tt_content_newCType.php
index 53f4aa17..6a702796 100644
--- a/Configuration/TCA/Overrides/tt_content_newCType.php
+++ b/Configuration/TCA/Overrides/tt_content_newCType.php
@@ -13,10 +13,10 @@
      'tt_content',
      'CType',
      [
-        'Plain CSS or JavaScript inline',
-        't3sbs_assets',
-        'cssJsIcon',
-    ],
+                'Plain CSS or JavaScript inline',
+                't3sbs_assets',
+                'cssJsIcon',
+        ],
      'textmedia',
      'after'
  );
@@ -24,10 +24,10 @@
     'tt_content',
     'CType',
     [
-        'Bootstrap Media object',
-        't3sbs_mediaobject',
-        'content-beside-text-img-left'
-    ],
+                'Bootstrap Media object',
+                't3sbs_mediaobject',
+                'content-beside-text-img-left'
+        ],
     'textmedia',
     'after'
 );
@@ -35,10 +35,10 @@
     'tt_content',
     'CType',
     [
-        'Bootstrap Card',
-        't3sbs_card',
-        'content-card'
-    ],
+                'Bootstrap Card',
+                't3sbs_card',
+                'content-card'
+        ],
     't3sbs_mediaobject',
     'after'
 );
@@ -46,10 +46,10 @@
     'tt_content',
     'CType',
     [
-        'Bootstrap Toasts',
-        't3sbs_toast',
-        'content-widget-calltoaction'
-    ],
+                'Bootstrap Toasts',
+                't3sbs_toast',
+                'content-widget-calltoaction'
+        ],
     't3sbs_card',
     'after'
 );
@@ -57,10 +57,10 @@
     'tt_content',
     'CType',
     [
-        'Bootstrap Carousel Item (in carousel- or swiper-container)',
-        't3sbs_carousel',
-        'content-carousel-item-textandimage'
-    ],
+                'Bootstrap Carousel Item (in carousel- or swiper-container)',
+                't3sbs_carousel',
+                'content-carousel-item-textandimage'
+        ],
     't3sbs_toast',
     'after'
 );
@@ -68,10 +68,10 @@
     'tt_content',
     'CType',
     [
-        'Bootstrap Button',
-        't3sbs_button',
-        'form-radio-button'
-    ],
+                'Bootstrap Button',
+                't3sbs_button',
+                'form-radio-button'
+        ],
     't3sbs_carousel',
     'after'
 );
@@ -79,10 +79,10 @@
     'tt_content',
     'CType',
     [
-        'Fluidtemplate',
-        't3sbs_fluidtemplate',
-        'actions-template-new'
-    ],
+                'Fluidtemplate',
+                't3sbs_fluidtemplate',
+                'actions-template-new'
+        ],
     't3sbs_button',
     'after'
 );
@@ -90,10 +90,10 @@
     'tt_content',
     'CType',
     [
-        'Bootstrap Image Gallery',
-        't3sbs_gallery',
-        'apps-filetree-folder-media'
-    ],
+                'Bootstrap Image Gallery',
+                't3sbs_gallery',
+                'apps-filetree-folder-media'
+        ],
     't3sbs_fluidtemplate',
     'after'
 );
@@ -103,680 +103,700 @@
  * New fields in table:tt_content
 */
 $tempContentColumns = [
-    'tx_t3sbootstrap_header_display' => [
-        'label' => 'Display headings',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'none-1', 'value' => '',],
-                ['label' => 'display-1', 'value' => 'display-1',],
-                ['label' => 'display-2', 'value' => 'display-2',],
-                ['label' => 'display-3', 'value' => 'display-3',],
-                ['label' => 'display-4', 'value' => 'display-4',],
-                ['label' => 'display-5', 'value' => 'display-5',],
-                ['label' => 'display-6', 'value' => 'display-6',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_header_class' => [
-        'label' => 'Header Extra Class',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'input',
-            'size' => 40,
-            'eval' => 'trim',
-            'valuePicker' => [
-                'items' => [
-                    ['m-3 (margin)', 'm-3'],
-                    ['mt-3 (margin-top)', 'mt-3'],
-                    ['mb-3 (margin-bottom)', 'mb-3'],
-                    ['ms-3 (margin-left)', 'ms-3'],
-                    ['me-3 (margin-right)', 'me-3'],
-                    ['mx-3 (margin-left and -right)', 'mx-3'],
-                    ['my-3 (margin-top and -bottom)', 'my-3'],
-                    ['text-primary', 'text-primary'],
-                    ['text-secondary', 'text-secondary'],
-                    ['text-danger', 'text-danger'],
-                    ['text-success', 'text-success'],
-                    ['text-warning', 'text-warning'],
-                    ['text-info', 'text-info'],
-                    ['text-black', 'text-black'],
-                    ['text-white', 'text-white'],
-                    ['text-uppercase', 'text-uppercase'],
-                    ['One line left and right', 'h-line-1'],
-                    ['Two lines left and right', 'h-line-2']
+        'tx_t3sbootstrap_header_display' => [
+                'label' => 'Display headings',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'none', 'value' => '',],
+                                ['label' => 'display-1', 'value' => 'display-1',],
+                                ['label' => 'display-2', 'value' => 'display-2',],
+                                ['label' => 'display-3', 'value' => 'display-3',],
+                                ['label' => 'display-4', 'value' => 'display-4',],
+                                ['label' => 'display-5', 'value' => 'display-5',],
+                                ['label' => 'display-6', 'value' => 'display-6',],
+                        ],
+                        'default' => ''
+                ]
+        ],
+        'tx_t3sbootstrap_header_class' => [
+                'label' => 'Header Extra Class',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'input',
+                        'size' => 40,
+                        'eval' => 'trim',
+                        'valuePicker' => [
+                                'items' => [
+                                        ['m-3 (margin)', 'm-3'],
+                                        ['mt-3 (margin-top)', 'mt-3'],
+                                        ['mb-3 (margin-bottom)', 'mb-3'],
+                                        ['ms-3 (margin-left)', 'ms-3'],
+                                        ['me-3 (margin-right)', 'me-3'],
+                                        ['mx-3 (margin-left and -right)', 'mx-3'],
+                                        ['my-3 (margin-top and -bottom)', 'my-3'],
+                                        ['text-primary', 'text-primary'],
+                                        ['text-secondary', 'text-secondary'],
+                                        ['text-danger', 'text-danger'],
+                                        ['text-success', 'text-success'],
+                                        ['text-warning', 'text-warning'],
+                                        ['text-info', 'text-info'],
+                                        ['text-black', 'text-black'],
+                                        ['text-white', 'text-white'],
+                                        ['text-uppercase', 'text-uppercase'],
+                                        ['One line left and right', 'h-line-1'],
+                                        ['Two lines left and right', 'h-line-2']
+                                ],
+                        ],
                 ],
-            ],
         ],
-    ],
-    'tx_t3sbootstrap_header_fontawesome' => [
-        'label' => 'Font Awesome Icon',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'input',
-            'size' => 40,
-            'eval' => 'trim',
-            'valuePicker' => [
-                'items' => [
-                    ['typo3', 'fa-brands fa-typo3'],
-                    ['envelope', 'fa-solid fa-envelope'],
-                    ['circle-info', 'fa-solid fa-circle-info'],
-                    ['exclamation-circle', 'fa-solid fa-circle-exclamation'],
-                    ['circle-question', 'fa-solid fa-circle-question'],
-                    ['circle-check', 'fa-solid fa-circle-check'],
-                    ['circle-chevron-left', 'fa-solid fa-circle-chevron-left'],
-                    ['circle-chevron-right', 'fa-solid fa-circle-chevron-right'],
-                    ['youtube', 'fa-brands fa-youtube'],
-                    ['vimeo', 'fa-brands fa-square-vimeo'],
+        'tx_t3sbootstrap_header_fontawesome' => [
+                'label' => 'Font Awesome Icon',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'input',
+                        'size' => 40,
+                        'eval' => 'trim',
+                        'valuePicker' => [
+                                'items' => [
+                                        ['typo3', 'fa-brands fa-typo3'],
+                                        ['envelope', 'fa-solid fa-envelope'],
+                                        ['info-circle', 'fa-solid fa-circle-info'],
+                                        ['exclamation-circle', 'fa-solid fa-circle-exclamation'],
+                                        ['question-circle', 'fa-solid fa-circle-question'],
+                                        ['check-circle', 'fa-solid fa-circle-check'],
+                                        ['chevron-circle-left', 'fa-solid fa-circle-chevron-left'],
+                                        ['chevron-circle-right', 'fa-solid fa-circle-chevron-right'],
+                                        ['youtube', 'fa-brands fa-youtube'],
+                                        ['vimeo', 'fa-brands fa-square-vimeo'],
+                                ],
+                        ],
                 ],
-            ],
         ],
-    ],
-    'tx_t3sbootstrap_header_celink' => [
-        'exclude' => 1,
-        'label' => 'Link the entire Content Element',
-        'config' => [
-            'type' => 'check'
-        ]
-    ],
-    'tx_t3sbootstrap_header_position' => [
-        'label' => 'Header Position',
-        'exclude' => 1,
-        'displayCond' => [
-            'OR' => [
-                'FIELD:CType:=:textmedia',
-                'FIELD:CType:=:textpic',
-            ],
+        'tx_t3sbootstrap_header_celink' => [
+                'exclude' => 1,
+                'label' => 'Link the entire Content Element',
+                'config' => [
+                        'type' => 'check'
+                ]
         ],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'Above the image (default)', 'value' => 'above',],
-                ['label' => 'Beside or under the image', 'value' => 'beside',],
-            ],
-            'default' => 'above'
-        ]
-    ],
-    'tx_t3sbootstrap_header_sectionMenu' => [
-        'label' => 'Section Menu Text',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'input',
-            'size' => 40,
-            'eval' => 'trim',
+        'tx_t3sbootstrap_header_position' => [
+                'label' => 'Header Position',
+                'exclude' => 1,
+                'displayCond' => [
+                        'OR' => [
+                                'FIELD:CType:=:textmedia',
+                                'FIELD:CType:=:textpic',
+                        ],
+                ],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'Above the image (default)', 'value' => 'above',],
+                                ['label' => 'Beside or under the image', 'value' => 'beside',],
+                        ],
+                        'default' => 'above'
+                ]
         ],
-    ],
-    'tx_t3sbootstrap_padding_sides' => [
-        'label' => 'Padding spacing side',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'no padding', 'value' => '',],
-                ['label' => 'padding on all 4 sides', 'value' => 'blank',],
-                ['label' => 'padding-top', 'value' => 't',],
-                ['label' => 'padding-bottom', 'value' => 'b',],
-                ['label' => 'padding-left', 'value' => 's',],
-                ['label' => 'padding-right', 'value' => 'e',],
-                ['label' => 'padding-left and -right', 'value' => 'x',],
-                ['label' => 'padding-top and -bottom', 'value' => 'y',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_padding_size' => [
-        'label' => 'Padding spacing size',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => '0', 'value' => '0',],
-                ['label' => '1 (.25 rem)', 'value' => '1',],
-                ['label' => '2 (.5 rem)', 'value' => '2',],
-                ['label' => '3 (1 rem)', 'value' => '3',],
-                ['label' => '4 (1.5 rem)', 'value' => '4',],
-                ['label' => '5 (3 rem)', 'value' => '5',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_margin_sides' => [
-        'label' => 'Margin spacing side',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'no margin', 'value' => '',],
-                ['label' => 'margin on all 4 sides', 'value' => 'blank',],
-                ['label' => 'margin-top', 'value' => 't',],
-                ['label' => 'margin-bottom', 'value' => 'b',],
-                ['label' => 'margin-left', 'value' => 's',],
-                ['label' => 'margin-right', 'value' => 'e',],
-                ['label' => 'margin-left and -right', 'value' => 'x',],
-                ['label' => 'margin-top and -bottom', 'value' => 'y',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_margin_size' => [
-        'label' => 'Margin spacing size',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => '0','value' => '0',],
-                ['label' => '1 (.25 rem)', 'value' => '1',],
-                ['label' => '2 (.5 rem)', 'value' => '2',],
-                ['label' => '3 (1 rem)', 'value' => '3',],
-                ['label' => '4 (1.5 rem)', 'value' => '4',],
-                ['label' => '5 (3 rem)', 'value' => '5',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_container' => [
-        'label' => 'Container',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->container_'.$extconf['container'],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'no container', 'value' => '0',],
-                ['label' => 'container', 'value' => 'container',],
-                ['label' => 'container-fluid', 'value' => 'container-fluid',],
-                ['label' => 'container-fluid px-0', 'value' => 'container-fluid px-0',],
-                ['label' => 'container-sm (< 576px)', 'value' => 'container-sm',],
-                ['label' => 'container-md (≥ 576px)', 'value' => 'container-md',],
-                ['label' => 'container-lg (≥ 768px)', 'value' => 'container-lg',],
-                ['label' => 'container-xl (≥ 992px)', 'value' => 'container-xl',],
-                ['label' => 'container-xxl (≥ 1200px)', 'value' => 'container-xxl',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_flexform' => [
-        'exclude' => 1,
-        'l10n_display' => 'hideDiff',
-        'label' => ' ',
-        'config' => [
-            'type' => 'flex',
-            'ds_pointerField' => 'CType',
-            'ds' => [
-                'default' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Bootstrap.xml',
-                't3sbs_card' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/CardSetting.xml',
-                't3sbs_toast' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/ToastSetting.xml',
-                't3sbs_carousel' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Carousel.xml',
-                't3sbs_button' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Button.xml',
-                't3sbs_mediaobject' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Mediaobject.xml',
-                'table' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Table.xml',
-                'two_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/TwoColumns.xml',
-                'three_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/ThreeColumns.xml',
-                'four_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/FourColumns.xml',
-                'six_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/SixColumns.xml',
-                'card_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/CardWrapper.xml',
-                'button_group' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Buttongroup.xml',
-                'autoLayout_row' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/AutoLayoutRow.xml',
-                'background_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/BackgroundWrapper.xml',
-                'parallax_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/ParallaxWrapper.xml',
-                'container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Container.xml',
-                'carousel_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/CarouselContainer.xml',
-                'collapsible_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/CollapseContainer.xml',
-                'collapsible_accordion' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Collapse.xml',
-                'modal' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Modal.xml',
-                'tabs_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Tabs.xml',
-                'tabs_tab' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/TabsTab.xml',
-                'masonry_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/MasonryWrapper.xml',
-                'swiper_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/SwiperContainer.xml',
-                'toast_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/ToastContainer.xml',
-                'row_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/RowColumns.xml',
-            ]
-        ]
-    ],
-    'tx_t3sbootstrap_extra_class' => [
-        'label'  => 'Extra Class',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'input',
-            'size' => 35
-        ]
-    ],
-    'tx_t3sbootstrap_extra_style' => [
-        'label'  => 'Extra Style',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'input',
-            'size' => 35
-        ]
-    ],
-    'tx_t3sbootstrap_bgcolor' => [
-        'label' => 'Background color',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
-        'config' => [
-            'type' => 'color',
-            'size' => 20
+        'tx_t3sbootstrap_header_sectionMenu' => [
+                'label' => 'Section Menu Text',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'input',
+                        'size' => 40,
+                        'eval' => 'trim',
+                ],
         ],
-    ],
-    'tx_t3sbootstrap_inTextImgColumns' => [
-        'label' => 'Gallery columns',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 1, 'value' => 1,],
-                ['label' => 2, 'value' => 2,],
-                ['label' => 3, 'value' => 3,],
-                ['label' => 4, 'value' => 4,],
-                ['label' => 5, 'value' => 5,],
-                ['label' => 6, 'value' => 6,],
-                ['label' => 7, 'value' => 7,],
-                ['label' => 8, 'value' => 8,],
-                ['label' => 9, 'value' => 9,],
-                ['label' => 10, 'value' => 10,],
-                ['label' => 11, 'value' => 11,],
-                ['label' => 12, 'value' => 12,],
-            ],
-            'default' => 4
-        ]
-    ],
-    'tx_t3sbootstrap_bgopacity' => [
-        'label' => 'Opacity (background)',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
-        'config' => [
-                'type' => 'number',
-                'format' => 'decimal',
-                'range' => [
-                    'lower' => 0,
-                    'upper' => 1
+        'tx_t3sbootstrap_padding_sides' => [
+                'label' => 'Padding spacing side',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'no padding', 'value' => '',],
+                                ['label' => 'padding on all 4 sides', 'value' => 'blank',],
+                                ['label' => 'padding-top', 'value' => 't',],
+                                ['label' => 'padding-bottom', 'value' => 'b',],
+                                ['label' => 'padding-left', 'value' => 's',],
+                                ['label' => 'padding-right', 'value' => 'e',],
+                                ['label' => 'padding-left and -right', 'value' => 'x',],
+                                ['label' => 'padding-top and -bottom', 'value' => 'y',],
+                        ],
+                        'default' => ''
+                ]
+        ],
+        'tx_t3sbootstrap_padding_size' => [
+                'label' => 'Padding spacing size',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => '0', 'value' => '0',],
+                                ['label' => '1 (.25 rem)', 'value' => '1',],
+                                ['label' => '2 (.5 rem)', 'value' => '2',],
+                                ['label' => '3 (1 rem)', 'value' => '3',],
+                                ['label' => '4 (1.5 rem)', 'value' => '4',],
+                                ['label' => '5 (3 rem)', 'value' => '5',],
+                        ],
+                        'default' => ''
+                ]
+        ],
+        'tx_t3sbootstrap_margin_sides' => [
+                'label' => 'Margin spacing side',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'no margin', 'value' => '',],
+                                ['label' => 'margin on all 4 sides', 'value' => 'blank',],
+                                ['label' => 'margin-top', 'value' => 't',],
+                                ['label' => 'margin-bottom', 'value' => 'b',],
+                                ['label' => 'margin-left', 'value' => 's',],
+                                ['label' => 'margin-right', 'value' => 'e',],
+                                ['label' => 'margin-left and -right', 'value' => 'x',],
+                                ['label' => 'margin-top and -bottom', 'value' => 'y',],
+                        ],
+                        'default' => ''
+                ]
+        ],
+        'tx_t3sbootstrap_margin_size' => [
+                'label' => 'Margin spacing size',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->spacing_'.$extconf['spacing'],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => '0','value' => '0',],
+                                ['label' => '1 (.25 rem)', 'value' => '1',],
+                                ['label' => '2 (.5 rem)', 'value' => '2',],
+                                ['label' => '3 (1 rem)', 'value' => '3',],
+                                ['label' => '4 (1.5 rem)', 'value' => '4',],
+                                ['label' => '5 (3 rem)', 'value' => '5',],
+                        ],
+                        'default' => ''
+                ]
+        ],
+        'tx_t3sbootstrap_container' => [
+                'label' => 'Container',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->container_'.$extconf['container'],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'no container', 'value' => '0',],
+                                ['label' => 'container', 'value' => 'container',],
+                                ['label' => 'container-fluid', 'value' => 'container-fluid',],
+                                ['label' => 'container-fluid px-0', 'value' => 'container-fluid px-0',],
+                                ['label' => 'container-sm (< 576px)', 'value' => 'container-sm',],
+                                ['label' => 'container-md (≥ 576px)', 'value' => 'container-md',],
+                                ['label' => 'container-lg (≥ 768px)', 'value' => 'container-lg',],
+                                ['label' => 'container-xl (≥ 992px)', 'value' => 'container-xl',],
+                                ['label' => 'container-xxl (≥ 1200px)', 'value' => 'container-xxl',],
+                        ],
+                        'default' => ''
+                ]
+        ],
+        'tx_t3sbootstrap_flexform' => [
+                'exclude' => 1,
+                'l10n_display' => 'hideDiff',
+                'label' => ' ',
+                'config' => [
+                        'type' => 'flex',
+                        'ds_pointerField' => 'CType',
+                        'ds' => [
+                                'default' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Bootstrap.xml',
+                                't3sbs_card' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/CardSetting.xml',
+                                't3sbs_toast' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/ToastSetting.xml',
+                                't3sbs_carousel' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Carousel.xml',
+                                't3sbs_button' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Button.xml',
+                                't3sbs_mediaobject' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Mediaobject.xml',
+                                'table' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Table.xml',
+                                'two_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/TwoColumns.xml',
+                                'three_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/ThreeColumns.xml',
+                                'four_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/FourColumns.xml',
+                                'six_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/SixColumns.xml',
+                                'card_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/CardWrapper.xml',
+                                'button_group' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Buttongroup.xml',
+                                'autoLayout_row' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/AutoLayoutRow.xml',
+                                'background_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/BackgroundWrapper.xml',
+                                'parallax_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/ParallaxWrapper.xml',
+                                'container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Container.xml',
+                                'carousel_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/CarouselContainer.xml',
+                                'collapsible_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/CollapseContainer.xml',
+                                'collapsible_accordion' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Collapse.xml',
+                                'modal' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Modal.xml',
+                                'tabs_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/Tabs.xml',
+                                'tabs_tab' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/TabsTab.xml',
+                                'masonry_wrapper' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/MasonryWrapper.xml',
+                                'swiper_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/SwiperContainer.xml',
+                                'toast_container' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/ToastContainer.xml',
+                                'row_columns' => 'FILE:EXT:t3sbootstrap/Configuration/FlexForms/Container/RowColumns.xml',
+                        ]
+                ]
+        ],
+        'tx_t3sbootstrap_extra_class' => [
+                'label'  => 'Extra Class',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'input',
+                        'size' => 35
+                ]
+        ],
+        'tx_t3sbootstrap_extra_style' => [
+                'label'  => 'Extra Style',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'input',
+                        'size' => 35
+                ]
+        ],
+        'tx_t3sbootstrap_bgcolor' => [
+                'label' => 'Background color',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
+                'config' => [
+                        'type' => 'color',
+                        'size' => 20
                 ],
-                'slider' => [
-                'step' => 0.1,
-                'width' => 200
-            ],
-            'default' => 1
         ],
-    ],
-    'tx_t3sbootstrap_contextcolor' => [
-        'label' => 'Context color',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'none', 'value' => '',],
-                ['label' => 'primary', 'value' => 'primary',],
-                ['label' => 'secondary', 'value' => 'secondary',],
-                ['label' => 'success', 'value' => 'success',],
-                ['label' => 'info', 'value' => 'info',],
-                ['label' => 'warning', 'value' => 'warning',],
-                ['label' => 'danger', 'value' => 'danger',],
-                ['label' => 'light', 'value' => 'light',],
-                ['label' => 'dark', 'value' => 'dark',],
-                ['label' => 'body', 'value' => 'body',],
-                ['label' => 'transparent', 'value' => 'transparent',],
-                ['label' => 'custom 1', 'value' => 'customOne',],
-                ['label' => 'custom 2', 'value' => 'customTwo',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_textcolor' => [
-        'label' => 'Text color',
-        'exclude' => 1,
-        'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'default','value' => '',],
-                ['label' => 'white', 'value' => 'white',],
-                ['label' => 'muted', 'value' => 'muted',],
-                ['label' => 'secondary', 'value' => 'secondary',],
-                ['label' => 'primary', 'value' => 'primary',],
-                ['label' => 'success', 'value' => 'success',],
-                ['label' => 'info', 'value' => 'info',],
-                ['label' => 'warning', 'value' => 'warning',],
-                ['label' => 'danger', 'value' => 'danger',],
-                ['label' => 'light', 'value' => 'light',],
-                ['label' => 'dark', 'value' => 'dark',],
-                ['label' => 'body', 'value' => 'body',],
-                ['label' => 'transparent', 'value' => 'transparent',],
-                ['label' => 'custom 1', 'value' => 'customOne',],
-                ['label' => 'custom 2', 'value' => 'customTwo',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_inTextImgRowWidth' => [
-        'label' => 'Gallery row width in %',
-        'exclude' => 1,
-        'displayCond' => [
-             'OR' => [
-                'FIELD:CType:=:textpic',
-                'FIELD:CType:=:textmedia',
-                'FIELD:CType:=:t3sbs_mediaobject',
-                'FIELD:CType:=:t3sbs_card',
-                'FIELD:CType:=:t3sbs_toast',
-                'FIELD:CType:=:t3sbs_gallery',
-             ],
+        'tx_t3sbootstrap_inTextImgColumns' => [
+                'label' => 'Gallery columns',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 1, 'value' => 1,],
+                                ['label' => 2, 'value' => 2,],
+                                ['label' => 3, 'value' => 3,],
+                                ['label' => 4, 'value' => 4,],
+                                ['label' => 5, 'value' => 5,],
+                                ['label' => 6, 'value' => 6,],
+                                ['label' => 7, 'value' => 7,],
+                                ['label' => 8, 'value' => 8,],
+                                ['label' => 9, 'value' => 9,],
+                                ['label' => 10, 'value' => 10,],
+                                ['label' => 11, 'value' => 11,],
+                                ['label' => 12, 'value' => 12,],
+                        ],
+                        'default' => 4
+                ]
         ],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'auto', 'value' => 'auto',],
-                ['label' => 25, 'value' => 'w-25',],
-                ['label' => 33, 'value' => 'w-33',],
-                ['label' => 50, 'value' => 'w-50',],
-                ['label' => 66, 'value' => 'w-66',],
-                ['label' => 75, 'value' => 'w-75',],
-                ['label' => 100, 'value' => 'w-100',],
-                ['label' => 'none', 'value' => 'none',],
-            ],
-            'default' => 'auto'
-        ]
-    ],
-    'tx_t3sbootstrap_gutters' => [
-        'label' => 'Horizontal gutters',
-        'exclude' => 1,
-        'description' => 'INFO: https://getbootstrap.com/docs/5.3/layout/gutters/#horizontal-gutters',
-        'displayCond' => [
-             'OR' => [
-                'FIELD:CType:=:image',
-                'FIELD:CType:=:textpic',
-                'FIELD:CType:=:textmedia',
-                'FIELD:CType:=:t3sbs_gallery',
-             ],
+        'tx_t3sbootstrap_bgopacity' => [
+                'label' => 'Opacity (background)',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
+                'config' => [
+                                'type' => 'number',
+                                'format' => 'decimal',
+                                'range' => [
+                                        'lower' => 0,
+                                        'upper' => 1
+                                ],
+                                'slider' => [
+                                'step' => 0.1,
+                                'width' => 200
+                        ],
+                        'default' => 1
+                ],
         ],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'gx-0 (no gutters)', 'value' => 'gx-0',],
-                ['label' => 'gx-1', 'value' => 'gx-1',],
-                ['label' => 'gx-2', 'value' => 'gx-2',],
-                ['label' => 'gx-3', 'value' => 'gx-3',],
-                ['label' => 'gx-4 (default)', 'value' => 'gx-4',],
-                ['label' => 'gx-5', 'value' => 'gx-5',],
-            ],
-            'default' => 'gx-4'
-        ]
-    ],
-    'tx_t3sbootstrap_verticalgutters' => [
-        'label' => 'Vertical gutters',
-        'exclude' => 1,
-        'description' => 'INFO: https://getbootstrap.com/docs/5.3/layout/gutters/#vertical-gutters',
-        'displayCond' => [
-             'OR' => [
-                'FIELD:CType:=:image',
-                'FIELD:CType:=:textpic',
-                'FIELD:CType:=:textmedia',
-                'FIELD:CType:=:t3sbs_gallery',
-             ],
+        'tx_t3sbootstrap_contextcolor' => [
+                'label' => 'Context color',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'none', 'value' => '',],
+                                ['label' => 'primary', 'value' => 'primary',],
+                                ['label' => 'secondary', 'value' => 'secondary',],
+                                ['label' => 'success', 'value' => 'success',],
+                                ['label' => 'info', 'value' => 'info',],
+                                ['label' => 'warning', 'value' => 'warning',],
+                                ['label' => 'danger', 'value' => 'danger',],
+                                ['label' => 'light', 'value' => 'light',],
+                                ['label' => 'dark', 'value' => 'dark',],
+                                ['label' => 'body', 'value' => 'body',],
+                                ['label' => 'transparent', 'value' => 'transparent',],
+                                ['label' => 'custom 1', 'value' => 'customOne',],
+                                ['label' => 'custom 2', 'value' => 'customTwo',],
+                        ],
+                        'default' => ''
+                ]
         ],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'gy-0 (no gutters)', 'value' => 'mb-0',],
-                ['label' => 'gy-1', 'value' => 'mb-1',],
-                ['label' => 'gy-2', 'value' => 'mb-2',],
-                ['label' => 'gy-3', 'value' => 'mb-3',],
-                ['label' => 'gy-4 (default)', 'value' => 'mb-4',],
-                ['label' => 'gy-5', 'value' => 'mb-5',],
-            ],
-            'default' => 'mb-4'
-        ]
-    ],
-    'tx_t3sbootstrap_bordercolor' => [
-        'label' => 'Border color',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'default', 'value' => '',],
-                ['label' => 'white', 'value' => 'white',],
-                ['label' => 'muted', 'value' => 'muted',],
-                ['label' => 'secondary', 'value' => 'secondary',],
-                ['label' => 'primary', 'value' => 'primary',],
-                ['label' => 'success', 'value' => 'success',],
-                ['label' => 'info', 'value' => 'info',],
-                ['label' => 'warning', 'value' => 'warning',],
-                ['label' => 'danger', 'value' => 'danger',],
-                ['label' => 'light', 'value' => 'light',],
-                ['label' => 'dark', 'value' => 'dark',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_image_ratio' => [
-        'label' => 'Image Ratio',
-        'exclude' => 1,
-        'displayCond' => [
-            'AND' => [
-                'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->ratio_'.$extconf['ratio'],
-                'OR' => [
-                    'FIELD:CType:=:textpic',
-                    'FIELD:CType:=:textmedia',
-                    'FIELD:CType:=:t3sbs_mediaobject',
-                    'FIELD:CType:=:t3sbs_card',
-                    'FIELD:CType:=:t3sbs_toast',
-                    'FIELD:CType:=:t3sbs_gallery',
+        'tx_t3sbootstrap_textcolor' => [
+                'label' => 'Text color',
+                'exclude' => 1,
+                'displayCond' => 'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->color_'.$extconf['color'],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'default','value' => '',],
+                                ['label' => 'white', 'value' => 'white',],
+                                ['label' => 'muted', 'value' => 'muted',],
+                                ['label' => 'secondary', 'value' => 'secondary',],
+                                ['label' => 'primary', 'value' => 'primary',],
+                                ['label' => 'success', 'value' => 'success',],
+                                ['label' => 'info', 'value' => 'info',],
+                                ['label' => 'warning', 'value' => 'warning',],
+                                ['label' => 'danger', 'value' => 'danger',],
+                                ['label' => 'light', 'value' => 'light',],
+                                ['label' => 'dark', 'value' => 'dark',],
+                                ['label' => 'body', 'value' => 'body',],
+                                ['label' => 'transparent', 'value' => 'transparent',],
+                                ['label' => 'custom 1', 'value' => 'customOne',],
+                                ['label' => 'custom 2', 'value' => 'customTwo',],
+                        ],
+                        'default' => ''
                 ]
-            ]
         ],
-        'config' => [
-            'type' => 'select',
-            'renderType' => 'selectSingle',
-            'items' => [
-                ['label' => 'none', 'value' => '',],
-                ['label' => '1:1', 'value' => '1:1',],
-                ['label' => '2:1', 'value' => '2:1',],
-                ['label' => '4:3', 'value' => '4:3',],
-                ['label' => '3:2', 'value' => '3:2',],
-                ['label' => '16:9', 'value' => '16:9',],
-                ['label' => '21:9', 'value' => '21:9',],
-            ],
-            'default' => ''
-        ]
-    ],
-    'tx_t3sbootstrap_image_orig' => [
-        'exclude' => 1,
-        'label' => 'Use Original Image',
-        'displayCond' => [
-            'AND' => [
-                'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->ratio_'.$extconf['ratio'],
-                'OR' => [
-                    'FIELD:CType:=:textpic',
-                    'FIELD:CType:=:textmedia',
-                    'FIELD:CType:=:t3sbs_mediaobject',
-                    'FIELD:CType:=:t3sbs_card',
-                    'FIELD:CType:=:t3sbs_toast',
-                    'FIELD:CType:=:t3sbs_gallery',
+        'tx_t3sbootstrap_inTextImgRowWidth' => [
+                'label' => 'Gallery row width in %',
+                'exclude' => 1,
+                'displayCond' => [
+                         'OR' => [
+                                'FIELD:CType:=:textpic',
+                                'FIELD:CType:=:textmedia',
+                                'FIELD:CType:=:t3sbs_mediaobject',
+                                'FIELD:CType:=:t3sbs_card',
+                                'FIELD:CType:=:t3sbs_toast',
+                                'FIELD:CType:=:t3sbs_gallery',
+                         ],
+                ],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'auto', 'value' => 'auto',],
+                                ['label' => 25, 'value' => 'w-25',],
+                                ['label' => 33, 'value' => 'w-33',],
+                                ['label' => 50, 'value' => 'w-50',],
+                                ['label' => 66, 'value' => 'w-66',],
+                                ['label' => 75, 'value' => 'w-75',],
+                                ['label' => 100, 'value' => 'w-100',],
+                                ['label' => 'none', 'value' => 'none',],
+                        ],
+                        'default' => 'auto'
                 ]
-            ]
         ],
-        'config' => [
-            'type' => 'check'
-        ]
-    ],
-    'tx_t3sbootstrap_animateCss' => [
-        'exclude' => 1,
-        'l10n_display' => 'hideDiff',
-        'label' => 'Animate.css',
-        'config' => [
-            'type' => 'select',
-            'items' => [
-                ['label' => 'None', 'value' => '0',],
-                ['label' => 'bounce', 'value' => 'bounce',],
-                ['label' => 'flash', 'value' => 'flash',],
-                ['label' => 'pulse', 'value' => 'pulse',],
-                ['label' => 'rubberBand', 'value' => 'rubberBand',],
-                ['label' => 'shake', 'value' => 'shake',],
-                ['label' => 'headShake', 'value' => 'headShake',],
-                ['label' => 'swing', 'value' => 'swing',],
-                ['label' => 'tada', 'value' => 'tada',],
-                ['label' => 'jello', 'value' => 'jello',],
-                ['label' => 'bounceIn', 'value' => 'bounceIn',],
-                ['label' => 'bounceInDown', 'value' => 'bounceInDown',],
-                ['label' => 'bounceInLeft', 'value' => 'bounceInLeft',],
-                ['label' => 'bounceInRight', 'value' => 'bounceInRight',],
-                ['label' => 'bounceInUp', 'value' => 'bounceInUp',],
-                ['label' => 'bounceOut', 'value' => 'bounceOut',],
-                ['label' => 'bounceOutDown', 'value' => 'bounceOutDown',],
-                ['label' => 'bounceOutLeft', 'value' => 'bounceOutLeft',],
-                ['label' => 'bounceOutRight', 'value' => 'bounceOutRight',],
-                ['label' => 'bounceOutUp', 'value' => 'bounceOutUp',],
-                ['label' => 'fadeIn', 'value' => 'fadeIn',],
-                ['label' => 'fadeInDown', 'value' => 'fadeInDown',],
-                ['label' => 'fadeInDownBig', 'value' => 'fadeInDownBig',],
-                ['label' => 'fadeInLeft', 'value' => 'fadeInLeft',],
-                ['label' => 'fadeInLeftBig', 'value' => 'fadeInLeftBig',],
-                ['label' => 'fadeInRight', 'value' => 'fadeInRight',],
-                ['label' => 'fadeInRightBig', 'value' => 'fadeInRightBig',],
-                ['label' => 'fadeInUp', 'value' => 'fadeInUp',],
-                ['label' => 'fadeInUpBig', 'value' => 'fadeInUpBig',],
-                ['label' => 'fadeOut', 'value' => 'fadeOut',],
-                ['label' => 'fadeOutDown', 'value' => 'fadeOutDown',],
-                ['label' => 'fadeOutDownBig', 'value' => 'fadeOutDownBig',],
-                ['label' => 'fadeOutLeft', 'value' => 'fadeOutLeft',],
-                ['label' => 'fadeOutLeftBig', 'value' => 'fadeOutLeftBig',],
-                ['label' => 'fadeOutRight', 'value' => 'fadeOutRight',],
-                ['label' => 'fadeOutRightBig', 'value' => 'fadeOutRightBig',],
-                ['label' => 'fadeOutUp', 'value' => 'fadeOutUp',],
-                ['label' => 'fadeOutUpBig', 'value' => 'fadeOutUpBig',],
-                ['label' => 'flipInX', 'value' => 'flipInX',],
-                ['label' => 'flipInY', 'value' => 'flipInY',],
-                ['label' => 'flipOutX', 'value' => 'flipOutX',],
-                ['label' => 'flipOutY', 'value' => 'flipOutY',],
-                ['label' => 'lightSpeedIn', 'value' => 'lightSpeedIn',],
-                ['label' => 'lightSpeedOut', 'value' => 'lightSpeedOut',],
-                ['label' => 'rotateIn', 'value' => 'rotateIn',],
-                ['label' => 'rotateInDownLeft', 'value' => 'rotateInDownLeft',],
-                ['label' => 'rotateInDownRight', 'value' => 'rotateInDownRight',],
-                ['label' => 'rotateInUpLeft', 'value' => 'rotateInUpLeft',],
-                ['label' => 'rotateInUpRight', 'value' => 'rotateInUpRight',],
-                ['label' => 'rotateOut', 'value' => 'rotateOut',],
-                ['label' => 'rotateOutDownLeft', 'value' => 'rotateOutDownLeft',],
-                ['label' => 'rotateOutDownRight', 'value' => 'rotateOutDownRight',],
-                ['label' => 'rotateOutUpLeft', 'value' => 'rotateOutUpLeft',],
-                ['label' => 'rotateOutUpRight', 'value' => 'rotateOutUpRight',],
-                ['label' => 'hinge', 'value' => 'hinge',],
-                ['label' => 'rollIn', 'value' => 'rollIn',],
-                ['label' => 'rollOut', 'value' => 'rollOut',],
-                ['label' => 'zoomIn', 'value' => 'zoomIn',],
-                ['label' => 'zoomInDown', 'value' => 'zoomInDown',],
-                ['label' => 'zoomInLeft', 'value' => 'zoomInLeft',],
-                ['label' => 'zoomInRight', 'value' => 'zoomInRight',],
-                ['label' => 'zoomInUp', 'value' => 'zoomInUp',],
-                ['label' => 'zoomOut', 'value' => 'zoomOut',],
-                ['label' => 'zoomOutDown', 'value' => 'zoomOutDown',],
-                ['label' => 'zoomOutLeft', 'value' => 'zoomOutLeft',],
-                ['label' => 'zoomOutRight', 'value' => 'zoomOutRight',],
-                ['label' => 'zoomOutUp', 'value' => 'zoomOutUp',],
-                ['label' => 'slideInDown', 'value' => 'slideInDown',],
-                ['label' => 'slideInLeft', 'value' => 'slideInLeft',],
-                ['label' => 'slideInRight', 'value' => 'slideInRight',],
-                ['label' => 'slideInUp', 'value' => 'slideInUp',],
-                ['label' => 'slideOutDown', 'value' => 'slideOutDown',],
-                ['label' => 'slideOutLeft', 'value' => 'slideOutLeft',],
-                ['label' => 'slideOutRight', 'value' => 'slideOutRight',],
-                ['label' => 'slideOutUp', 'value' => 'slideOutUp',],
-            ],
-            'renderType' => 'selectSingle'
-        ]
-    ],
-    'tx_t3sbootstrap_animateCssRepeat' => [
-        'exclude' => 1,
-        'label' => 'Repeat',
-        'config' => [
-            'type' => 'check'
-        ]
-    ],
-    'tx_t3sbootstrap_animateCssDuration' => [
-        'label' => 'Duration in seconds',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'number',
-            'size' => 3
-        ]
-    ],
-    'tx_t3sbootstrap_animateCssDelay' => [
-        'label' => 'Delay in seconds',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'number',
-            'size' => 3
-        ]
-    ],
-    'tx_t3sbootstrap_sectionOrder' => [
-        'label' => 'Custom order in section Menu',
-        'exclude' => 1,
-        'config' => [
-            'type' => 'number',
-            'size' => 3
-        ]
-    ],
-    'tx_t3sbootstrap_bodytext' => [
-        'label' => 'Text bottom ',
-        'config' => [
-            'type' => 'text',
-            'cols' => 80,
-            'rows' => 15,
-            'softref' => 'typolink_tag,email[subst],url',
-            'search' => [
-                'andWhere' => '{#CType}=\'t3sbs_card\'',
-            ],
+        'tx_t3sbootstrap_gutters' => [
+                'label' => 'Horizontal gutters',
+                'exclude' => 1,
+                'description' => 'INFO: https://getbootstrap.com/docs/5.3/layout/gutters/#horizontal-gutters',
+                'displayCond' => [
+                         'OR' => [
+                                'FIELD:CType:=:image',
+                                'FIELD:CType:=:textpic',
+                                'FIELD:CType:=:textmedia',
+                                'FIELD:CType:=:t3sbs_gallery',
+                         ],
+                ],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'gx-0 (no gutters)', 'value' => 'gx-0',],
+                                ['label' => 'gx-1', 'value' => 'gx-1',],
+                                ['label' => 'gx-2', 'value' => 'gx-2',],
+                                ['label' => 'gx-3', 'value' => 'gx-3',],
+                                ['label' => 'gx-4 (default)', 'value' => 'gx-4',],
+                                ['label' => 'gx-5', 'value' => 'gx-5',],
+                        ],
+                        'default' => 'gx-4'
+                ]
         ],
-    ],
-    'tx_t3sbootstrap_cardheader' => [
-        'label' => 'Card Header',
-        'config' => [
-            'type' => 'input',
-            'size' => 50,
-            'max' => 255,
+        'tx_t3sbootstrap_verticalgutters' => [
+                'label' => 'Vertical gutters',
+                'exclude' => 1,
+                'description' => 'INFO: https://getbootstrap.com/docs/5.3/layout/gutters/#vertical-gutters',
+                'displayCond' => [
+                         'OR' => [
+                                'FIELD:CType:=:image',
+                                'FIELD:CType:=:textpic',
+                                'FIELD:CType:=:textmedia',
+                                'FIELD:CType:=:t3sbs_gallery',
+                         ],
+                ],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'gy-0 (no gutters)', 'value' => 'mb-0',],
+                                ['label' => 'gy-1', 'value' => 'mb-1',],
+                                ['label' => 'gy-2', 'value' => 'mb-2',],
+                                ['label' => 'gy-3', 'value' => 'mb-3',],
+                                ['label' => 'gy-4 (default)', 'value' => 'mb-4',],
+                                ['label' => 'gy-5', 'value' => 'mb-5',],
+                        ],
+                        'default' => 'mb-4'
+                ]
         ],
-    ],
-    'tx_t3sbootstrap_cardfooter' => [
-        'label' => 'Card Header',
-        'config' => [
-            'type' => 'input',
-            'size' => 50,
-            'max' => 255,
+        'tx_t3sbootstrap_bordercolor' => [
+                'label' => 'Border color',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'default', 'value' => '',],
+                                ['label' => 'white', 'value' => 'white',],
+                                ['label' => 'muted', 'value' => 'muted',],
+                                ['label' => 'secondary', 'value' => 'secondary',],
+                                ['label' => 'primary', 'value' => 'primary',],
+                                ['label' => 'success', 'value' => 'success',],
+                                ['label' => 'info', 'value' => 'info',],
+                                ['label' => 'warning', 'value' => 'warning',],
+                                ['label' => 'danger', 'value' => 'danger',],
+                                ['label' => 'light', 'value' => 'light',],
+                                ['label' => 'dark', 'value' => 'dark',],
+                        ],
+                        'default' => ''
+                ]
         ],
-    ],
-    'tx_t3sbootstrap_list_item' => [
-        'label' => 'List Group',
-        'config' => [
-            'type' => 'inline',
-            'foreign_table' => 'tx_t3sbootstrap_list_item_inline',
-            'foreign_field' => 'parentid',
-            'foreign_table_field' => 'parenttable',
+        'tx_t3sbootstrap_image_ratio' => [
+                'label' => 'Image Ratio',
+                'exclude' => 1,
+                'displayCond' => [
+                        'AND' => [
+                                'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->ratio_'.$extconf['ratio'],
+                                'OR' => [
+                                        'FIELD:CType:=:textpic',
+                                        'FIELD:CType:=:textmedia',
+                                        'FIELD:CType:=:t3sbs_mediaobject',
+                                        'FIELD:CType:=:t3sbs_card',
+                                        'FIELD:CType:=:t3sbs_toast',
+                                        'FIELD:CType:=:t3sbs_gallery',
+                                ]
+                        ]
+                ],
+                'config' => [
+                        'type' => 'select',
+                        'renderType' => 'selectSingle',
+                        'items' => [
+                                ['label' => 'none', 'value' => '',],
+                                ['label' => '1:1', 'value' => '1:1',],
+                                ['label' => '2:1', 'value' => '2:1',],
+                                ['label' => '4:3', 'value' => '4:3',],
+                                ['label' => '3:2', 'value' => '3:2',],
+                                ['label' => '16:9', 'value' => '16:9',],
+                                ['label' => '21:9', 'value' => '21:9',],
+                        ],
+                        'default' => ''
+                ]
         ],
-    ],
-    'tx_t3sbootstrap_upgrade_card' => [
-        'label' => 'Upgrade wizard',
-        'config' => [
-            'type' => 'check',
-        ]
-    ],
+        'tx_t3sbootstrap_image_orig' => [
+                'exclude' => 1,
+                'label' => 'Use Original Image',
+                'displayCond' => [
+                        'AND' => [
+                                'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->ratio_'.$extconf['ratio'],
+                                'OR' => [
+                                        'FIELD:CType:=:textpic',
+                                        'FIELD:CType:=:textmedia',
+                                        'FIELD:CType:=:t3sbs_mediaobject',
+                                        'FIELD:CType:=:t3sbs_card',
+                                        'FIELD:CType:=:t3sbs_toast',
+                                        'FIELD:CType:=:t3sbs_gallery',
+                                ]
+                        ]
+                ],
+                'config' => [
+                        'type' => 'check',
+                        'renderType' => 'checkboxToggle'
+                ]
+        ],
+
+        'tx_t3sbootstrap_zoom_orig' => [
+                'exclude' => 1,
+                'label' => 'Use Original Image for Lightbox',
+                'description' => 'Only useful with image manipulation (cropping)',
+                'displayCond' => [
+                        'AND' => [
+                                'USER:T3SBS\T3sbootstrap\UserFunction\TcaMatcher->ratio_'.$extconf['ratio'],
+                                'OR' => [
+                                        'FIELD:CType:=:textpic',
+                                        'FIELD:CType:=:textmedia',
+                                        'FIELD:CType:=:t3sbs_mediaobject',
+                                        'FIELD:CType:=:t3sbs_card',
+                                        'FIELD:CType:=:t3sbs_toast',
+                                        'FIELD:CType:=:t3sbs_gallery',
+                                ]
+                        ]
+                ],
+                'config' => [
+                        'type' => 'check',
+                        'renderType' => 'checkboxToggle'
+                ]
+        ],
+
+        'tx_t3sbootstrap_animateCss' => [
+                'exclude' => 1,
+                'l10n_display' => 'hideDiff',
+                'label' => 'Animate.css',
+                'config' => [
+                        'type' => 'select',
+                        'items' => [
+                                ['label' => 'None', 'value' => '0',],
+                                ['label' => 'bounce', 'value' => 'bounce',],
+                                ['label' => 'flash', 'value' => 'flash',],
+                                ['label' => 'pulse', 'value' => 'pulse',],
+                                ['label' => 'rubberBand', 'value' => 'rubberBand',],
+                                ['label' => 'shake', 'value' => 'shake',],
+                                ['label' => 'headShake', 'value' => 'headShake',],
+                                ['label' => 'swing', 'value' => 'swing',],
+                                ['label' => 'tada', 'value' => 'tada',],
+                                ['label' => 'jello', 'value' => 'jello',],
+                                ['label' => 'bounceIn', 'value' => 'bounceIn',],
+                                ['label' => 'bounceInDown', 'value' => 'bounceInDown',],
+                                ['label' => 'bounceInLeft', 'value' => 'bounceInLeft',],
+                                ['label' => 'bounceInRight', 'value' => 'bounceInRight',],
+                                ['label' => 'bounceInUp', 'value' => 'bounceInUp',],
+                                ['label' => 'bounceOut', 'value' => 'bounceOut',],
+                                ['label' => 'bounceOutDown', 'value' => 'bounceOutDown',],
+                                ['label' => 'bounceOutLeft', 'value' => 'bounceOutLeft',],
+                                ['label' => 'bounceOutRight', 'value' => 'bounceOutRight',],
+                                ['label' => 'bounceOutUp', 'value' => 'bounceOutUp',],
+                                ['label' => 'fadeIn', 'value' => 'fadeIn',],
+                                ['label' => 'fadeInDown', 'value' => 'fadeInDown',],
+                                ['label' => 'fadeInDownBig', 'value' => 'fadeInDownBig',],
+                                ['label' => 'fadeInLeft', 'value' => 'fadeInLeft',],
+                                ['label' => 'fadeInLeftBig', 'value' => 'fadeInLeftBig',],
+                                ['label' => 'fadeInRight', 'value' => 'fadeInRight',],
+                                ['label' => 'fadeInRightBig', 'value' => 'fadeInRightBig',],
+                                ['label' => 'fadeInUp', 'value' => 'fadeInUp',],
+                                ['label' => 'fadeInUpBig', 'value' => 'fadeInUpBig',],
+                                ['label' => 'fadeOut', 'value' => 'fadeOut',],
+                                ['label' => 'fadeOutDown', 'value' => 'fadeOutDown',],
+                                ['label' => 'fadeOutDownBig', 'value' => 'fadeOutDownBig',],
+                                ['label' => 'fadeOutLeft', 'value' => 'fadeOutLeft',],
+                                ['label' => 'fadeOutLeftBig', 'value' => 'fadeOutLeftBig',],
+                                ['label' => 'fadeOutRight', 'value' => 'fadeOutRight',],
+                                ['label' => 'fadeOutRightBig', 'value' => 'fadeOutRightBig',],
+                                ['label' => 'fadeOutUp', 'value' => 'fadeOutUp',],
+                                ['label' => 'fadeOutUpBig', 'value' => 'fadeOutUpBig',],
+                                ['label' => 'flipInX', 'value' => 'flipInX',],
+                                ['label' => 'flipInY', 'value' => 'flipInY',],
+                                ['label' => 'flipOutX', 'value' => 'flipOutX',],
+                                ['label' => 'flipOutY', 'value' => 'flipOutY',],
+                                ['label' => 'lightSpeedIn', 'value' => 'lightSpeedIn',],
+                                ['label' => 'lightSpeedOut', 'value' => 'lightSpeedOut',],
+                                ['label' => 'rotateIn', 'value' => 'rotateIn',],
+                                ['label' => 'rotateInDownLeft', 'value' => 'rotateInDownLeft',],
+                                ['label' => 'rotateInDownRight', 'value' => 'rotateInDownRight',],
+                                ['label' => 'rotateInUpLeft', 'value' => 'rotateInUpLeft',],
+                                ['label' => 'rotateInUpRight', 'value' => 'rotateInUpRight',],
+                                ['label' => 'rotateOut', 'value' => 'rotateOut',],
+                                ['label' => 'rotateOutDownLeft', 'value' => 'rotateOutDownLeft',],
+                                ['label' => 'rotateOutDownRight', 'value' => 'rotateOutDownRight',],
+                                ['label' => 'rotateOutUpLeft', 'value' => 'rotateOutUpLeft',],
+                                ['label' => 'rotateOutUpRight', 'value' => 'rotateOutUpRight',],
+                                ['label' => 'hinge', 'value' => 'hinge',],
+                                ['label' => 'rollIn', 'value' => 'rollIn',],
+                                ['label' => 'rollOut', 'value' => 'rollOut',],
+                                ['label' => 'zoomIn', 'value' => 'zoomIn',],
+                                ['label' => 'zoomInDown', 'value' => 'zoomInDown',],
+                                ['label' => 'zoomInLeft', 'value' => 'zoomInLeft',],
+                                ['label' => 'zoomInRight', 'value' => 'zoomInRight',],
+                                ['label' => 'zoomInUp', 'value' => 'zoomInUp',],
+                                ['label' => 'zoomOut', 'value' => 'zoomOut',],
+                                ['label' => 'zoomOutDown', 'value' => 'zoomOutDown',],
+                                ['label' => 'zoomOutLeft', 'value' => 'zoomOutLeft',],
+                                ['label' => 'zoomOutRight', 'value' => 'zoomOutRight',],
+                                ['label' => 'zoomOutUp', 'value' => 'zoomOutUp',],
+                                ['label' => 'slideInDown', 'value' => 'slideInDown',],
+                                ['label' => 'slideInLeft', 'value' => 'slideInLeft',],
+                                ['label' => 'slideInRight', 'value' => 'slideInRight',],
+                                ['label' => 'slideInUp', 'value' => 'slideInUp',],
+                                ['label' => 'slideOutDown', 'value' => 'slideOutDown',],
+                                ['label' => 'slideOutLeft', 'value' => 'slideOutLeft',],
+                                ['label' => 'slideOutRight', 'value' => 'slideOutRight',],
+                                ['label' => 'slideOutUp', 'value' => 'slideOutUp',],
+                        ],
+                        'renderType' => 'selectSingle'
+                ]
+        ],
+        'tx_t3sbootstrap_animateCssRepeat' => [
+                'exclude' => 1,
+                'label' => 'Repeat',
+                'config' => [
+                        'type' => 'check'
+                ]
+        ],
+        'tx_t3sbootstrap_animateCssDuration' => [
+                'label' => 'Duration in seconds',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'number',
+                        'size' => 3
+                ]
+        ],
+        'tx_t3sbootstrap_animateCssDelay' => [
+                'label' => 'Delay in seconds',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'number',
+                        'size' => 3
+                ]
+        ],
+        'tx_t3sbootstrap_sectionOrder' => [
+                'label' => 'Custom order in section Menu',
+                'exclude' => 1,
+                'config' => [
+                        'type' => 'number',
+                        'size' => 3
+                ]
+        ],
+        'tx_t3sbootstrap_bodytext' => [
+                'label' => 'Text bottom ',
+                'config' => [
+                        'type' => 'text',
+                        'cols' => 80,
+                        'rows' => 15,
+                        'softref' => 'typolink_tag,email[subst],url',
+                        'search' => [
+                                'andWhere' => '{#CType}=\'t3sbs_card\'',
+                        ],
+                ],
+        ],
+        'tx_t3sbootstrap_cardheader' => [
+                'label' => 'Card Header',
+                'config' => [
+                        'type' => 'input',
+                        'size' => 50,
+                        'max' => 255,
+                ],
+        ],
+        'tx_t3sbootstrap_cardfooter' => [
+                'label' => 'Card Header',
+                'config' => [
+                        'type' => 'input',
+                        'size' => 50,
+                        'max' => 255,
+                ],
+        ],
+        'tx_t3sbootstrap_list_item' => [
+                'label' => 'List Group',
+                'config' => [
+                        'type' => 'inline',
+                        'foreign_table' => 'tx_t3sbootstrap_list_item_inline',
+                        'foreign_field' => 'parentid',
+                        'foreign_table_field' => 'parenttable',
+                ],
+        ],
+
 ];
 
 
@@ -788,38 +808,38 @@
  * Assets Inline
  */
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_assets'] = [
-    'showitem' => '
-    --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-        --palette--;;general,
-            header; Internal title (not displayed),
-    --div--;Java Script,
-        bodytext;JavaScript,
-        pi_flexform; Inline JavaScript Settings,
-    --div--;CSS,
-        tx_t3sbootstrap_bodytext;CSS,
-    --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-        --palette--;;hidden
-    ',
-    'columnsOverrides' => [
-        'bodytext' => [
-            'config' => [
-                'type' => 'text',
-                'format' => 'javascript',
-                'renderType' => 't3editor',
-                'wrap' => 'virtual',
-                'rows' => 15,
-            ],
-        ],
-        'tx_t3sbootstrap_bodytext' => [
-            'config' => [
-                'type' => 'text',
-                'renderType' => 't3editor',
-                'format' => 'css',
-                'rows' => 15,
-                'wrap' => 'virtual',
-            ],
+        'showitem' => '
+        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
+                --palette--;;general,
+                        header; Internal title (not displayed),
+        --div--;Java Script,
+                bodytext;JavaScript,
+                pi_flexform; Inline JavaScript Settings,
+        --div--;CSS,
+                tx_t3sbootstrap_bodytext;CSS,
+        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
+                --palette--;;hidden
+        ',
+        'columnsOverrides' => [
+                'bodytext' => [
+                        'config' => [
+                                'type' => 'text',
+                                'format' => 'javascript',
+                                'renderType' => 't3editor',
+                                'wrap' => 'virtual',
+                                'rows' => 15,
+                        ],
+                ],
+                'tx_t3sbootstrap_bodytext' => [
+                        'config' => [
+                                'type' => 'text',
+                                'renderType' => 't3editor',
+                                'format' => 'css',
+                                'rows' => 15,
+                                'wrap' => 'virtual',
+                        ],
+                ],
         ],
-    ],
 ];
 
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
@@ -833,34 +853,34 @@
  * Button - t3sbs_button
  */
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_button'] = [
-    'showitem' => '
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.headers;headers,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
-            --palette--;;language,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-            --palette--;;hidden,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,categories,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,rowDescription,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
-    '
+        'showitem' => '
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.headers;headers,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
+                        --palette--;;language,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
+                        --palette--;;hidden,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,categories,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,rowDescription,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
+        '
 ];
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_button']['columnsOverrides'] = [
-  'header_link' => [
-     'config' => [
-         'eval' => 'trim,required'
-     ]
-  ],
-  'header' => [
-     'config' => [
-         'eval' => 'trim,required'
-     ]
-  ],
+    'header_link' => [
+         'config' => [
+                 'eval' => 'trim,required'
+         ]
+    ],
+    'header' => [
+         'config' => [
+                 'eval' => 'trim,required'
+         ]
+    ],
 ];
 
 
@@ -868,39 +888,39 @@
  * Carousel item - t3sbs_carousel
  */
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_carousel'] = [
-    'showitem' => '
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.headers;headers,
-            bodytext;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext_formlabel,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.images,
-            assets,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,T3SFlex;tx_t3sbootstrap_flexform,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
-            --palette--;;language,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-            --palette--;;hidden,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,
-            categories,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,
-            rowDescription,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
-    ',
-    'columnsOverrides' => [
-        'bodytext' => [
-            'config' => [
-                'enableRichtext' => true
-            ]
-        ],
-        'assets' => [
-            'config' => [
-                'maxitems' => 1
-            ]
+        'showitem' => '
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.headers;headers,
+                        bodytext;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext_formlabel,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.images,
+                        assets,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,T3SFlex;tx_t3sbootstrap_flexform,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
+                        --palette--;;language,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
+                        --palette--;;hidden,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,
+                        categories,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,
+                        rowDescription,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
+        ',
+        'columnsOverrides' => [
+                'bodytext' => [
+                        'config' => [
+                                'enableRichtext' => true
+                        ]
+                ],
+                'assets' => [
+                        'config' => [
+                                'maxitems' => 1
+                        ]
+                ]
         ]
-    ]
 ];
 
 /***************
@@ -908,16 +928,16 @@
  */
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_mediaobject'] = $GLOBALS['TCA']['tt_content']['types']['textmedia'];
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_mediaobject']['columnsOverrides'] = [
-    'bodytext' => [
-        'config' => [
-            'enableRichtext' => true
-        ]
-    ],
-    'assets' => [
-        'config' => [
-            'maxitems' => 1
+        'bodytext' => [
+                'config' => [
+                        'enableRichtext' => true
+                ]
+        ],
+        'assets' => [
+                'config' => [
+                        'maxitems' => 1
+                ]
         ]
-    ]
 ];
 
 
@@ -925,50 +945,50 @@
  * Card - t3sbs_card
  */
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_card'] = [
-    'showitem' => '
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.headers;headers,
-        --div--;Content,pi_flexform;Card Content,
-            tx_t3sbootstrap_cardheader;Card Header,
-            bodytext;Text top,
-            tx_t3sbootstrap_list_item;List Group,
-            tx_t3sbootstrap_bodytext;Text bottom,
-            tx_t3sbootstrap_cardfooter;Card Footer,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.media,
-            assets,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.palette.mediaAdjustments;mediaAdjustments,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.palette.gallerySettings;gallerySettings,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.imagelinks;imagelinks,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
-            --palette--;;language,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-            --palette--;;hidden,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,categories,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,rowDescription,
-        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
-    ',
-    'columnsOverrides' => [
-        'bodytext' => [
-            'config' => [
-                'enableRichtext' => true
-            ]
-        ],
-        'tx_t3sbootstrap_bodytext' => [
-            'config' => [
-                'enableRichtext' => true
-            ]
-        ],
-        'assets' => [
-            'config' => [
-                'maxitems' => 2
-            ]
+        'showitem' => '
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.headers;headers,
+                --div--;Content,pi_flexform;Card Content,
+                        tx_t3sbootstrap_cardheader;Card Header,
+                        bodytext;Text top,
+                        tx_t3sbootstrap_list_item;List Group,
+                        tx_t3sbootstrap_bodytext;Text bottom,
+                        tx_t3sbootstrap_cardfooter;Card Footer,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.media,
+                        assets,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.palette.mediaAdjustments;mediaAdjustments,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.palette.gallerySettings;gallerySettings,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.imagelinks;imagelinks,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
+                        --palette--;;language,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
+                        --palette--;;hidden,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,categories,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,rowDescription,
+                --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
+        ',
+        'columnsOverrides' => [
+                'bodytext' => [
+                        'config' => [
+                                'enableRichtext' => true
+                        ]
+                ],
+                'tx_t3sbootstrap_bodytext' => [
+                        'config' => [
+                                'enableRichtext' => true
+                        ]
+                ],
+                'assets' => [
+                        'config' => [
+                                'maxitems' => 2
+                        ]
+                ]
         ]
-    ]
 ];
 
 
@@ -983,23 +1003,23 @@
  */
 // add extra column
 $GLOBALS['TCA']['tt_content']['columns']['bullets_type']['config']['items'] = [
-    ['label' => 'BS Inline list', 'value' => 2,],
-    ['label' => 'BS Unstyled list', 'value' => 3,],
-    ['label' => 'BS Listengruppen', 'value' => 4,],
-    ['label' => 'BS Definition list (use pipe "|")','value' => 5,],
+        ['label' => 'BS Inline list', 'value' => 2,],
+        ['label' => 'BS Unstyled list', 'value' => 3,],
+        ['label' => 'BS Listengruppen', 'value' => 4,],
+        ['label' => 'BS Definition list (use pipe "|")','value' => 5,],
 ];
 
 /***************
  * FluidTemplate
  */
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_fluidtemplate']['showitem'] = '
-        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
-    header;Data Variable (optional),
-    subheader;Path to your Fluid-Template,
-        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
-    --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access,
-        hidden;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:field.default.hidden,
-        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access
+                --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
+        header;Data Variable (optional),
+        subheader;Path to your Fluid-Template,
+                --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
+        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access,
+                hidden;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:field.default.hidden,
+                --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access
 ';
 
 
@@ -1007,22 +1027,22 @@
  * BS Image Gallery
  */
 $GLOBALS['TCA']['tt_content']['types']['t3sbs_gallery'] = [
-     'showitem' => '
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.header;header,rowDescription,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.media,assets,
-            LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:media.ALT.uploads_formlabel,
-            --linebreak--, file_collections;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:file_collections.ALT.uploads_formlabel,
-            --linebreak--, filelink_sorting,
-            --palette--;;mediaAdjustments,imagecols,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,
-             --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access,
-            hidden;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:field.default.hidden,
-            --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
-        --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.extended
-    '
+         'showitem' => '
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.header;header,rowDescription,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.media,assets,
+                        LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:media.ALT.uploads_formlabel,
+                        --linebreak--, file_collections;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:file_collections.ALT.uploads_formlabel,
+                        --linebreak--, filelink_sorting,
+                        --palette--;;mediaAdjustments,imagecols,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,
+                         --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.appearanceLinks;appearanceLinks,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access,
+                        hidden;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:field.default.hidden,
+                        --palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
+                --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.extended
+        '
 ];
 
 
@@ -1058,6 +1078,17 @@
     'after:tx_t3sbootstrap_bordercolor'
 );
 
+
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
+    'tt_content',
+    'imagelinks',
+    'tx_t3sbootstrap_zoom_orig',
+    'after: image_zoom'
+);
+
+
+
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
     'tt_content',
     'imageSettings',
@@ -1083,6 +1114,7 @@
     'after:tx_t3sbootstrap_gutters'
 );
 
+
 # add palette bootstrap etc
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
     'tt_content',
@@ -1134,41 +1166,41 @@
 }
 
 $GLOBALS['TCA']['tt_content']['palettes']['bsHeaderExtra'] = [
-  'showitem' => 'tx_t3sbootstrap_header_display, tx_t3sbootstrap_header_position, --linebreak--,
-  tx_t3sbootstrap_header_class, tx_t3sbootstrap_header_fontawesome'
+    'showitem' => 'tx_t3sbootstrap_header_display, tx_t3sbootstrap_header_position, --linebreak--,
+    tx_t3sbootstrap_header_class, tx_t3sbootstrap_header_fontawesome'
 ];
 
 $GLOBALS['TCA']['tt_content']['palettes']['bootstrapSpacing'] = [
-  'showitem' => 'tx_t3sbootstrap_padding_sides, tx_t3sbootstrap_padding_size, --linebreak--,
-  tx_t3sbootstrap_margin_sides, tx_t3sbootstrap_margin_size'
+    'showitem' => 'tx_t3sbootstrap_padding_sides, tx_t3sbootstrap_padding_size, --linebreak--,
+    tx_t3sbootstrap_margin_sides, tx_t3sbootstrap_margin_size'
 ];
 
 if ($extconf['extraStyle']) {
     $GLOBALS['TCA']['tt_content']['palettes']['bootstrap'] = [
-  'showitem' => 'tx_t3sbootstrap_extra_class,
-  --linebreak--, tx_t3sbootstrap_extra_style,
-  --linebreak--, tx_t3sbootstrap_container,
-  --linebreak--, tx_t3sbootstrap_flexform'
+    'showitem' => 'tx_t3sbootstrap_extra_class,
+    --linebreak--, tx_t3sbootstrap_extra_style,
+    --linebreak--, tx_t3sbootstrap_container,
+    --linebreak--, tx_t3sbootstrap_flexform'
 ];
 } else {
     $GLOBALS['TCA']['tt_content']['palettes']['bootstrap'] = [
-  'showitem' => 'tx_t3sbootstrap_extra_class,
-  --linebreak--, tx_t3sbootstrap_container,
-  --linebreak--, tx_t3sbootstrap_flexform'
+    'showitem' => 'tx_t3sbootstrap_extra_class,
+    --linebreak--, tx_t3sbootstrap_container,
+    --linebreak--, tx_t3sbootstrap_flexform'
 ];
 }
 
 $GLOBALS['TCA']['tt_content']['palettes']['bootstrapColor'] = [
-  'showitem' => 'tx_t3sbootstrap_contextcolor, tx_t3sbootstrap_bgcolor, --linebreak--, tx_t3sbootstrap_bgopacity, tx_t3sbootstrap_textcolor'
+    'showitem' => 'tx_t3sbootstrap_contextcolor, tx_t3sbootstrap_bgcolor, --linebreak--, tx_t3sbootstrap_bgopacity, tx_t3sbootstrap_textcolor'
 ];
 
 if ($extconf['animateCss']) {
     $GLOBALS['TCA']['tt_content']['palettes']['animate'] = [
-      'showitem' => 'tx_t3sbootstrap_animateCss,
-      tx_t3sbootstrap_animateCssDuration, --linebreak--,
-      tx_t3sbootstrap_animateCssDelay,
-      tx_t3sbootstrap_animateCssRepeat'
-    ];
+            'showitem' => 'tx_t3sbootstrap_animateCss,
+            tx_t3sbootstrap_animateCssDuration, --linebreak--,
+            tx_t3sbootstrap_animateCssDelay,
+            tx_t3sbootstrap_animateCssRepeat'
+        ];
 }
 
 if ($extconf['sectionOrder']) {
diff --git a/Configuration/TCA/tx_t3sbootstrap_domain_model_config.php b/Configuration/TCA/tx_t3sbootstrap_domain_model_config.php
index 641ba610..4d887e48 100644
--- a/Configuration/TCA/tx_t3sbootstrap_domain_model_config.php
+++ b/Configuration/TCA/tx_t3sbootstrap_domain_model_config.php
@@ -211,8 +211,8 @@
                 'items' => [
                     ['label' => 'none', 'value' => '',],
                     ['label' => 'Baguettbox', 'value' => 1,],
-                    ['label' => 'Halkabox [1]', 'value' => 2,],
-                    ['label' => 'GLightbox [1]', 'value' => 3,],
+                    ['label' => 'Halkabox', 'value' => 2,],
+                    ['label' => 'GLightbox', 'value' => 3,],
                 ],
             ]
         ],
@@ -963,8 +963,8 @@
                     ['label' => 'Small (<= 576px) [sm]', 'value' => 'sm',],
                     ['label' => 'Medium (<= 768px [md]', 'value' => 'md',],
                     ['label' => 'Large (<= 992px) [lg]', 'value' => 'lg',],
-                    ['label' => 'Extra large (<= 1200px) [xl]', 'value' => 'xl',],
-                    ['label' => 'Extra extra large (<= 1400px) [xxl]', 'value' => 'xxl',],
+                    ['label' => 'Extra large (<= 1400px) [xl]', 'value' => 'xl',],
+                    ['label' => 'Extra extra large (> 1400px) [xxl]', 'value' => 'xxl',],
                     ['label' => 'Never expand [no]', 'value' => 'no',],
                 ]
             ]
diff --git a/Configuration/TSConfig/CKEditor.tsconfig b/Configuration/TSConfig/CKEditor.tsconfig
index 60587fb9..e474e42f 100644
--- a/Configuration/TSConfig/CKEditor.tsconfig
+++ b/Configuration/TSConfig/CKEditor.tsconfig
@@ -2,6 +2,7 @@
 #### Allen Editoren im BE wird der Stil t3sbootstrap zugewiesen ####
 ####################################################################
 
+		
 RTE {
 	default {
 		preset = t3sbootstrap
@@ -32,10 +33,14 @@ RTE {
 				type = telephone
 			}
 
+			email {
+				class = email-link
+				type = email
+			}
+
 		}
 		buttons.link {
-			properties.class.allowedClasses = phone-link, external-link, internal-link, email-link, download-link
+			properties.class.allowedClasses = phone-link, external-link, internal-link, email-link, download-link, btn btn-primary, btn btn-secondary, btn btn-success, btn btn-danger, btn btn-warning, btn btn-info, btn btn-light, btn btn-dark
 		}
 	}
 }
-
diff --git a/Configuration/TSConfig/Registered/Alerts.tsconfig b/Configuration/TSConfig/Registered/Alerts.tsconfig
new file mode 100644
index 00000000..7f2e5836
--- /dev/null
+++ b/Configuration/TSConfig/Registered/Alerts.tsconfig
@@ -0,0 +1,37 @@
+TCEFORM.tt_content {
+	layout {
+		addItems {
+			94 = ------ T3SB ------
+			105 = Alert primary
+			106 = Alert info
+			107 = Alert success
+			108 = Alert warning
+			109 = Alert danger
+			110 = Alert secondary
+			111 = Alert light
+			112 = Alert dark
+		}
+		altLabels {
+			94 = ------ T3SB ------
+			105 = Alert primary
+			106 = Alert info
+			107 = Alert success
+			108 = Alert warning
+			109 = Alert danger
+			110 = Alert secondary
+			111 = Alert light
+			112 = Alert dark
+		}
+		classes {
+			94 = 
+			105 = alert alert-primary
+			106 = alert alert-info
+			107 = alert alert-success
+			108 = alert alert-warning
+			109 = alert alert-danger
+			110 = alert alert-secondary
+			111 = alert alert-light
+			112 = alert alert-dark
+		}
+	}
+}
diff --git a/Configuration/TypoScript/Lib/ContentElement.typoscript b/Configuration/TypoScript/Lib/ContentElement.typoscript
index cacd1b02..40afdd31 100644
--- a/Configuration/TypoScript/Lib/ContentElement.typoscript
+++ b/Configuration/TypoScript/Lib/ContentElement.typoscript
@@ -55,7 +55,6 @@ lib.contentElement {
 				}
 			}
 		}
-		codesnippet = {$bootstrap.extconf.codesnippet}
 		linkHoverEffect = {$bootstrap.extconf.linkHoverEffect}
 		lazyLoad = {$bootstrap.extconf.lazyLoad}
 		imgCopyright = {$bootstrap.extconf.imgCopyright}
@@ -69,8 +68,6 @@ lib.contentElement {
 		halkaboxVersion = {$bootstrap.cdn.halkabox}
 		swiperVersion = {$bootstrap.cdn.swiper}
 		cdn = {$bootstrap.cdn.enable}
-		highlightIntegrity = {$bootstrap.cdn.highlightIntegrity}
-		highlightVersion = {$bootstrap.cdn.highlight}
 		dateformat = {$bootstrap.config.dateFormat}
 		subheaderColor = {$bootstrap.config.subheaderColor}
 		sectionmenuStickyTop = {$bootstrap.config.sectionmenuStickyTop}
@@ -96,7 +93,7 @@ lib.contentElement {
 		btnSlideOutCorrection = 21
 		t3sbconcatenate = {$bootstrap.extconf.t3sbconcatenate}
 		sectionMenuClass = {$bootstrap.config.sectionMenuClass}
-		// used also with config
+		sitepackage = {$bootstrap.extconf.sitepackage}
 		config {
 			sectionmenuAnchorOffset = {$bootstrap.config.sectionmenuAnchorOffset}
 			sectionmenuScrollspyRootMargin = {$bootstrap.config.sectionmenuScrollspyRootMargin}
@@ -144,27 +141,27 @@ lib.contentElement {
 
 [{$bootstrap.image.minimumWidth} == 1]
 lib.contentElement.settings.srcsetMobile = 575
-[global]
+[END]
 
 # 2 == halkabox - https://github.com/ahmednooor/halkaBox.js
-[{$bootstrap.config.lightboxSelection} == 2]
+[{$bootstrap.config.lightboxSelection} == '2']
 lib.contentElement.settings.media.popup {
 	linkParams.ATagParams.stdWrap >
 	linkParams.ATagParams.dataWrap = class="gallery-{file:current:uid_foreign}"  data-title="{file:current:description}"
 	directImageLink = 1
 }
-[global]
+[END]
 
 # 3 == LightBox Plugin - glightbox.js - https://github.com/biati-digital/glightbox
-[{$bootstrap.config.lightboxSelection} == 3]
+[{$bootstrap.config.lightboxSelection} == '3']
 lib.contentElement.settings.media.popup {
 	linkParams.ATagParams.stdWrap >
 	linkParams.ATagParams.dataWrap = id="ex-{file:current:uid}" class="glightbox" data-glightbox="title:{file:current:description}" data-gallery="gallery-{file:current:uid_foreign}" data-effect="fade"
 	directImageLink = 1
 }
-[global]
+[END]
 
 [{$bootstrap.ext.news} == 1]
 # settings for news lightbox
 plugin.tx_news.settings.media.popup < lib.contentElement.settings.media.popup
-[global]
+[END]
diff --git a/Configuration/TypoScript/Lib/_main.typoscript b/Configuration/TypoScript/Lib/_main.typoscript
index 532d84fe..51c43965 100644
--- a/Configuration/TypoScript/Lib/_main.typoscript
+++ b/Configuration/TypoScript/Lib/_main.typoscript
@@ -1,50 +1,8 @@
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Lib/ContentElement.typoscript'
 
-lib.parseFunc_RTE.externalBlocks.table.stdWrap.HTMLparser.tags.table.fixAttrib.class.list >
-
-lib.parseFunc.allowTags := addToList(s, mark)
-lib.parseFunc_RTE.allowTags := addToList(s, mark)
-
-lib.parseFunc.tags := addToList(mark)
-lib.parseFunc_RTE.tags := addToList(mark)
-
-lib.parseFunc_RTE.externalBlocks.table.stdWrap{
-  HTMLparser = 1
-  HTMLparser {
-	tags.table.fixAttrib.class {
-	  default = table
-	  always = 1
-	  list >
-	}
-	keepNonMatchedTags = 1
-  }
-}
-
-lib.parseFunc_RTE {
-	externalBlocks {
-		div {
-			stripNL = 1
-			stdWrap.parseFunc = < lib.parseFunc
-		}
-	}
-}
-
-lib.parseFunc_RTE.externalBlocks.pre.stdWrap{
-	HTMLparser = 1
-	HTMLparser {
-		tags.pre.fixAttrib.class {
-			default = rteContentList
-			always = 1
-			list = rteContentList
-		}
-		keepNonMatchedTags = 1
-	}
-}
-
 
 lib.pageTitle = TEXT
 lib.pageTitle.data = leveltitle:-1
-#lib.pageTitle.stdWrap.wrap = |
 lib.pageTitle.stdWrap.required = 1
 
 lib.newsTitle = TEXT
diff --git a/Configuration/TypoScript/Page/Fileadmin/Fontawesome.typoscript b/Configuration/TypoScript/Page/Fileadmin/Fontawesome.typoscript
new file mode 100644
index 00000000..c895128f
--- /dev/null
+++ b/Configuration/TypoScript/Page/Fileadmin/Fontawesome.typoscript
@@ -0,0 +1,44 @@
+
+##########################################################################################################
+#
+# FONTAWESOME KIT
+#
+##########################################################################################################
+
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0]
+page.includeCSS.t3sfontawesomeKit = /fileadmin/T3SB/Resources/Public/FA6-Kit/css/fontawesome.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.solid}']
+page.includeCSS.t3sfontawesomeSolid = /fileadmin/T3SB/Resources/Public/FA6-Kit/css/solid.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.regular}']
+page.includeCSS.t3sfontawesomeRegular = /fileadmin/T3SB/Resources/Public/FA6-Kit/css/regular.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.light}']
+page.includeCSS.t3sfontawesomeLight = /fileadmin/T3SB/Resources/Public/FA6-Kit/css/light.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.thin}']
+page.includeCSS.t3sfontawesomeThin = /fileadmin/T3SB/Resources/Public/FA6-Kit/css/thin.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.duotone}']
+page.includeCSS.t3sfontawesomeDuotone = /fileadmin/T3SB/Resources/Public/FA6-Kit/css/duotone.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.brands}']
+page.includeCSS.t3sfontawesomeBrands = /fileadmin/T3SB/Resources/Public/FA6-Kit/css/brands.min.css
+[END]
+
+# svgJs
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 1]
+page.includeJSFooter.fontawesomeSvgJs = /fileadmin/T3SB/Resources/Public/FA6-Kit/js/all.min.js
+[END]
+
+
+##########################################################################################################
+#
+# FONTAWESOME FREE / local
+#
+##########################################################################################################
+
+[{$bootstrap.extconf.fontawesomeCss} == 3 && {$bootstrap.fontawesome.svgJs} == 0]
+page.includeCSS.t3sfontawesomeDefault = /fileadmin/T3SB/Resources/Public/CSS/fontawesome.min.css
+[END]
diff --git a/Configuration/TypoScript/Page/Fileadmin/IncludeBootstrapCss.typoscript b/Configuration/TypoScript/Page/Fileadmin/IncludeBootstrapCss.typoscript
new file mode 100644
index 00000000..b5b4127e
--- /dev/null
+++ b/Configuration/TypoScript/Page/Fileadmin/IncludeBootstrapCss.typoscript
@@ -0,0 +1,15 @@
+page {
+
+	includeCSSLibs {
+
+		##########################################################################################################
+		#
+		# BOOTSTRAP CSS
+		#
+		##########################################################################################################
+
+		bootstrapCSS = /fileadmin/T3SB/Resources/Public/CSS/bootstrap.min.css
+
+
+	}
+}
diff --git a/Configuration/TypoScript/Page/Fileadmin/IncludeDefault.typoscript b/Configuration/TypoScript/Page/Fileadmin/IncludeDefault.typoscript
new file mode 100644
index 00000000..dad71e2a
--- /dev/null
+++ b/Configuration/TypoScript/Page/Fileadmin/IncludeDefault.typoscript
@@ -0,0 +1,26 @@
+page {
+	includeCSS {
+
+		##########################################################################################################
+		#
+		# GOOGLE FONTS
+		#
+		##########################################################################################################
+
+		googleFontCSS = /fileadmin/T3SB/Resources/Public/CSS/googlefonts.css
+		googleFontCSS.if.isTrue = {$bootstrap.cdn.googlefonts}
+
+	}
+}
+
+
+
+# load jquery into the header
+[{$bootstrap.config.jqueryHeader} == 1 && {$bootstrap.cdn.enable} == 0]
+page.includeJSFooterlibs.jquery >
+page.includeJSLibs {
+	jquery = /fileadmin/T3SB/Resources/Public/JS/jquery.min.js
+	jquery.forceOnTop = 1
+	jquery.if.isFalse = {$bootstrap.disable.jquery}
+}
+[END]
diff --git a/Configuration/TypoScript/Page/IncludeLocal.typoscript b/Configuration/TypoScript/Page/Fileadmin/IncludeLocal.typoscript
similarity index 72%
rename from Configuration/TypoScript/Page/IncludeLocal.typoscript
rename to Configuration/TypoScript/Page/Fileadmin/IncludeLocal.typoscript
index 0430225b..f33c45b4 100644
--- a/Configuration/TypoScript/Page/IncludeLocal.typoscript
+++ b/Configuration/TypoScript/Page/Fileadmin/IncludeLocal.typoscript
@@ -1,18 +1,5 @@
 page {
 
-	includeCSS {
-
-		##########################################################################################################
-		#
-		# COOKIECONSENT
-		#
-		##########################################################################################################
-
-		cookieconsentCss = /fileadmin/T3SB/Resources/Public/CSS/cookieconsent.min.css
-		cookieconsentCss.if.isTrue = {$bootstrap.extconf.cookieconsent}
-
-	}
-
 	includeJSFooterlibs {
 
 		##########################################################################################################
@@ -38,15 +25,6 @@ page {
 
 	includeJSFooter {
 
-		##########################################################################################################
-		#
-		# COOKIECONSENT
-		#
-		##########################################################################################################
-
-		cookieconsentJs = /fileadmin/T3SB/Resources/Public/JS/cookieconsent.min.js
-		cookieconsentJs.if.isTrue = {$bootstrap.extconf.cookieconsent}
-
 		##########################################################################################################
 		#
 		# JQUERY EASING
diff --git a/Configuration/TypoScript/Page/Fileadmin/_main.typoscript b/Configuration/TypoScript/Page/Fileadmin/_main.typoscript
new file mode 100644
index 00000000..cfd6d93a
--- /dev/null
+++ b/Configuration/TypoScript/Page/Fileadmin/_main.typoscript
@@ -0,0 +1,15 @@
+
+[{$bootstrap.extconf.customScss} == 1 && {$bootstrap.cdn.enable} == 0]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Fileadmin/IncludeLocal.typoscript'
+[END]
+
+[{$bootstrap.extconf.customScss} == 0 && {$bootstrap.cdn.enable} == 0]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Fileadmin/IncludeBootstrapCss.typoscript'
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Fileadmin/IncludeLocal.typoscript'
+[END]
+
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Fileadmin/IncludeDefault.typoscript'
+
+[{$bootstrap.cdn.enable} == 0]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Fileadmin/Fontawesome.typoscript'
+[END]
diff --git a/Configuration/TypoScript/Page/IncludeBootstrapCss.typoscript b/Configuration/TypoScript/Page/IncludeBootstrapCdnCss.typoscript
similarity index 74%
rename from Configuration/TypoScript/Page/IncludeBootstrapCss.typoscript
rename to Configuration/TypoScript/Page/IncludeBootstrapCdnCss.typoscript
index d3fd90cd..8edecdca 100644
--- a/Configuration/TypoScript/Page/IncludeBootstrapCss.typoscript
+++ b/Configuration/TypoScript/Page/IncludeBootstrapCdnCss.typoscript
@@ -1,4 +1,5 @@
 page {
+	
 	includeCSS {
 
 		##########################################################################################################
@@ -7,21 +8,11 @@ page {
 		#
 		##########################################################################################################
 
-		# Local (fileadmin)
-		bootstrapCSS = /fileadmin/T3SB/Resources/Public/CSS/bootstrap.min.css
-		bootstrapCSS.forceOnTop = 1
-		bootstrapCSS.if {
-			isFalse = {$bootstrap.cdn.enable}
-		}
-
 		# CDN
 		bootstrapCDN = https://cdn.jsdelivr.net/npm/bootstrap@{$bootstrap.cdn.bootstrap}/dist/css/bootstrap.min.css
 		bootstrapCDN.external = 1
-		bootstrapCDN.integrity = {$bootstrap.cdn.bootstrapCssIntegrity}
 		bootstrapCDN.forceOnTop = 1
 		bootstrapCDN.if {
-			value = 1
-			equals = {$bootstrap.cdn.enable}
 			isFalse = {$bootstrap.cdn.bootswatch}
 		}
 
@@ -36,10 +27,12 @@ page {
 		bootswatchCDN.external = 1
 		bootswatchCDN.forceOnTop = 1
 		bootswatchCDN.if {
-			value = 1
-			equals = {$bootstrap.cdn.enable}
 			isTrue = {$bootstrap.cdn.bootswatch}
 		}
 	}
 }
 
+
+
+
+
diff --git a/Configuration/TypoScript/Page/IncludeBootstrapScss.typoscript b/Configuration/TypoScript/Page/IncludeBootstrapScss.typoscript
index ff7bdf8c..e7bb8d25 100644
--- a/Configuration/TypoScript/Page/IncludeBootstrapScss.typoscript
+++ b/Configuration/TypoScript/Page/IncludeBootstrapScss.typoscript
@@ -1,5 +1,5 @@
 page {
-	includeCSS {
+	includeCSSLibs {
 
 		##########################################################################################################
 		#
@@ -7,10 +7,8 @@ page {
 		#
 		##########################################################################################################
 
-		# CUSTOM
 		bootstrapCustom = uploads/tx_t3sbootstrap/bootstrap.scss
 		bootstrapCustom.forceOnTop = 1
-
 	}
 }
 
diff --git a/Configuration/TypoScript/Page/IncludeCdn.typoscript b/Configuration/TypoScript/Page/IncludeCdn.typoscript
index 8f144048..f902af30 100644
--- a/Configuration/TypoScript/Page/IncludeCdn.typoscript
+++ b/Configuration/TypoScript/Page/IncludeCdn.typoscript
@@ -1,18 +1,5 @@
 
 page {
-	includeCSS {
-
-		##########################################################################################################
-		#
-		# COOKIECONSENT
-		#
-		##########################################################################################################
-
-		cookieconsentCssCDN = https://cdn.jsdelivr.net/npm/cookieconsent@{$bootstrap.cdn.cookieconsent}/build/cookieconsent.min.css
-		cookieconsentCssCDN.external = 1
-		cookieconsentCssCDN.if.isTrue = {$bootstrap.extconf.cookieconsent}
-
-	}
 
 	includeJSFooterlibs {
 
@@ -31,32 +18,21 @@ page {
 		popperCDN = https://cdnjs.cloudflare.com/ajax/libs/popper.js/{$bootstrap.cdn.popperjs}/umd/popper.min.js
 		popperCDN.integrity = {$bootstrap.cdn.popperjsIntegrity}
 		popperCDN.external = 1
-		popperCDN.if.isFalse = {$bootstrap.extconf.t3sbconcatenate}
+		popperCDN.if.isFalse = {$bootstrap.bundle.enable}
 
 		bootstrapCDN = https://cdn.jsdelivr.net/npm/bootstrap@{$bootstrap.cdn.bootstrap}/dist/js/bootstrap.min.js
 		bootstrapCDN.integrity = {$bootstrap.cdn.bootstrapJsIntegrity}
 		bootstrapCDN.external = 1
-		bootstrapCDN.if.isFalse = {$bootstrap.extconf.t3sbconcatenate}
+		bootstrapCDN.if.isFalse = {$bootstrap.bundle.enable}
 
 		bootstrapCDNBundle = https://cdn.jsdelivr.net/npm/bootstrap@{$bootstrap.cdn.bootstrap}/dist/js/bootstrap.bundle.min.js
 		bootstrapCDNBundle.integrity = {$bootstrap.cdn.bootstrapBundleJsIntegrity}
 		bootstrapCDNBundle.external = 1
-		bootstrapCDNBundle.if.isTrue = {$bootstrap.extconf.t3sbconcatenate}
+		bootstrapCDNBundle.if.isTrue = {$bootstrap.bundle.enable}
 	}
 
 	includeJSFooter {
 
-		##########################################################################################################
-		#
-		# COOKIECONSENT
-		#
-		##########################################################################################################
-
-		cookieconsentJsCDN = https://cdn.jsdelivr.net/npm/cookieconsent@{$bootstrap.cdn.cookieconsent}/build/cookieconsent.min.js
-		cookieconsentJsCDN.integrity = {$bootstrap.cdn.cookieconsentIntegrity}
-		cookieconsentJsCDN.external = 1
-		cookieconsentJsCDN.if.isTrue = {$bootstrap.extconf.cookieconsent}
-
 		##########################################################################################################
 		#
 		# JQUERY EASING
@@ -95,19 +71,45 @@ page {
 		picturefillCDN.if.isTrue = {$bootstrap.image.picturefill}
 
 	}
-
-	##########################################################################################################
-	#
-	# FONTAWESOME - using the SVG + JS version
-	#
-	##########################################################################################################
-
-	footerData {
-		61 = TEXT
-		61.value = 
-		61.if {
-			value = 3
-			isInList = {$bootstrap.extconf.fontawesomeCss}
-		}
-	}
 }
+
+##########################################################################################################
+#
+# FONTAWESOME KIT
+#
+##########################################################################################################
+# FA Kit webfonts
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.kitcode}']
+page.includeCSS.fontawesomeWebfont = https://kit.fontawesome.com/{$bootstrap.fontawesome.kitcode}.css
+page.includeCSS.fontawesomeWebfont.external = 1
+page.includeCSS.fontawesomeWebfont.crossorigin = anonymous
+[END]
+# FA Kit SVG + JS version
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 1 && '{$bootstrap.fontawesome.kitcode}']
+page.includeJSFooter.fontawesomeSvgJs = https://kit.fontawesome.com/{$bootstrap.fontawesome.kitcode}.js
+page.includeJSFooter.fontawesomeSvgJs.external = 1
+page.includeJSFooter.fontawesomeSvgJs.crossorigin = anonymous
+[END]
+
+
+##########################################################################################################
+#
+# FONTAWESOME FREE
+#
+##########################################################################################################
+# FA free webfonts
+[{$bootstrap.extconf.fontawesomeCss} == 3 && {$bootstrap.fontawesome.svgJs} == 0]
+page.footerData.61 >
+page.includeCSS.t3sfontawesomeMin = https://cdnjs.cloudflare.com/ajax/libs/font-awesome/{$bootstrap.cdn.fontawesome}/css/all.min.css
+page.includeCSS.t3sfontawesomeMin.external = 1
+page.includeCSS.t3sfontawesomeMin.integrity = {$bootstrap.cdn.fontawesomeIntegrity}
+page.includeCSS.t3sfontawesomeMin.crossorigin = anonymous
+[END]
+# FA free SVG + JS version
+[{$bootstrap.extconf.fontawesomeCss} == 3 && {$bootstrap.fontawesome.svgJs} == 1]
+page.includeJSFooter.t3sfontawesomeMin = https://cdnjs.cloudflare.com/ajax/libs/font-awesome/{$bootstrap.cdn.fontawesome}/js/all.min.js
+page.includeJSFooter.t3sfontawesomeMin.external = 1
+#page.includeJSFooter.t3sfontawesomeMin.crossorigin = anonymous
+page.includeJSFooter.t3sfontawesomeMin.data.data-auto-replace-svg = nest
+[END]
+
diff --git a/Configuration/TypoScript/Page/IncludeDefault.typoscript b/Configuration/TypoScript/Page/IncludeDefault.typoscript
deleted file mode 100644
index b35a6ecf..00000000
--- a/Configuration/TypoScript/Page/IncludeDefault.typoscript
+++ /dev/null
@@ -1,105 +0,0 @@
-page {
-
-	includeCSS {
-
-		##########################################################################################################
-		#
-		# Default CSS
-		#
-		##########################################################################################################
-
-		t3sbootstrap = EXT:t3sbootstrap/Resources/Public/Styles/t3sbootstrap.css
-		t3sbootstrap.if.isFalse = {$bootstrap.config.disableDefaultCss}
-
-
-		##########################################################################################################
-		#
-		# GOOGLE FONTS
-		#
-		##########################################################################################################
-
-		googleFontCSS = /fileadmin/T3SB/Resources/Public/CSS/googlefonts.css
-		googleFontCSS.forceOnTop = 1
-		googleFontCSS.if.isTrue = {$bootstrap.cdn.googlefonts}
-
-	}
-
-	##########################################################################################################
-	#
-	# Inline JS
-	#
-	##########################################################################################################
-
-	jsInline.5 < temp.jsCookieConsent
-	jsInline.5.if.isTrue = {$bootstrap.extconf.cookieconsent}
-
-}
-
-temp.jsCookieConsent >
-
-
-##########################################################################################################
-#
-# Conditions
-#
-##########################################################################################################
-
-// preload GOOGLE FONTS
-[{$bootstrap.preloadGooleFonts} == 1]
-@import '/fileadmin/T3SB/Configuration/TypoScript/preloadGooleFonts.typoscript'
-[global]
-
-# Bugfix for Safari browser if using webp with lazyload
-[browser('Safari') && {$bootstrap.ext.webp} == 1 && {$bootstrap.extconf.lazyLoad} > 0]
-page.cssInline {
-	124 = TEXT
-	124.value = picture img.lazy {opacity:1 !important;}
-}
-[global]
-
-# Background Image
-[{$bootstrap.config.backgroundImageEnable} == 1]
-page.cssInline {
-	5 = TEXT
-	5.value = body {background-repeat:no-repeat;background-position: center center;background-size: cover;background-attachment: fixed}
-}
-[global]
-
-# load jquery into the header
-[{$bootstrap.config.jqueryHeader} == 1 && {$bootstrap.cdn.enable} == 1]
-page.includeJSFooterlibs.jqueryCDN >
-page.includeJSLibs {
-	jqueryCDN = https://code.jquery.com/jquery-{$bootstrap.cdn.jquery}.slim.min.js
-	jqueryCDN.external = 1
-	jqueryCDN.forceOnTop = 1
-	jqueryCDN.if.isFalse = {$bootstrap.disable.jquery}
-}
-[global]
-
-[{$bootstrap.config.jqueryHeader} == 1 && {$bootstrap.cdn.enable} == 0]
-page.includeJSFooterlibs.jquery >
-page.includeJSLibs {
-	jquery = /fileadmin/T3SB/Resources/Public/JS/jquery.min.js
-	jquery.forceOnTop = 1
-	jquery.if.isFalse = {$bootstrap.disable.jquery}
-}
-[global]
-
-##########################################################################################################
-#
-# FONTAWESOME - minimal installation with required icons and for link icons set in RTE
-#
-##########################################################################################################
-[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 0]
-page.includeCSS.t3sfontawesomeMinLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeMinLink.css
-[global]
-[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 3]
-page.includeCSS.t3sfontawesomeLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesome6Link.css
-[global]
-[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 4]
-page.includeCSS.t3sfontawesomeProLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesome6ProLink.css
-[global]
-[{$bootstrap.config.faLinkIcons} == 0]
-page.includeCSS.t3sfontawesomeMin = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeMin.css
-page.includeCSS.t3sfontawesomeMin.if.isFalse = {$bootstrap.extconf.fontawesomeCss}
-[global]
diff --git a/Configuration/TypoScript/Page/JS/CookieConsent.typoscript b/Configuration/TypoScript/Page/JS/CookieConsent.typoscript
deleted file mode 100644
index ebcac1e3..00000000
--- a/Configuration/TypoScript/Page/JS/CookieConsent.typoscript
+++ /dev/null
@@ -1,84 +0,0 @@
-
-temp.jsCookieConsent = COA
-temp.jsCookieConsent {
-	1 = TEXT
-	1.value (
-	
-		// Cookieconsent - page.jsInline.5
-		window.addEventListener("load", function(){
-			var p;
-	
-			window.cookieconsent.initialise({
-	
-				onInitialise: function(status) {
-					var type = this.options.type;
-					console.log("cookieconsent_type:", type);
-					console.log("cookieconsent_status:", status);
-				},
-	
-				theme: "{$bootstrap.cookieconsent.theme}",
-				position: "{$bootstrap.cookieconsent.position}",
-				palette: {
-					popup: {
-						background: "{$bootstrap.cookieconsent.popup.background}",
-						text: "{$bootstrap.cookieconsent.popup.text}"
-					},
-					button: {
-						background: "{$bootstrap.cookieconsent.button.background}",
-						text: "{$bootstrap.cookieconsent.button.text}"
-					}
-				},
-				content: {
-					message: "{$bootstrap.cookieconsent.message}",
-					dismiss: "{$bootstrap.cookieconsent.dismiss}",
-					deny: "{$bootstrap.cookieconsent.deny}",
-					allow: "{$bootstrap.cookieconsent.allow}",
-					link: "{$bootstrap.cookieconsent.link}",
-					href: "{$bootstrap.cookieconsent.href}",
-				},
-	
-				elements: {
-					allow: '{{allow}}',
-				},
-	
-				type: "{$bootstrap.cookieconsent.type}",
-	
-				revokeBtn: "{$bootstrap.cookieconsent.revokeBtn}",
-				// no popup on this pages
-				blacklistPage: ["{$bootstrap.cookieconsent.href}"],
-	
-					 onStatusChange: function(status) {
-					console.log(this.hasConsented() ?
-					  'enable cookies' : 'disable cookies');
-	
-					var type = this.options.type;
-					if ( type == 'opt-in' && this.hasConsented() ) {
-						location.reload(true);
-					}
-					if ( type == 'opt-out' && !this.hasConsented() ) {
-						location.reload(true);
-					}
-					 },
-	
-					 law: {
-					regionalLaw: {$bootstrap.cookieconsent.regionalLaw},
-					 },
-					 location: {$bootstrap.cookieconsent.location},
-	
-	
-			}, function (popup) {
-			p = popup;
-		  }, function (err) {
-			console.error(err);
-		  });
-	
-	
-			if ( document.getElementById('btn-revokeChoice') ) {
-				document.getElementById('btn-revokeChoice').onclick = function (e) {
-					p.revokeChoice();
-				};
-			}
-	
-		});	
-	)
-}
diff --git a/Configuration/TypoScript/Page/Sitepackage/Fontawesome.typoscript b/Configuration/TypoScript/Page/Sitepackage/Fontawesome.typoscript
new file mode 100644
index 00000000..e89fb170
--- /dev/null
+++ b/Configuration/TypoScript/Page/Sitepackage/Fontawesome.typoscript
@@ -0,0 +1,45 @@
+
+##########################################################################################################
+#
+# FONTAWESOME KIT
+#
+##########################################################################################################
+
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0]
+page.includeCSS.t3sfontawesomeKit = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/fontawesome.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.solid}']
+page.includeCSS.t3sfontawesomeSolid = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/solid.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.regular}']
+page.includeCSS.t3sfontawesomeRegular = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/regular.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.light}']
+page.includeCSS.t3sfontawesomeLight = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/light.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.thin}']
+page.includeCSS.t3sfontawesomeThin = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/thin.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.duotone}']
+page.includeCSS.t3sfontawesomeDuotone = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/duotone.min.css
+[END]
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 0 && '{$bootstrap.fontawesome.brands}']
+page.includeCSS.t3sfontawesomeBrands = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/css/brands.min.css
+[END]
+
+# svgJs
+['{$bootstrap.extconf.fontawesomeCss}' && {$bootstrap.extconf.fontawesomeCss} < 3 && {$bootstrap.fontawesome.svgJs} == 1]
+page.includeJSFooter.fontawesomeSvgJs = EXT:t3sb_package/T3SB/Resources/Public/FA6-Kit/js/all.min.js
+[END]
+
+
+##########################################################################################################
+#
+# FONTAWESOME FREE / local
+#
+##########################################################################################################
+
+[{$bootstrap.extconf.fontawesomeCss} == 3 && {$bootstrap.fontawesome.svgJs} == 0]
+page.includeCSS.t3sfontawesomeDefault = EXT:t3sb_package/T3SB/Resources/Public/CSS/fontawesome.min.css
+[END]
+
diff --git a/Configuration/TypoScript/Page/Sitepackage/IncludeBootstrapCss.typoscript b/Configuration/TypoScript/Page/Sitepackage/IncludeBootstrapCss.typoscript
new file mode 100644
index 00000000..474c2122
--- /dev/null
+++ b/Configuration/TypoScript/Page/Sitepackage/IncludeBootstrapCss.typoscript
@@ -0,0 +1,15 @@
+page {
+
+	includeCSSLibs {
+
+		##########################################################################################################
+		#
+		# BOOTSTRAP CSS
+		#
+		##########################################################################################################
+
+		bootstrapCSS = EXT:t3sb_package/T3SB/Resources/Public/CSS/bootstrap.min.css
+
+	}
+}
+
diff --git a/Configuration/TypoScript/Page/Sitepackage/IncludeDefault.typoscript b/Configuration/TypoScript/Page/Sitepackage/IncludeDefault.typoscript
new file mode 100644
index 00000000..f71e2eef
--- /dev/null
+++ b/Configuration/TypoScript/Page/Sitepackage/IncludeDefault.typoscript
@@ -0,0 +1,26 @@
+page {
+	includeCSS {
+
+		##########################################################################################################
+		#
+		# GOOGLE FONTS
+		#
+		##########################################################################################################
+
+		googleFontCSS = EXT:t3sb_package/T3SB/Resources/Public/CSS/googlefonts.css
+		googleFontCSS.if.isTrue = {$bootstrap.cdn.googlefonts}
+
+	}
+}
+
+
+
+# load jquery into the header
+[{$bootstrap.config.jqueryHeader} == 1 && {$bootstrap.cdn.enable} == 0]
+page.includeJSFooterlibs.jquery >
+page.includeJSLibs {
+	jquery = EXT:t3sb_package/T3SB/Resources/Public/JS/jquery.min.js
+	jquery.forceOnTop = 1
+	jquery.if.isFalse = {$bootstrap.disable.jquery}
+}
+[END]
diff --git a/Configuration/TypoScript/Page/Sitepackage/IncludeLocal.typoscript b/Configuration/TypoScript/Page/Sitepackage/IncludeLocal.typoscript
new file mode 100644
index 00000000..31623286
--- /dev/null
+++ b/Configuration/TypoScript/Page/Sitepackage/IncludeLocal.typoscript
@@ -0,0 +1,62 @@
+page {
+
+	includeJSFooterlibs {
+
+		##########################################################################################################
+		#
+		# jQuery, Popper & Bootstrap
+		#
+		##########################################################################################################
+
+		jquery = EXT:t3sb_package/T3SB/Resources/Public/JS/jquery.min.js
+		jquery.forceOnTop = 1
+		jquery.if.isFalse = {$bootstrap.disable.jquery}
+
+		popper = EXT:t3sb_package/T3SB/Resources/Public/JS/popper.js
+		popper.if.isFalse = {$bootstrap.bundle.enable}
+
+		bootstrap = EXT:t3sb_package/T3SB/Resources/Public/JS/bootstrap.min.js
+		bootstrap.if.isFalse = {$bootstrap.bundle.enable}
+
+		bootstrapBundle = EXT:t3sb_package/T3SB/Resources/Public/JS/bootstrap.bundle.min.js
+		bootstrapBundle.if.isTrue = {$bootstrap.bundle.enable}
+
+	}
+
+	includeJSFooter {
+
+		##########################################################################################################
+		#
+		# JQUERY EASING
+		#
+		##########################################################################################################
+
+		t3sbjqueryeasing = EXT:t3sb_package/T3SB/Resources/Public/JS/jquery.easing.min.js
+		t3sbjqueryeasing.forceOnTop = 1
+		t3sbjqueryeasing.if.isFalse = {$bootstrap.disable.jquery}
+
+		##########################################################################################################
+		#
+		# LAZYLOAD
+		#
+		##########################################################################################################
+
+		lazyload = EXT:t3sb_package/T3SB/Resources/Public/JS/lazyload.min.js
+		lazyload.if.isTrue = {$bootstrap.extconf.lazyLoad}
+		lazyload.if {
+			value = 1,2
+			isInList = {$bootstrap.extconf.lazyLoad}
+		}
+		##########################################################################################################
+		#
+		# PICTUREFILL
+		#
+		##########################################################################################################
+
+		# Local
+		picturefill = EXT:t3sb_package/T3SB/Resources/Public/JS/picturefill.min.js
+		picturefill.if.isTrue = {$bootstrap.image.picturefill}
+
+	}
+
+}
diff --git a/Configuration/TypoScript/Page/Sitepackage/_main.typoscript b/Configuration/TypoScript/Page/Sitepackage/_main.typoscript
new file mode 100644
index 00000000..db40009c
--- /dev/null
+++ b/Configuration/TypoScript/Page/Sitepackage/_main.typoscript
@@ -0,0 +1,15 @@
+
+[{$bootstrap.extconf.customScss} == 1 && {$bootstrap.cdn.enable} == 0]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Sitepackage/IncludeLocal.typoscript'
+[END]
+
+[{$bootstrap.extconf.customScss} == 0 && {$bootstrap.cdn.enable} == 0]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Sitepackage/IncludeBootstrapCss.typoscript'
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Sitepackage/IncludeLocal.typoscript'
+[END]
+
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Sitepackage/IncludeDefault.typoscript'
+
+[{$bootstrap.cdn.enable} == 0]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Sitepackage/Fontawesome.typoscript'
+[END]
diff --git a/Configuration/TypoScript/Page/Template.typoscript b/Configuration/TypoScript/Page/Template.typoscript
index b0c12797..feb1fd98 100644
--- a/Configuration/TypoScript/Page/Template.typoscript
+++ b/Configuration/TypoScript/Page/Template.typoscript
@@ -31,19 +31,17 @@ page {
 			fontawesome.extconf = {$bootstrap.extconf.fontawesomeCss}
 			fontawesome.cdn = {$bootstrap.cdn.enable}
 			fontawesome.version = {$bootstrap.cdn.fontawesome}
-			fontawesome.5latest = {$bootstrap.cdn.fontawesome5latest}
 			fontawesome.6latest = {$bootstrap.cdn.fontawesome6latest}
 			fontawesome.pagetitle = {$bootstrap.extconf.fontawesomepagetitle}
 			fontawesome.fontawesomeCss = {$bootstrap.extconf.fontawesomeCss}
 			fontawesome.faLinkIcons = {$bootstrap.config.faLinkIcons}
+
 			disableDefaultCss = {$bootstrap.config.disableDefaultCss}
-			codesnippet = {$bootstrap.extconf.codesnippet}
 			lazyLoad = {$bootstrap.extconf.lazyLoad}
 			lazyLoadThreshold = {$bootstrap.image.lazyLoadThreshold}
 			webp = {$bootstrap.ext.webp}
 			indexedsearch.loaded = {$bootstrap.ext.indexedsearch}
 			kesearch.loaded = {$bootstrap.ext.kesearch}
-			cookieconsent = {$bootstrap.extconf.cookieconsent}
 			cdn = {$bootstrap.cdn.enable}
 			googlefonts = {$bootstrap.cdn.googlefonts}
 			t3sbconcatenate = {$bootstrap.extconf.t3sbconcatenate}
@@ -51,12 +49,13 @@ page {
 			backToTopTitle = {$bootstrap.backToTopTitle}
 			backToTopClass = {$bootstrap.backToTopClass}
 			backToTopForAllPages = {$bootstrap.backToTopForAllPages}
-			gtm = {$bootstrap.gtm}
 			bgMediaQueries = {$bootstrap.image.bgMediaQueries}
 			sectionmenuIcons = {$bootstrap.config.sectionmenuIcons}
 			submenu.styleOne = {$bootstrap.submenu.styleOne}
 			viewportWidthCookie = {$bootstrap.image.viewportWidthCookie}
+			sitepackage = {$bootstrap.extconf.sitepackage}
 			navbar {
+				noLinkTitle = {$bootstrap.navbar.noLinkTitle}
 				image.defaultPath = {$bootstrap.navbar.image.defaultPath}
 				image.width = {$bootstrap.navbar.image.width}
 				image.height = {$bootstrap.navbar.image.height}
@@ -357,5 +356,4 @@ plugin.tx_felogin_login {
 	}
 }
 
-// import outsourced setup
-@import 'fileadmin/T3SB/Configuration/TypoScript/t3sbsetup.typoscript'
+
diff --git a/Configuration/TypoScript/Page/_main.typoscript b/Configuration/TypoScript/Page/_main.typoscript
index 8faca0cc..9354f217 100644
--- a/Configuration/TypoScript/Page/_main.typoscript
+++ b/Configuration/TypoScript/Page/_main.typoscript
@@ -1,34 +1,101 @@
+
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Configuration.typoscript'
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Register.typoscript'
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/BodyTag.typoscript'
 
-[{$bootstrap.extconf.cookieconsent} == 1]
-@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/JS/CookieConsent.typoscript'
-[global]
-
 [{$bootstrap.extconf.customScss} == 1 && {$bootstrap.cdn.enable} == 0]
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeBootstrapScss.typoscript'
-@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeLocal.typoscript'
-[global]
+[END]
+
+[{$bootstrap.extconf.sitepackage} == 1]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Sitepackage/_main.typoscript'
+[ELSE]
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Fileadmin/_main.typoscript'
+[END]
 
 [{$bootstrap.extconf.customScss} == 1 && {$bootstrap.cdn.enable} == 1]
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeBootstrapScss.typoscript'
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeCdn.typoscript'
-[global]
+[END]
 
 [{$bootstrap.extconf.customScss} == 0 && {$bootstrap.cdn.enable} == 1]
-@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeBootstrapCss.typoscript'
+@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeBootstrapCdnCss.typoscript'
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeCdn.typoscript'
-[global]
+[END]
 
-[{$bootstrap.extconf.customScss} == 0 && {$bootstrap.cdn.enable} == 0]
-@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeBootstrapCss.typoscript'
-@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeLocal.typoscript'
-[global]
-
-@import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/IncludeDefault.typoscript'
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Template.typoscript'
 
 [{$bootstrap.print.enable} == 1]
 @import 'EXT:t3sbootstrap/Configuration/TypoScript/Page/Print.typoscript'
-[global]
+[END]
+
+
+
+page {
+
+	includeCSS {
+
+		##########################################################################################################
+		#
+		# EXT:t3sbootstrap default CSS
+		#
+		##########################################################################################################
+
+		t3sbootstrap = EXT:t3sbootstrap/Resources/Public/Styles/t3sbootstrap.css
+		t3sbootstrap.if.isFalse = {$bootstrap.config.disableDefaultCss}
+
+	}
+
+}
+
+
+# Bugfix for Safari browser if using webp with lazyload
+[browser('Safari') && {$bootstrap.ext.webp} == 1 && {$bootstrap.extconf.lazyLoad} > 0]
+page.cssInline {
+	124 = TEXT
+	124.value = picture img.lazy {opacity:1 !important;}
+}
+[END]
+
+# Background Image
+[{$bootstrap.config.backgroundImageEnable} == 1]
+page.cssInline {
+	5 = TEXT
+	5.value = body {background-repeat:no-repeat;background-position: center center;background-size: cover;background-attachment: fixed}
+}
+[END]
+
+
+
+# load jquery into the header
+[{$bootstrap.config.jqueryHeader} == 1 && {$bootstrap.cdn.enable} == 1]
+page.includeJSFooterlibs.jqueryCDN >
+page.includeJSLibs {
+	jqueryCDN = https://code.jquery.com/jquery-{$bootstrap.cdn.jquery}.slim.min.js
+	jqueryCDN.external = 1
+	jqueryCDN.forceOnTop = 1
+	jqueryCDN.if.isFalse = {$bootstrap.disable.jquery}
+}
+[END]
+
+
+##########################################################################################################
+#
+# FONTAWESOME - minimal installation with required icons and for link icons set in RTE
+#
+##########################################################################################################
+[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 0]
+page.includeCSS.t3sfontawesomeMinLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeMinLink.css
+[END]
+[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 1]
+page.includeCSS.t3sfontawesomeLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeLink.css
+[END]
+[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 2]
+page.includeCSS.t3sfontawesomeLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeProLink.css
+[END]
+[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 3]
+page.includeCSS.t3sfontawesomeLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeLink.css
+[END]
+[{$bootstrap.config.faLinkIcons} == 0 && {$bootstrap.extconf.fontawesomeCss} == 0]
+page.includeCSS.t3sfontawesomeMin = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeMin.css
+[END]
diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript
index cd4caf2c..04603a81 100644
--- a/Configuration/TypoScript/constants.typoscript
+++ b/Configuration/TypoScript/constants.typoscript
@@ -15,7 +15,7 @@ plugin.tx_t3sbootstrap {
 }
 
 
-bootstrap.cdn.bootstraplatest = 5.3.1
+bootstrap.cdn.bootstraplatest = 5.3.2
 bootstrap.cdn.noZip = 0
 bootstrap.cdn.fontawesome6latest = 6.4.2
 
@@ -28,7 +28,6 @@ bootstrap.cdn.fontawesome6latest = 6.4.2
 # customsubcategory=a-google=GoogleFonts - Integrate Google Fonts
 # customsubcategory=b-version=CDN Versions used in the scheduler task T3SB CDN to local - must be valid
 # customsubcategory=c-integrity=CDN Integrity - if set crossorigin is set to anonymous
-
 # customcategory=bootstrap-image=T3SB Image settings
 # customsubcategory=a-image=Default Image Size
 # customsubcategory=b-image=Additional image sizes (srcset) that should be generated for each content image.
@@ -41,15 +40,19 @@ bootstrap.cdn.fontawesome6latest = 6.4.2
 # customcategory=bootstrap-pages=T3SB Global pages override
 # customsubcategory=a-pages=Global pages override
 
+# customcategory=bootstrap-fontawesome=T3SB Font Awesome
+# customsubcategory=a-fontawesome=Framework
+# customsubcategory=b-fontawesome=Styles - if "FA6-KIT" is activated in EM config
+
 bootstrap.cdn {
-	# cat=bootstrap-cdn/a-enable/10; type=boolean; label=Enable CDN - please consider the "GDPR" ("DSGVO"):before CDN can be disabled, run the scheduler task "T3SB CDN to local" to write the required files to fileadmin/T3SB/Resources/Public/
+	# cat=bootstrap-cdn/a-enable/10; type=boolean; label=Enable CDN - please consider the "GDPR" ("DSGVO"):before CDN can be disabled, run the scheduler task "T3SB CDN to local" to write the required files to fileadmin/T3SB/ or EXT:t3sb_package/T3SB/
 	enable = 1
 	# cat=bootstrap-cdn/a-enable/20; type=options[none=0, Cerulean=cerulean, Cosmo=cosmo, Cyborg=cyborg, Darkly=darkly, Flatly=flatly, Journal=journal, Litera=litera, Lumen=lumen, Lux=lux, Materia=materia, Minty=minty, Morph=morph Pulse=pulse, Quartz=quartz, Sandstone=sandstone, Simplex=simplex, Sketchy=sketchy, Slate=slate, Solar=solar, Spacelab=spacelab, Superhero=superhero, United=united, Vapor=vapor, Yeti=yeti, Zephyr=zephyr]; label=Bootswatch Themes CDN: Override default Bootstrap values with selected Bootswatch Theme - Info: https://bootswatch.com/.
 	bootswatch = 0
 	# cat=bootstrap-cdn/a-google/10; type=small; label=Comma separated list with google fonts:integrate Google Fonts "GDPR"-compliant locally into your website (e.g.: Montserrat,Fira Sans)
 	googlefonts =
 	# cat=bootstrap-cdn/b-version/10; type=small; label=Bootstrap:
-	bootstrap = 5.3.1
+	bootstrap = 5.3.2
 	# cat=bootstrap-cdn/b-version/11; type=small; label=Popper js:
 	popperjs = 2.11.8
 	# cat=bootstrap-cdn/b-version/13; type=small; label=Masonry js:
@@ -60,10 +63,6 @@ bootstrap.cdn {
 	jquery = 3.7.0
 	# cat=bootstrap-cdn/b-version/22; type=small; label=jQuery Easing:
 	jqueryEasing = 1.4.1
-	# cat=bootstrap-cdn/b-version/25; type=int+; label=Cookieconsent: set to 3 only to get v3.x (latest)
-	cookieconsent = 3
-	# cat=bootstrap-cdn/b-version/27; type=small; label=Highlight: used with codesnippet
-	highlight = 11.6.0
 	# cat=bootstrap-cdn/b-version/30; type=small; label=Lazyload:
 	lazyload = 17.8.3
 	# cat=bootstrap-cdn/b-version/32; type=small; label=Picturefill:
@@ -78,15 +77,15 @@ bootstrap.cdn {
 	glightbox = 3.2.0
 	# cat=bootstrap-cdn/b-version/50; type=small; label=Jarallax: set to 2 only to get v2.x (latest)
 	jarallax = 2
-	# cat=bootstrap-cdn/b-version/60; type=small; label=Swiper: set to 10 only to get v10.x (latest)
-	swiper = 10
+	# cat=bootstrap-cdn/b-version/60; type=small; label=Swiper: set to 11 only to get v11.x (latest)
+	swiper = 11
 
 	# cat=bootstrap-cdn/c-integrity/10; type=small; label=Bootstrap CSS:
-	bootstrapCssIntegrity = sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM
+	bootstrapCssIntegrity = sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN
 	# cat=bootstrap-cdn/c-integrity/11; type=small; label=Bootstrap JS:
-	bootstrapJsIntegrity = sha384-fbbOQedDUMZZ5KreZpsbe1LCZPVmfTnH7ois6mU1QK+m14rQ1l2bGBq41eYeM/fS
+	bootstrapJsIntegrity = sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+
 	# cat=bootstrap-cdn/c-integrity/12; type=small; label=Bootstrap Bundle JS:
-	bootstrapBundleJsIntegrity = sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz
+	bootstrapBundleJsIntegrity = sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL
 	# cat=bootstrap-cdn/c-integrity/13; type=small; label=Popper js:
 	popperjsIntegrity = sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r
 	# cat=bootstrap-cdn/c-integrity/14; type=small; label=Masonry js:
@@ -95,10 +94,6 @@ bootstrap.cdn {
 	jqueryIntegrity = sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=
 	# cat=bootstrap-cdn/c-integrity/22; type=small; label=jQuery Easing:
 	jqueryEasingIntegrity = 
-	# cat=bootstrap-cdn/c-integrity/25; type=small; label=Cookieconsent:
-	cookieconsentIntegrity = 
-	# cat=bootstrap-cdn/c-integrity/27; type=small; label=Highlight:
-	highlightIntegrity = 
 	# cat=bootstrap-cdn/c-integrity/30; type=small; label=Lazyload:
 	lazyloadIntegrity = 
 	# cat=bootstrap-cdn/c-integrity/32; type=small; label=Picturefill:
@@ -109,6 +104,8 @@ bootstrap.cdn {
 	halkaboxIntegrity = 
 	# cat=bootstrap-cdn/c-integrity/42; type=small; label=G Lightbox:
 	glightboxIntegrity = 
+	# cat=bootstrap-cdn/c-integrity/50; type=small; label=Font Awesome:
+	fontawesomeIntegrity = sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==
 }
 
 bootstrap.image {
@@ -212,10 +209,30 @@ bootstrap.pages.override {
 	subtitlecolor =
 }
 
+bootstrap.fontawesome {
+	# cat=bootstrap-fontawesome/a-fontawesome/10; type=boolean; label=FONT AWESOME - using SVG & JS (if enabled) or Web Fonts & CSS (if disabled):Font Awesome comes with two different web frameworks for easily using icons on the web: our original Web Fonts & CSS method and our newer SVG & JS framework. Each has benefits and caveats - pick the one that works best for your project and situation.
+	svgJs = 0
+	# cat=bootstrap-fontawesome/a-fontawesome/20; type=small; label=Your FA6 KIT code:is only required if "FA6-KIT" & "CDN" is activated 
+	kitcode = 
+	# cat=bootstrap-fontawesome/b-fontawesome/20; type=boolean; label=Brands:
+	brands = 1
+	# cat=bootstrap-fontawesome/b-fontawesome/30; type=boolean; label=Solid:
+	solid = 1
+	# cat=bootstrap-fontawesome/b-fontawesome/40; type=boolean; label=Regular:
+	regular = 1
+	# cat=bootstrap-fontawesome/b-fontawesome/50; type=boolean; label=Light (FA6 Pro only):
+	light = 0
+	# cat=bootstrap-fontawesome/b-fontawesome/60; type=boolean; label=Thin (FA6 Pro only):
+	thin = 0
+	# cat=bootstrap-fontawesome/b-fontawesome/70; type=boolean; label=Duotone (FA6 Pro only):
+	duotone = 0
+}
+
 
 #-------------------------------------------------------------------------------
 #	NOT in Constant Editor
 #-------------------------------------------------------------------------------
+
 # include Bootstraps bundle.min.js (include popper.js)
 bootstrap.bundle.enable = 1
 
@@ -233,29 +250,23 @@ bootstrap.config.enableUtilityColors = 1
 # hints to increase the website speed in the BE Modul
 bootstrap.config.enableInfo = 1
 
-bootstrap.config.sectionMenuClass = 0
+bootstrap.config.sectionMenuClass = 
 
 # include print template
 bootstrap.print.enable = 0
 
-# Custom path to your custom.scss files: e.g.: fileadmin/T3SB/Resources/Public/SCSS/ (clear cache and run the Scheduler).
-bootstrap.customScssPath = fileadmin/T3SB/Resources/Public/SCSS/
-
 # disable default CSS - t3sbootstrap.css
 bootstrap.config.disableDefaultCss = 0
 
 # back to top button
 bootstrap.backToTopTitle = to top
-bootstrap.backToTopClass = fa fa-chevron-circle-up fa-4x
+bootstrap.backToTopClass = fa-solid fa-circle-chevron-up fa-4x
+
 bootstrap.backToTopForAllPages = 0
 
-# Preload the google fonts includedby bootstrap.cdn.googlefonts if activated (execute scheduler task t3sbootstrap:cdnToLocal)
-bootstrap.preloadGooleFonts = 0
 # font-weights for Google fonts (regular == 400)
 bootstrap.gooleFontsWeights = 300, regular, 700
 
-# GTM Account ID - include the Google Tag Manager if entered
-bootstrap.gtm = 0
 
 # disable jQuery by default
 bootstrap.disable.jquery = 1
@@ -266,6 +277,7 @@ bootstrap.config.jqueryHeader = 0
 bootstrap.disable.accordion.scrollToTop = 0
 
 bootstrap.navbar {
+	noLinkTitle = 
 	image.defaultPath = EXT:t3sbootstrap/Resources/Public/Images/bootstrap-logo-white.svg
 	image.width = 30
 	image.height = 24
@@ -291,29 +303,6 @@ bootstrap.navbar {
 # style one for the submenu (0 = default)
 bootstrap.submenu.styleOne = 0
 
-# enable in EM config (info: https://github.com/insites/cookieconsent)
-bootstrap.cookieconsent {
-	# info, opt-in or opt-out
-	type = info
-	popup.background = #000
-	popup.text = #fff
-	button.background = #f1d600
-	button.text = #000
-	# block (default), edgeless, classic
-	theme = edgeless
-	# top, bottom, top-left, top-right, bottom-left, bottom-right
-	position = top
-	message = Diese Website setzt Cookies und verwendet Google Analytics. Durch die Nutzung unserer Website erklären Sie sich damit einverstanden.
-	dismiss = Info ausblenden
-	allow = zulassen
-	link = Mehr erfahren
-	deny = Cookies ablehnen
-	href = /datenschutzerklaerung/
-	revokeBtn = 
Cookie Optionen
- regionalLaw = false - location = true -} - # Color mode toggler - only if "bootstrap.config.navbarDarkMode" is disabled bootstrap.colorMode { enable = 0 @@ -321,7 +310,7 @@ bootstrap.colorMode { position = position-fixed bottom-0 end-0 mb-3 me-3 } -styles.content.allowTags:= addToList( s, mark) +styles.content.allowTags:= addToList( div, s, mark) # in px (preset) styles.content.textmedia.maxW = 1320 @@ -347,18 +336,7 @@ pages.override { dropdownRight = } -# Prevents a LOG ERROR "TYPO3.CMS.Frontend.Configuration.TypoScript.ConditionMatching.ConditionMatcher": Expression could not be parsed -bootstrap.config.uid = 1 -bootstrap.config.lightboxSelection = 0 -bootstrap.config.faLinkIcons = 0 -bootstrap.config.backgroundImageEnable = 0 -bootstrap.config.footerSticky = 0 -bootstrap.config.compress = -bootstrap.config.navbarBreakpoint = [loaded('felogin')] plugin.tx_felogin_login.view.templateRootPath = EXT:t3sbootstrap/Resources/Private/Extensions/felogin/Resources/Private/Templates/ -[global] - -// import outsourced constants from DB -@import 'fileadmin/T3SB/Configuration/TypoScript/t3sbconstants.typoscript' +[END] diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index c996aa72..e476c21c 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -6,6 +6,7 @@ module.tx_t3sbootstrap { layoutRootPaths.0 = EXT:t3sbootstrap/Resources/Private/Backend/Layouts/ } settings { + sitepackage = {$bootstrap.extconf.sitepackage} customScss = {$bootstrap.extconf.customScss} customScssPath = {$bootstrap.customScssPath} editScss = {$bootstrap.extconf.editScss} @@ -21,7 +22,6 @@ module.tx_t3sbootstrap { compress = {$bootstrap.config.compress} lazyLoad = {$bootstrap.extconf.lazyLoad} webp = {$bootstrap.ext.webp} - gtm = {$bootstrap.gtm} navbarBreakpoint = {$bootstrap.config.navbarBreakpoint} breakpoint.sm = {$bootstrap.navbar.breakpoint.sm} breakpoint.md = {$bootstrap.navbar.breakpoint.md} @@ -29,7 +29,6 @@ module.tx_t3sbootstrap { breakpoint.xl = {$bootstrap.navbar.breakpoint.xl} breakpoint.xxl = {$bootstrap.navbar.breakpoint.xxl} disableJquery = {$bootstrap.disable.jquery} - preloadGooleFonts = {$bootstrap.preloadGooleFonts} gooleFontsWeights = {$bootstrap.gooleFontsWeights} cdn { // Versions @@ -40,7 +39,6 @@ module.tx_t3sbootstrap { bootswatch = {$bootstrap.cdn.bootswatch} jquery = {$bootstrap.cdn.jquery} jqueryEasing = {$bootstrap.cdn.jqueryEasing} - highlight = {$bootstrap.cdn.highlight} fontawesome = {$bootstrap.cdn.fontawesome} lazyload = {$bootstrap.cdn.lazyload} picturefill = {$bootstrap.cdn.picturefill} @@ -48,7 +46,6 @@ module.tx_t3sbootstrap { baguetteBox = {$bootstrap.cdn.baguetteBox} halkabox = {$bootstrap.cdn.halkabox} glightbox = {$bootstrap.cdn.glightbox} - cookieconsent = {$bootstrap.cdn.cookieconsent} masonry = {$bootstrap.cdn.masonry} jarallax = {$bootstrap.cdn.jarallax} swiper = {$bootstrap.cdn.swiper} @@ -131,27 +128,6 @@ temp.pagelayout { @import 'EXT:t3sbootstrap/Configuration/TypoScript/Content/_main.typoscript' @import 'EXT:t3sbootstrap/Configuration/TypoScript/ContentElement/_main.typoscript' -########################################################################################################## -# -# Google Tag Manager -# -########################################################################################################## - -[{$bootstrap.gtm} && {$bootstrap.extconf.cookieconsent} == 1 && request.getCookieParams()['cookieconsent_status'] == 'allow'] -page.includeJS.gtm = https://www.googletagmanager.com/gtag/js?id={$bootstrap.gtm} -page.includeJS.gtm.external = 1 -page.includeJS.gtm.async = 1 -page.jsInline.1 = TEXT -page.jsInline.1.value ( - // Google Tag Manager - window.dataLayer = window.dataLayer || []; - function gtag(){dataLayer.push(arguments);} - gtag('js', new Date()); - gtag('config', '{$bootstrap.gtm}'); - -) -[global] - [applicationContext == "Development"] config { diff --git a/Contrib/scssphp/composer.json b/Contrib/scssphp/composer.json index f81203dd..d17ffb92 100644 --- a/Contrib/scssphp/composer.json +++ b/Contrib/scssphp/composer.json @@ -43,7 +43,7 @@ "thoughtbot/bourbon": "^7.0", "twbs/bootstrap": "~5.0", "twbs/bootstrap4": "4.6.1", - "zurb/foundation": "~6.5" + "zurb/foundation": "~6.7.0" }, "repositories": [ { diff --git a/Contrib/scssphp/src/Compiler.php b/Contrib/scssphp/src/Compiler.php index ecafc8cb..86c3a8ab 100644 --- a/Contrib/scssphp/src/Compiler.php +++ b/Contrib/scssphp/src/Compiler.php @@ -458,10 +458,33 @@ public function compile($code, $path = null) } /** - * Compile scss + * Compiles the provided scss file into CSS. + * + * @param string $path + * + * @return CompilationResult + * + * @throws SassException when the source fails to compile + */ + public function compileFile($path) + { + $source = file_get_contents($path); + + if ($source === false) { + throw new \RuntimeException('Could not read the file content'); + } + + return $this->compileString($source, $path); + } + + /** + * Compiles the provided scss source code into CSS. + * + * If provided, the path is considered to be the path from which the source code comes + * from, which will be used to resolve relative imports. * * @param string $source - * @param string|null $path + * @param string|null $path The path for the source, used to resolve relative imports * * @return CompilationResult * @@ -1508,6 +1531,7 @@ protected function filterScopeWithWithout($scope, $with, $without) // start from the root while ($scope->parent && $scope->parent->type !== Type::T_ROOT) { array_unshift($childStash, $scope); + \assert($scope->parent !== null); $scope = $scope->parent; } @@ -2090,6 +2114,11 @@ protected function collapseSelectors($selectors) foreach ($selector as $node) { $compound = ''; + if (!is_array($node)) { + $output[] = $node; + continue; + } + array_walk_recursive( $node, function ($value, $key) use (&$compound) { @@ -2124,12 +2153,16 @@ private function collapseSelectorsAsList($selectors) foreach ($selector as $node) { $compound = ''; - array_walk_recursive( - $node, - function ($value, $key) use (&$compound) { - $compound .= $value; - } - ); + if (!is_array($node)) { + $compound .= $node; + } else { + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + } if ($this->isImmediateRelationshipCombinator($compound)) { if (\count($output)) { @@ -2885,7 +2918,7 @@ protected function compileChild($child, OutputBlock $out) { if (isset($child[Parser::SOURCE_LINE])) { $this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ? $child[Parser::SOURCE_INDEX] : null; - $this->sourceLine = isset($child[Parser::SOURCE_LINE]) ? $child[Parser::SOURCE_LINE] : -1; + $this->sourceLine = $child[Parser::SOURCE_LINE]; $this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ? $child[Parser::SOURCE_COLUMN] : -1; } elseif (\is_array($child) && isset($child[1]->sourceLine) && $child[1] instanceof Block) { $this->sourceIndex = $child[1]->sourceIndex; @@ -4529,8 +4562,10 @@ public function compileValue($value, $quote = true) return $colorName; } - if (is_numeric($alpha)) { + if (\is_int($alpha) || \is_float($alpha)) { $a = new Number($alpha, ''); + } elseif (is_numeric($alpha)) { + $a = new Number((float) $alpha, ''); } else { $a = $alpha; } @@ -6984,10 +7019,14 @@ protected function coerceValue($value) return static::$null; } - if (is_numeric($value)) { + if (\is_int($value) || \is_float($value)) { return new Number($value, ''); } + if (is_numeric($value)) { + return new Number((float) $value, ''); + } + if ($value === '') { return static::$emptyString; } diff --git a/Contrib/scssphp/src/OutputStyle.php b/Contrib/scssphp/src/OutputStyle.php index c284639c..a1d8b425 100644 --- a/Contrib/scssphp/src/OutputStyle.php +++ b/Contrib/scssphp/src/OutputStyle.php @@ -1,9 +1,62 @@ saveEncoding(); $this->extractLineNumbers($buffer); + if ($this->utf8 && !preg_match('//u', $buffer)) { + $message = $this->sourceName ? 'Invalid UTF-8 file: ' . $this->sourceName : 'Invalid UTF-8 file'; + throw new ParserException($message); + } + $this->pushBlock(null); // root block $this->whitespace(); $this->pushBlock(null); @@ -323,6 +328,13 @@ public function parseValue($buffer, &$out) $list = $this->valueList($out); + if ($this->count !== \strlen($this->buffer)) { + $error = $this->parseError('Expected end of value'); + $message = 'Passing trailing content after the expression when parsing a value is deprecated since Scssphp 1.12.0 and will be an error in 2.0. ' . $error->getMessage(); + + @trigger_error($message, E_USER_DEPRECATED); + } + $this->restoreEncoding(); return $list; @@ -1678,9 +1690,9 @@ protected function whitespace() */ protected function appendComment($comment) { - assert($this->env !== null); - if (! $this->discardComments) { + assert($this->env !== null); + $this->env->comments[] = $comment; } } diff --git a/Contrib/scssphp/src/Version.php b/Contrib/scssphp/src/Version.php index d604a505..17394ce5 100644 --- a/Contrib/scssphp/src/Version.php +++ b/Contrib/scssphp/src/Version.php @@ -19,5 +19,5 @@ */ class Version { - const VERSION = '1.11.0'; + const VERSION = '1.12.0'; } diff --git a/Resources/Private/Backend/Templates/Config/Constants.html b/Resources/Private/Backend/Templates/Config/Constants.html index 19b9120a..00173e71 100644 --- a/Resources/Private/Backend/Templates/Config/Constants.html +++ b/Resources/Private/Backend/Templates/Config/Constants.html @@ -7,7 +7,7 @@
-

Overview of the provided, outsourced constants

+

Overview of the provided, outsourced constants from {f:if(condition: '{settings.sitepackage}', then: 'EXT:t3sb_package', else: '/fileadmin/')}

@@ -26,6 +26,7 @@

Overview of the provided, outsourced constants + - \ No newline at end of file + diff --git a/Resources/Private/Backend/Templates/Config/Dashboard.html b/Resources/Private/Backend/Templates/Config/Dashboard.html index 49d264cc..00e50c7f 100644 --- a/Resources/Private/Backend/Templates/Config/Dashboard.html +++ b/Resources/Private/Backend/Templates/Config/Dashboard.html @@ -386,6 +386,18 @@
+ + + + + + + + + Sitepackage +

@@ -428,17 +440,6 @@
-
  • - - - - - - - - - Codesnippet -
  • @@ -515,17 +516,6 @@
    - - - - - - - - - Cookieconsent -
  • diff --git a/Resources/Private/Backend/Templates/Config/Edit.html b/Resources/Private/Backend/Templates/Config/Edit.html index 9b5bd7f2..ef6c1c66 100644 --- a/Resources/Private/Backend/Templates/Config/Edit.html +++ b/Resources/Private/Backend/Templates/Config/Edit.html @@ -23,7 +23,7 @@

    Edit Configuration

    The data entered here are provided as outsourced constants.
    - (fileadmin/T3SB/Configuration/TypoScript/t3sbconstants.typoscript) + (t3sb_package/.. or fileadmin/T3SB/Configuration/TypoScript/t3sbconstants.typoscript)

    The snippets in red font color are the constants you can use to override the settings in your constants - if you prefer this!

    diff --git a/Resources/Private/Backend/Templates/Config/List.html b/Resources/Private/Backend/Templates/Config/List.html index db1be5fb..c0c87b64 100644 --- a/Resources/Private/Backend/Templates/Config/List.html +++ b/Resources/Private/Backend/Templates/Config/List.html @@ -133,7 +133,6 @@

    Global pages override is set in Constant Editor:

  • - @@ -188,18 +187,9 @@

    Global pages override is set in Constant Editor:

    - - -

    - Custom SCSS is activated. -

    -
    - -

    - Custom SCSS is not activated. -

    -
    -
    +

    + Custom SCSS is not activated. +

    diff --git a/Resources/Private/Extensions/indexed_search/Resources/Private/Partials/Searchresult.html b/Resources/Private/Extensions/indexed_search/Resources/Private/Partials/Searchresult.html index d356eafa..dee97c66 100644 --- a/Resources/Private/Extensions/indexed_search/Resources/Private/Partials/Searchresult.html +++ b/Resources/Private/Extensions/indexed_search/Resources/Private/Partials/Searchresult.html @@ -2,7 +2,7 @@

    - + {row.result_number} {row.title -> f:format.raw()} {row.rating} diff --git a/Resources/Private/Extensions/news/Configuration/TypoScript/setup.typoscript b/Resources/Private/Extensions/news/Configuration/TypoScript/setup.typoscript index 63c7fdea..9faddf50 100644 --- a/Resources/Private/Extensions/news/Configuration/TypoScript/setup.typoscript +++ b/Resources/Private/Extensions/news/Configuration/TypoScript/setup.typoscript @@ -19,6 +19,7 @@ plugin.tx_news { settings { cssFile = detail.lightbox.selection = {$bootstrap.config.lightboxSelection} +# detail.carousel = {$settings.detail.carousel} media.minWidth = {$bootstrap.image.minimumWidth} loadingSpinner = {$bootstrap.config.loadingSpinner} loadingSpinnerColor = {$bootstrap.config.loadingSpinnerColor} @@ -36,6 +37,7 @@ plugin.tx_news { glightboxVersion = {$bootstrap.cdn.glightbox} halkaboxVersion = {$bootstrap.cdn.halkabox} jqueryDisable = {$bootstrap.disable.jquery} + sitepackage = {$bootstrap.extconf.sitepackage} } _LOCAL_LANG.de.more-link = mehr diff --git a/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/Detail.html b/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/Detail.html index 6717bb9a..2f67b495 100644 --- a/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/Detail.html +++ b/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/Detail.html @@ -21,7 +21,7 @@ - +

    - -
    - {newsItem.bodytext} -
    + + +
    + {newsItem.bodytext} +
    +
    diff --git a/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/T3sbMediaContainer.html b/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/T3sbMediaContainer.html index f204b0b1..0ce11ee0 100644 --- a/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/T3sbMediaContainer.html +++ b/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/T3sbMediaContainer.html @@ -40,11 +40,11 @@