diff --git a/Classes/Command/CdnToLocal.php b/Classes/Command/CdnToLocal.php index 19f779b5..44843ff6 100644 --- a/Classes/Command/CdnToLocal.php +++ b/Classes/Command/CdnToLocal.php @@ -10,6 +10,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManager; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; +use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; /* * This file is part of the TYPO3 extension t3sbootstrap. @@ -53,6 +54,25 @@ protected function execute(InputInterface $input, OutputInterface $output) 't3sbootstrap', 'm1' ); + + # check FA version & settings + $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('t3sbootstrap'); + if ( !empty($extConf['fontawesomeCss']) ) { + if ( (int)$extConf['fontawesomeCss'] < 3 ) { + # v5 + if ( (int)$settings['cdn']['fontawesome'] > 5 ) { + $settings['cdn']['fontawesome'] = $settings['cdn']['fontawesome5latest']; + } + } elseif ( (int)$extConf['fontawesomeCss'] > 2 ) { + # v6 + if ( (int)$settings['cdn']['fontawesome'] < 6 ) { + $settings['cdn']['fontawesome'] = $settings['cdn']['fontawesome6latest']; + } + } + } else { + $settings['cdn']['fontawesome'] = '5.15.4'; + } + foreach ($settings['cdn'] as $key=>$version) { if ($key == 'jquery') { diff --git a/Classes/Command/CustomScss.php b/Classes/Command/CustomScss.php index bc2cdae0..4922017d 100644 --- a/Classes/Command/CustomScss.php +++ b/Classes/Command/CustomScss.php @@ -59,8 +59,6 @@ protected function execute(InputInterface $input, OutputInterface $output) if ( $settings['customScss'] && array_key_exists('customScss', $extConf) && $extConf['customScss'] === '1' ) { - - # get the Boostrap SCSS-Files $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'; @@ -154,7 +152,6 @@ protected function execute(InputInterface $input, OutputInterface $output) # 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('*') @@ -167,7 +164,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $siteroots = $result->fetchAll(); foreach ($siteroots as $key=>$siteroot) { - if ($key === 0) { $customFileName = 'custom-variables.scss'; $customFileNameOverride = 'custom.scss'; @@ -267,17 +263,18 @@ 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 ($keepVariables === 0) { + } elseif (empty($keepVariables)) { unlink($customFile); } } - - if (!file_exists($customFile) && $keepVariables === 0) { + if (!file_exists($customFile) && empty($keepVariables)) { if (!is_dir($customPath)) { mkdir($customPath, 0777, true); } diff --git a/Classes/Components/Card.php b/Classes/Components/Card.php index 20866a19..c2dd68ec 100644 --- a/Classes/Components/Card.php +++ b/Classes/Components/Card.php @@ -112,9 +112,8 @@ public function getProcessedData(array $processedData, array $flexconf): array $cardData['block']['enable'] = TRUE; } // class - $cardClass = 'card'; - $cardClass .= $processedData['class']; - $cardClass .= !empty($parentflexconf['equalHeight']) ? ' h-100' : ''; + $cardClass = $processedData['class']; + $cardClass .= ' card'; if ( $processedData['data']['tx_t3sbootstrap_textcolor'] ) { $cardClass .= ' text-'.$processedData['data']['tx_t3sbootstrap_textcolor']; diff --git a/Classes/Controller/ConfigController.php b/Classes/Controller/ConfigController.php index f721a842..794d1fa8 100644 --- a/Classes/Controller/ConfigController.php +++ b/Classes/Controller/ConfigController.php @@ -752,7 +752,7 @@ protected function setDefaults(Config $newConfig): Config $newConfig->setNavbarAlignment( 'left' ); $newConfig->setNavbarBrand( 'imgText' ); $newConfig->setNavbarContainer( 'inside' ); - $newConfig->setNavbarClass('bg-gradient'); + $newConfig->setNavbarClass(''); $newConfig->setJumbotronEnable( 1 ); $newConfig->setJumbotronSlide( 0 ); $newConfig->setJumbotronPosition( 'below' ); @@ -760,7 +760,7 @@ protected function setDefaults(Config $newConfig): Config $newConfig->setJumbotronContainerposition( 'Inside' ); $newConfig->setJumbotronCarouselInterval(5000); $newConfig->setJumbotronCarouselPause(0); - $newConfig->setJumbotronClass( 'p-5 mb-4 bg-light bg-gradient rounded-0' ); + $newConfig->setJumbotronClass( 'p-5 mb-4 bg-light rounded-0' ); $newConfig->setBreadcrumbEnable( 1 ); $newConfig->setBreadcrumbCorner( 1 ); $newConfig->setBreadcrumbPosition( 'belowJum' ); diff --git a/Classes/DataProcessing/GalleryProcessor.php b/Classes/DataProcessing/GalleryProcessor.php index 33888411..a627bffb 100644 --- a/Classes/DataProcessing/GalleryProcessor.php +++ b/Classes/DataProcessing/GalleryProcessor.php @@ -700,9 +700,12 @@ protected function calculateMediaWidthsAndHeights() // Set the corrected dimensions for each media element foreach ($this->fileObjects as $key => $fileObject) { - $mediaHeight = $this->equalMediaHeight; - $mediaWidth = $this->getCroppedDimensionalProperty($fileObject, 'width') - * ($mediaHeight / max($this->getCroppedDimensionalProperty($fileObject, 'height'), 1)); + $mediaHeight = $this->equalMediaHeight; + if (is_array($fileObject)) { + $fileObject = $fileObject[0]; + } + $mediaWidth = $this->getCroppedDimensionalProperty($fileObject, 'width') + * ($mediaHeight / max($this->getCroppedDimensionalProperty($fileObject, 'height'), 1)); $this->mediaDimensions[$key] = [ 'width' => floor($mediaWidth), diff --git a/Classes/Layouts/FourColumns.php b/Classes/Layouts/FourColumns.php index c0d57c3c..47d93840 100644 --- a/Classes/Layouts/FourColumns.php +++ b/Classes/Layouts/FourColumns.php @@ -25,6 +25,8 @@ public function getProcessedData(array $processedData, array $flexconf): array $processedData = GeneralUtility::makeInstance(Gutters::class)->getGutters($processedData, $flexconf); $processedData = GeneralUtility::makeInstance(Grid::class)->getGrid($processedData, $flexconf); + $processedData['equalHeight'] = !empty($flexconf['equalHeight']) ? ' d-flex align-items-stretch' : ''; + return $processedData; } diff --git a/Classes/Layouts/SixColumns.php b/Classes/Layouts/SixColumns.php index d372d744..74ef8418 100644 --- a/Classes/Layouts/SixColumns.php +++ b/Classes/Layouts/SixColumns.php @@ -25,6 +25,8 @@ public function getProcessedData(array $processedData, array $flexconf): array $processedData = GeneralUtility::makeInstance(Gutters::class)->getGutters($processedData, $flexconf); $processedData = GeneralUtility::makeInstance(Grid::class)->getGrid($processedData, $flexconf); + $processedData['equalHeight'] = !empty($flexconf['equalHeight']) ? ' d-flex align-items-stretch' : ''; + return $processedData; } diff --git a/Classes/Layouts/ThreeColumns.php b/Classes/Layouts/ThreeColumns.php index 09200c47..dd30e3ed 100644 --- a/Classes/Layouts/ThreeColumns.php +++ b/Classes/Layouts/ThreeColumns.php @@ -25,6 +25,8 @@ public function getProcessedData(array $processedData, array $flexconf): array $processedData = GeneralUtility::makeInstance(Gutters::class)->getGutters($processedData, $flexconf); $processedData = GeneralUtility::makeInstance(Grid::class)->getGrid($processedData, $flexconf); + $processedData['equalHeight'] = !empty($flexconf['equalHeight']) ? ' d-flex align-items-stretch' : ''; + return $processedData; } diff --git a/Classes/Layouts/TwoColumns.php b/Classes/Layouts/TwoColumns.php index 341cfaa0..168dd3e0 100644 --- a/Classes/Layouts/TwoColumns.php +++ b/Classes/Layouts/TwoColumns.php @@ -41,6 +41,7 @@ public function getProcessedData(array $processedData, array $flexconf, bool $we $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 7bdbd9c7..c0bb022c 100644 --- a/Classes/Parser/AbstractParser.php +++ b/Classes/Parser/AbstractParser.php @@ -15,80 +15,116 @@ */ abstract class AbstractParser implements ParserInterface { - - public function supports(string $extension): bool - { - return false; - } - - public function compile(string $file, array $settings): string - { - return $file; - } - - protected function isCached(string $file, array $settings): bool - { - $cacheIdentifier = $this->getCacheIdentifier($file, $settings); - $cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']); - $cacheFileMeta = $this->getCacheFileMeta($cacheFile); - - return file_exists($cacheFile) && file_exists($cacheFileMeta); - } - - protected function needsCompile(string $cacheFile, string $cacheFileMeta, array $settings): bool - { - $needCompilation = false; - $fileModificationTime = filemtime($cacheFile); - $metadata = unserialize((string) file_get_contents($cacheFileMeta), ['allowed_classes' => false]); - - foreach ($metadata['files'] as $file) { - if (filemtime($file) > $fileModificationTime) { - $needCompilation = true; - break; - } - } - - if (!$needCompilation && $settings['variables'] !== $metadata['variables']) { - $needCompilation = true; - } - - if (!$needCompilation && $settings['options']['sourceMap'] !== $metadata['sourceMap']) { - $needCompilation = true; - } - - return $needCompilation; - } - - protected function getCacheFile(string $cacheIdentifier, string $tempDirectory): string - { - return $tempDirectory . $cacheIdentifier . '.css'; - } - - protected function getCacheFileMeta(string $filename): string - { - return $filename . '.meta'; - } - - protected function getCacheIdentifier(string $file, array $settings): string - { - $filehash = md5($file); - $hash = hash('sha256', $filehash . serialize($settings)); - $extension = pathinfo($file, PATHINFO_EXTENSION); - - return basename($file, '.' . $extension) . '-' . $hash; - } - - protected function getPathSite(): string - { - return Environment::getPublicPath() . '/'; - } - - /** - * Clear all page caches - * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheGroupException - */ - protected function clearPageCaches(): void - { - GeneralUtility::makeInstance(CacheManager::class)->flushCachesInGroup('pages'); - } + /** + * @param string $extension + * @return bool + */ + public function supports(string $extension): bool + { + return false; + } + + /** + * @param string $file + * @param array $settings + * @return string + */ + public function compile(string $file, array $settings): string + { + return $file; + } + + /** + * @param string $file + * @param array $settings + * @return bool + */ + protected function isCached(string $file, array $settings): bool + { + $cacheIdentifier = $this->getCacheIdentifier($file, $settings); + $cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']); + $cacheFileMeta = $this->getCacheFileMeta($cacheFile); + + return file_exists($cacheFile) && file_exists($cacheFileMeta); + } + + /** + * @param string $cacheFile + * @param string $cacheFileMeta + * @param array $settings + * @return bool + */ + protected function needsCompile(string $cacheFile, string $cacheFileMeta, array $settings): bool + { + $needCompilation = false; + $fileModificationTime = filemtime($cacheFile); + $metadata = unserialize((string) file_get_contents($cacheFileMeta), ['allowed_classes' => false]); + + foreach ($metadata['files'] as $file) { + if (filemtime($file) > $fileModificationTime) { + $needCompilation = true; + break; + } + } + + if (!$needCompilation && $settings['variables'] !== $metadata['variables']) { + $needCompilation = true; + } + + if (!$needCompilation && $settings['options']['sourceMap'] !== $metadata['sourceMap']) { + $needCompilation = true; + } + + return $needCompilation; + } + + /** + * @param string $cacheIdentifier + * @param string $tempDirectory + * @return string + */ + protected function getCacheFile(string $cacheIdentifier, string $tempDirectory): string + { + return $tempDirectory . $cacheIdentifier . '.css'; + } + + /** + * @param string $filename + * @return string + */ + protected function getCacheFileMeta(string $filename) + { + return $filename . '.meta'; + } + + /** + * @param string $file + * @param array $settings + * @return string + */ + protected function getCacheIdentifier(string $file, array $settings): string + { + $filehash = md5($file); + $hash = hash('sha256', $filehash . serialize($settings)); + $extension = pathinfo($file, PATHINFO_EXTENSION); + + return basename($file, '.' . $extension) . '-' . $hash; + } + + /** + * @return string + */ + protected function getPathSite(): string + { + return Environment::getPublicPath() . '/'; + } + + /** + * Clear all page caches + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheGroupException + */ + protected function clearPageCaches(): void + { + GeneralUtility::makeInstance(CacheManager::class)->flushCachesInGroup('pages'); + } } diff --git a/Classes/Parser/ParserInterface.php b/Classes/Parser/ParserInterface.php index e55b3fd3..77c4a509 100644 --- a/Classes/Parser/ParserInterface.php +++ b/Classes/Parser/ParserInterface.php @@ -11,7 +11,16 @@ */ interface ParserInterface { - public function supports(string $extension): bool; + /** + * @param string $extension + * @return bool + */ + public function supports(string $extension): bool; - public function compile(string $file, array $settings): string; + /** + * @param string $file + * @param array $settings + * @return string + */ + public function compile(string $file, array $settings): string; } diff --git a/Classes/Parser/ScssParser.php b/Classes/Parser/ScssParser.php index b54a472a..4ec58f53 100644 --- a/Classes/Parser/ScssParser.php +++ b/Classes/Parser/ScssParser.php @@ -19,84 +19,98 @@ */ class ScssParser extends AbstractParser { - /** - * Constructor - */ - public function __construct() - { - if (!class_exists('ScssPhp\ScssPhp\Version')) { - require_once ExtensionManagementUtility::extPath('t3sbootstrap') . '/Contrib/scssphp/scss.inc.php'; - } - } - - public function supports(string $extension): bool - { - return $extension === 'scss'; - } - - public function compile(string $file, array $settings): string - { - $cacheIdentifier = $this->getCacheIdentifier($file, $settings); - $cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']); - $cacheFileMeta = $this->getCacheFileMeta($cacheFile); - $compile = false; - - if (!$this->isCached($file, $settings) - || $this->needsCompile($cacheFile, $cacheFileMeta, $settings)) { - $compile = true; - } - - if ($compile) { - $result = $this->parseFile($file, $settings); - GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFile), $result['css']); - GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFileMeta), serialize($result['cache'])); - $this->clearPageCaches(); - } - - return $cacheFile; - } - - protected function parseFile(string $file, array $settings): array - { - $scss = new Compiler(); - $scss->setOutputStyle(OutputStyle::COMPRESSED); - $scss->addVariables($settings['variables']); - if ($settings['options']['sourceMap']) { - $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); - $scss->setSourceMapOptions([ - 'sourceMapRootpath' => $settings['cache']['tempDirectoryRelativeToRoot'], - 'sourceMapBasepath' => '' - ]); - } - $absoluteFilename = $settings['file']['absolute']; - // Adds visual directory path of the initial file as import path - // This scenarios happens, when e.g. developing packages using the `path` - // repository feature of Composer - having one package in `public/typo3conf/ext/` - // and the other one symlinked in e.g. `packages/`. - // Since the PHP SCSS parser works on resolved real paths, the symlinked context is lost. - $visualImportPath = dirname($absoluteFilename); - $scss->addImportPath(function ($url) use ($visualImportPath): ?string { - // Resolve potential back paths manually using PathUtility::getCanonicalPath, - // but make sure we do not break out of TYPO3 application path using GeneralUtility::getFileAbsFileName - // Also resolve EXT: paths if given - $isTypo3Absolute = (strpos($url, 'EXT:') === 0) || PathUtility::isAbsolutePath($url); - $fileName = $isTypo3Absolute ? $url : $visualImportPath . '/' . $url; - $full = GeneralUtility::getFileAbsFileName(PathUtility::getCanonicalPath($fileName)); - // The API forces us to check the existence of files paths, with or without url. - // We must only return a string if the file to be imported actually exists. - $hasExtension = (bool) preg_match('/[.]s?css$/', $url); - if ( - is_file($file = $full . '.scss') || - ($hasExtension && is_file($file = $full)) - ) { - // We could trigger a deprecation message here at some point - return $file; - } - - return null; - }); - // Add extensions path to import paths, so that we can use paths relative to this directory to resolve imports - $scss->addImportPath(Environment::getExtensionsPath()); + /** + * Constructor + */ + public function __construct() + { + if (!class_exists('ScssPhp\ScssPhp\Version')) { + require_once ExtensionManagementUtility::extPath('t3sbootstrap') . '/Contrib/scssphp/scss.inc.php'; + } + } + + /** + * @param string $extension + * @return bool + */ + public function supports(string $extension): bool + { + return $extension === 'scss'; + } + + /** + * @param string $file + * @param array $settings + * @return string + */ + public function compile(string $file, array $settings): string + { + $cacheIdentifier = $this->getCacheIdentifier($file, $settings); + $cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']); + $cacheFileMeta = $this->getCacheFileMeta($cacheFile); + $compile = false; + + if (!$this->isCached($file, $settings) + || $this->needsCompile($cacheFile, $cacheFileMeta, $settings)) { + $compile = true; + } + + if ($compile) { + $result = $this->parseFile($file, $settings); + GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFile), $result['css']); + GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFileMeta), serialize($result['cache'])); + $this->clearPageCaches(); + } + + return $cacheFile; + } + + /** + * @param string $file + * @param array $settings + * @return array + */ + protected function parseFile(string $file, array $settings): array + { + $scss = new Compiler(); + $scss->setOutputStyle(OutputStyle::COMPRESSED); + $scss->addVariables($settings['variables']); + if ($settings['options']['sourceMap']) { + $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); + $scss->setSourceMapOptions([ + 'sourceMapRootpath' => $settings['cache']['tempDirectoryRelativeToRoot'], + 'sourceMapBasepath' => '' + ]); + } + $absoluteFilename = $settings['file']['absolute']; + // Adds visual directory path of the initial file as import path + // This scenarios happens, when e.g. developing packages using the `path` + // repository feature of Composer - having one package in `public/typo3conf/ext/` + // and the other one symlinked in e.g. `packages/`. + // Since the PHP SCSS parser works on resolved real paths, the symlinked context is lost. + $visualImportPath = dirname($absoluteFilename); + $scss->addImportPath(function ($url) use ($visualImportPath): ?string { + // Resolve potential back paths manually using PathUtility::getCanonicalPath, + // but make sure we do not break out of TYPO3 application path using GeneralUtility::getFileAbsFileName + // Also resolve EXT: paths if given + $isTypo3Absolute = (strpos($url, 'EXT:') === 0) || PathUtility::isAbsolutePath($url); + $fileName = $isTypo3Absolute ? $url : $visualImportPath . '/' . $url; + $full = GeneralUtility::getFileAbsFileName(PathUtility::getCanonicalPath($fileName)); + // The API forces us to check the existence of files paths, with or without url. + // We must only return a string if the file to be imported actually exists. + $hasExtension = (bool) preg_match('/[.]s?css$/', $url); + if ( + is_file($file = $full . '.scss') || + ($hasExtension && is_file($file = $full)) + ) { + // We could trigger a deprecation message here at some point + return $file; + } + + return null; + }); + // Add extensions path to import paths, so that we can use paths relative to this directory to resolve imports + $scss->addImportPath(Environment::getExtensionsPath()); // Make paths in url() statements relative to site root $absoluteFilePath = dirname($absoluteFilename); @@ -122,28 +136,27 @@ function ($args) use ( } ); - // Compile file - $compilationResult = $scss->compileString('@import "' . $absoluteFilename . '"'); - - $css = $compilationResult->getCss(); - - // Fix paths in url() statements to be relative to temp directory - $relativeTempPath = $settings['cache']['tempDirectoryRelativeToRoot']; - $search = '%url\s*\(\s*[\\\'"]?(?!(((?:https?:)?\/\/)|(?:data:?:)))([^\\\'")]+)[\\\'"]?\s*\)%'; - $replace = 'url("' . $relativeTempPath . '$3")'; - $css = (string) preg_replace($search, $replace, $css); - - return [ - 'css' => $css, - 'cache' => [ - 'version' => Version::VERSION, - 'date' => date('r'), - 'css' => $css, - 'etag' => md5($css), - 'files' => $compilationResult->getIncludedFiles(), - 'variables' => $settings['variables'], - 'sourceMap' => $settings['options']['sourceMap'] - ] - ]; - } + // Compile file + $compilationResult = $scss->compileString('@import "' . $absoluteFilename . '"'); + $css = $compilationResult->getCss(); + + // Fix paths in url() statements to be relative to temp directory + $relativeTempPath = $settings['cache']['tempDirectoryRelativeToRoot']; + $search = '%url\s*\(\s*[\\\'"]?(?!(((?:https?:)?\/\/)|(?:data:?:)))([^\\\'")]+)[\\\'"]?\s*\)%'; + $replace = 'url("' . $relativeTempPath . '$3")'; + $css = (string) preg_replace($search, $replace, $css); + + return [ + 'css' => $css, + 'cache' => [ + 'version' => Version::VERSION, + 'date' => date('r'), + 'css' => $css, + 'etag' => md5($css), + 'files' => $compilationResult->getIncludedFiles(), + 'variables' => $settings['variables'], + 'sourceMap' => $settings['options']['sourceMap'] + ] + ]; + } } diff --git a/Classes/Wrapper/CardWrapper.php b/Classes/Wrapper/CardWrapper.php index a7db62c2..555ebf45 100644 --- a/Classes/Wrapper/CardWrapper.php +++ b/Classes/Wrapper/CardWrapper.php @@ -116,11 +116,14 @@ public function getProcessedData(array $processedData, array $flexconf): array $processedData['autoplay'] = (int)$flexconf['autoplay']; $processedData['delay'] = $flexconf['autoplay'] ? (int)$flexconf['delay'] : 99999999; } + + if ($flexconf['card_wrapper'] == 'deck' && $flexconf['equalHeight']) { + $processedData['equalHeight'] = ' d-flex align-items-stretch'; + } } $processedData['card_wrapper_layout'] = $flexconf['card_wrapper'] ?: ''; - return $processedData; } diff --git a/Configuration/FlexForms/Container/FourColumns.xml b/Configuration/FlexForms/Container/FourColumns.xml index 6badf318..c9987c7d 100644 --- a/Configuration/FlexForms/Container/FourColumns.xml +++ b/Configuration/FlexForms/Container/FourColumns.xml @@ -16,6 +16,15 @@ + + + + + check + 0 + + + diff --git a/Configuration/FlexForms/Container/SixColumns.xml b/Configuration/FlexForms/Container/SixColumns.xml index 2b6aff90..31e9a3bb 100644 --- a/Configuration/FlexForms/Container/SixColumns.xml +++ b/Configuration/FlexForms/Container/SixColumns.xml @@ -17,6 +17,15 @@ + + + + + check + 0 + + + @@ -151,8 +160,6 @@ - - array diff --git a/Configuration/FlexForms/Container/ThreeColumns.xml b/Configuration/FlexForms/Container/ThreeColumns.xml index 89267451..53ac5abb 100644 --- a/Configuration/FlexForms/Container/ThreeColumns.xml +++ b/Configuration/FlexForms/Container/ThreeColumns.xml @@ -16,6 +16,15 @@ + + + + + check + 0 + + + diff --git a/Configuration/FlexForms/Container/TwoColumns.xml b/Configuration/FlexForms/Container/TwoColumns.xml index 3ba21fc6..f9785ab3 100644 --- a/Configuration/FlexForms/Container/TwoColumns.xml +++ b/Configuration/FlexForms/Container/TwoColumns.xml @@ -17,6 +17,15 @@ + + + + + check + 0 + + + diff --git a/Configuration/RTE/CodesnippetFa6.yaml b/Configuration/RTE/CodesnippetFa6.yaml new file mode 100644 index 00000000..9b69d8c2 --- /dev/null +++ b/Configuration/RTE/CodesnippetFa6.yaml @@ -0,0 +1,9 @@ +imports: + - { resource: "EXT:t3sbootstrap/Configuration/RTE/Default.yaml" } + - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6.yaml" } + +editor: + + config: + extraPlugins: + - codesnippet diff --git a/Configuration/RTE/CodesnippetFa6Pro.yaml b/Configuration/RTE/CodesnippetFa6Pro.yaml new file mode 100644 index 00000000..a690d77e --- /dev/null +++ b/Configuration/RTE/CodesnippetFa6Pro.yaml @@ -0,0 +1,13 @@ +imports: + - { resource: "EXT:t3sbootstrap/Configuration/RTE/Default.yaml" } + - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6Pro.yaml" } + +editor: + + config: + contentsCss: + - "EXT:t3sbootstrap/Resources/Public/Backend/t3sbootstrap.css" + - "../../../../../../fileadmin/T3SB/FA5Pro/css/all.min.css" + + extraPlugins: + - codesnippet diff --git a/Configuration/RTE/DefaultFa6.yaml b/Configuration/RTE/DefaultFa6.yaml new file mode 100644 index 00000000..9fd35a85 --- /dev/null +++ b/Configuration/RTE/DefaultFa6.yaml @@ -0,0 +1,3 @@ +imports: + - { resource: "EXT:t3sbootstrap/Configuration/RTE/Default.yaml" } + - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6.yaml" } diff --git a/Configuration/RTE/DefaultFa6Pro.yaml b/Configuration/RTE/DefaultFa6Pro.yaml new file mode 100644 index 00000000..40d9228c --- /dev/null +++ b/Configuration/RTE/DefaultFa6Pro.yaml @@ -0,0 +1,10 @@ +imports: + - { resource: "EXT:t3sbootstrap/Configuration/RTE/Default.yaml" } + - { resource: "EXT:rte_ckeditor_fontawesome/Configuration/RTE/PluginFA6Pro.yaml" } + +editor: + + config: + contentsCss: + - "EXT:t3sbootstrap/Resources/Public/Backend/t3sbootstrap.css" + - "../../../../../../fileadmin/T3SB/FA5Pro/css/all.min.css" diff --git a/Configuration/TypoScript/Page/IncludeCdn.typoscript b/Configuration/TypoScript/Page/IncludeCdn.typoscript index b5d33671..3cd99bf2 100644 --- a/Configuration/TypoScript/Page/IncludeCdn.typoscript +++ b/Configuration/TypoScript/Page/IncludeCdn.typoscript @@ -104,9 +104,8 @@ page { 61 = TEXT 61.value = 61.if { - value = 1 - equals = {$bootstrap.extconf.fontawesomeCss} + value = 1,3 + isInList = {$bootstrap.extconf.fontawesomeCss} } } - } diff --git a/Configuration/TypoScript/Page/IncludeDefault.typoscript b/Configuration/TypoScript/Page/IncludeDefault.typoscript index 9f5c7072..07ed2c79 100644 --- a/Configuration/TypoScript/Page/IncludeDefault.typoscript +++ b/Configuration/TypoScript/Page/IncludeDefault.typoscript @@ -39,6 +39,12 @@ page { value = 2 equals = {$bootstrap.extconf.fontawesomeCss} } + 63 = TEXT + 63.value = + 63.if { + value = 4 + equals = {$bootstrap.extconf.fontawesomeCss} + } } ########################################################################################################## @@ -118,17 +124,21 @@ page.includeJSLibs { # FONTAWESOME - minimal installation with required icons and for link icons set in RTE # ########################################################################################################## -[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} < 2] -page.includeCSS.t3sfontawesomeLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeLink.css -page.includeCSS.t3sfontawesomeLink.if.isTrue = {$bootstrap.extconf.fontawesomeCss} +[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 0] page.includeCSS.t3sfontawesomeMinLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeMinLink.css -page.includeCSS.t3sfontawesomeMinLink.if.isFalse = {$bootstrap.extconf.fontawesomeCss} [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.t3sfontawesomeProLink = 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/fontawesome6Link.css +[END] +[{$bootstrap.config.faLinkIcons} == 1 && {$bootstrap.extconf.fontawesomeCss} == 4] +page.includeCSS.t3sfontawesomeProLink = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesome6ProLink.css +[END] [{$bootstrap.config.faLinkIcons} == 0] page.includeCSS.t3sfontawesomeMin = EXT:t3sbootstrap/Resources/Public/Contrib/Fontawesome/css/fontawesomeMin.css page.includeCSS.t3sfontawesomeMin.if.isFalse = {$bootstrap.extconf.fontawesomeCss} diff --git a/Configuration/TypoScript/Page/IncludeLocal.typoscript b/Configuration/TypoScript/Page/IncludeLocal.typoscript index 9e4fea01..e4c13055 100644 --- a/Configuration/TypoScript/Page/IncludeLocal.typoscript +++ b/Configuration/TypoScript/Page/IncludeLocal.typoscript @@ -83,10 +83,12 @@ page { 61 = TEXT 61.value = 61.if { - value = 1 - equals = {$bootstrap.extconf.fontawesomeCss} + value = 1,3 + isInList = {$bootstrap.extconf.fontawesomeCss} } } + + } diff --git a/Configuration/TypoScript/Page/Template.typoscript b/Configuration/TypoScript/Page/Template.typoscript index 905457b1..07a435a3 100644 --- a/Configuration/TypoScript/Page/Template.typoscript +++ b/Configuration/TypoScript/Page/Template.typoscript @@ -28,6 +28,11 @@ page { settings { // from EM config expandedContent = {$bootstrap.extconf.expandedContent} + 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} codesnippet = {$bootstrap.extconf.codesnippet} lazyLoad = {$bootstrap.extconf.lazyLoad} @@ -41,6 +46,7 @@ page { gtm = {$bootstrap.gtm} bgMediaQueries = {$bootstrap.image.bgMediaQueries} sectionmenuIcons = {$bootstrap.config.sectionmenuIcons} + submenu.styleOne = {$bootstrap.submenu.styleOne} navbar { image.defaultPath = {$bootstrap.navbar.image.defaultPath} image.width = {$bootstrap.navbar.image.width} diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript index 7cc70538..5c6a2ee5 100644 --- a/Configuration/TypoScript/constants.typoscript +++ b/Configuration/TypoScript/constants.typoscript @@ -17,6 +17,9 @@ plugin.tx_t3sbootstrap { # Constant Editor #------------------------------------------------------------------------------- +bootstrap.cdn.fontawesome5latest = 5.15.4 +bootstrap.cdn.fontawesome6latest = 6.1.1 + # customcategory=bootstrap-cdn=* T3SB::CDN- and Version-Settings # customsubcategory=a-enable=CDN (Content Delivery Network) - can offer a performance benefit! # customsubcategory=b-version=CDN Versions used in the scheduler task "T3SB CDN to local" - must be valid @@ -24,7 +27,7 @@ plugin.tx_t3sbootstrap { 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/ 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 (run Scheduler) - Info: https://bootswatch.com/. + # 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/b-version/10; type=small; label=Bootstrap: bootstrap = 5.1.3 @@ -32,7 +35,7 @@ bootstrap.cdn { popperjs = 2.11.5 # cat=bootstrap-cdn/b-version/13; type=small; label=Masonry js: masonry = 4.2.2 - # cat=bootstrap-cdn/b-version/12; type=small; label=Fontawesome: + # cat=bootstrap-cdn/b-version/12; type=small; label=Fontawesome: e.g. 5.15.4 or 6.1.1 fontawesome = 5.15.4 # cat=bootstrap-cdn/b-version/20; type=small; label=jQuery library: jquery = 3.6.0 @@ -64,7 +67,7 @@ bootstrap.cdn { # cat=bootstrap-cdn/c-integrity/11; type=small; label=Bootstrap JS: bootstrapJsIntegrity = sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13 # cat=bootstrap-cdn/c-integrity/12; type=small; label=Popper js: - popperjsIntegrity = sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB + popperjsIntegrity = sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk # cat=bootstrap-cdn/c-integrity/13; type=small; label=Masonry js: masonryIntegrity = sha384-GNFwBvfVxBkLMJpYMOABq3c+d3KnQxudP/mGPkzpZSTYykLBNsZEnG2D9G/X/+7D # cat=bootstrap-cdn/c-integrity/20; type=small; label=jQuery library: @@ -197,7 +200,7 @@ bootstrap.config.darkMode = 0 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 = +bootstrap.customScssPath = fileadmin/T3SB/Resources/Public/SCSS/ # disable default CSS - t3sbootstrap.css bootstrap.config.disableDefaultCss = 0 @@ -241,6 +244,9 @@ bootstrap.navbar { # extra style for navbar items bootstrap.config.navbarPlusicon = 0 +# 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 diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 9959c1a1..b51d65ee 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -42,6 +42,8 @@ module.tx_t3sbootstrap { masonry = {$bootstrap.cdn.masonry} jarallax = {$bootstrap.cdn.jarallax} swiper = {$bootstrap.cdn.swiper} + fontawesome5latest = {$bootstrap.cdn.fontawesome5latest} + fontawesome6latest = {$bootstrap.cdn.fontawesome6latest} } optimize { tables = {$bootstrap.optimize.tables} diff --git a/Contrib/scssphp/bin/pscss b/Contrib/scssphp/bin/pscss index 18c136ac..e6223983 100644 --- a/Contrib/scssphp/bin/pscss +++ b/Contrib/scssphp/bin/pscss @@ -26,7 +26,7 @@ use ScssPhp\ScssPhp\Parser; use ScssPhp\ScssPhp\Version; $style = null; -$loadPaths = null; +$loadPaths = []; $dumpTree = false; $inputFile = null; $changeDir = false; @@ -148,7 +148,7 @@ EOT; $value = parseArgument($i, array('-I', '--load-path')); if (isset($value)) { - $loadPaths = $value; + $loadPaths[] = $value; continue; } @@ -188,7 +188,7 @@ if ($dumpTree) { $scss = new Compiler(); if ($loadPaths) { - $scss->setImportPaths(explode(PATH_SEPARATOR, $loadPaths)); + $scss->setImportPaths($loadPaths); } if ($style) { diff --git a/Contrib/scssphp/composer.json b/Contrib/scssphp/composer.json index e4895871..86cd396b 100644 --- a/Contrib/scssphp/composer.json +++ b/Contrib/scssphp/composer.json @@ -40,6 +40,7 @@ "sass/sass-spec": "*", "squizlabs/php_codesniffer": "~3.5", "symfony/phpunit-bridge": "^5.1", + "thoughtbot/bourbon": "^7.0", "twbs/bootstrap": "~5.0", "twbs/bootstrap4": "4.6.0", "zurb/foundation": "~6.5" @@ -63,6 +64,24 @@ } } }, + { + "type": "package", + "package": { + "name": "thoughtbot/bourbon", + "version": "v7.0.0", + "source": { + "type": "git", + "url": "https://github.com/thoughtbot/bourbon.git", + "reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thoughtbot/bourbon/zipball/fbe338ee6807e7f7aa996d82c8a16f248bb149b3", + "reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3", + "shasum": "" + } + } + }, { "type": "package", "package": { diff --git a/Contrib/scssphp/src/Compiler.php b/Contrib/scssphp/src/Compiler.php index 76e17f1b..58ba795a 100644 --- a/Contrib/scssphp/src/Compiler.php +++ b/Contrib/scssphp/src/Compiler.php @@ -731,7 +731,7 @@ protected function compileRoot(Block $rootBlock) * * @return void */ - public function missingSelectors() + protected function missingSelectors() { foreach ($this->extends as $extend) { if (isset($extend[3])) { @@ -749,7 +749,7 @@ public function missingSelectors() $origin = $this->collapseSelectors($origin); $this->sourceLine = $block[Parser::SOURCE_LINE]; - throw $this->errorMsg("\"$origin\" failed to @extend \"$target\". The selector \"$target\" was not found."); + throw $this->error("\"$origin\" failed to @extend \"$target\". The selector \"$target\" was not found."); } } @@ -1970,7 +1970,7 @@ protected function evalSelectors($selectors) try { $isValid = $parser->parseSelector($buffer, $newSelectors, true); } catch (ParserException $e) { - throw $this->errorMsg($e->getMessage()); + throw $this->error($e->getMessage()); } if ($isValid) { @@ -2258,7 +2258,7 @@ protected function pushCallStack($name = '') $msg = $this->callStackMessage(true, 100); $msg = 'Infinite calling loop'; - throw $this->errorMsg($msg); + throw $this->error($msg); } } @@ -2328,7 +2328,7 @@ protected function compileChildrenNoReturn($stms, OutputBlock $out, $selfParent } if (isset($ret)) { - throw $this->errorMsg('@return may only be used within a function'); + throw $this->error('@return may only be used within a function'); } } @@ -3054,14 +3054,14 @@ protected function compileChild($child, OutputBlock $out) $replacedSel = $this->replaceSelfSelector($sel); if ($replacedSel !== $sel) { - throw $this->errorMsg('Parent selectors aren\'t allowed here.'); + throw $this->error('Parent selectors aren\'t allowed here.'); } $results = $this->evalSelectors([$sel]); foreach ($results as $result) { if (\count($result) !== 1) { - throw $this->errorMsg('complex selectors may not be extended.'); + throw $this->error('complex selectors may not be extended.'); } // only use the first one @@ -3214,7 +3214,7 @@ protected function compileChild($child, OutputBlock $out) $mixin = $this->get(static::$namespaces['mixin'] . $name, false); if (! $mixin) { - throw $this->errorMsg("Undefined mixin $name"); + throw $this->error("Undefined mixin $name"); } $callingScope = $this->getStoreEnv(); @@ -3271,7 +3271,7 @@ protected function compileChild($child, OutputBlock $out) if (! empty($mixin->parentEnv)) { $this->env->declarationScopeParent = $mixin->parentEnv; } else { - throw $this->errorMsg("@mixin $name() without parentEnv"); + throw $this->error("@mixin $name() without parentEnv"); } $this->compileChildrenNoReturn($mixin->children, $out, $selfParent, $this->env->marker . ' ' . $name); @@ -3338,10 +3338,10 @@ protected function compileChild($child, OutputBlock $out) $line = $this->sourceLine; $value = $this->compileValue($this->reduce($value, true)); - throw $this->errorMsg("File $fname on line $line ERROR: $value\n"); + throw $this->error("File $fname on line $line ERROR: $value\n"); default: - throw $this->errorMsg("unknown child type: $child[0]"); + throw $this->error("unknown child type: $child[0]"); } } @@ -3827,7 +3827,6 @@ protected function getFunctionReference($name, $safeCopy = false) // try to find a native lib function $normalizedName = $this->normalizeName($name); - $libName = null; if (isset($this->userFunctions[$normalizedName])) { // see if we can find a user function @@ -3836,10 +3835,45 @@ protected function getFunctionReference($name, $safeCopy = false) return [Type::T_FUNCTION_REFERENCE, 'user', $name, $f, $prototype]; } + $lowercasedName = strtolower($normalizedName); + + // Special functions overriding a CSS function are case-insensitive. We normalize them as lowercase + // to avoid the deprecation warning about the wrong case being used. + if ($lowercasedName === 'min' || $lowercasedName === 'max') { + $normalizedName = $lowercasedName; + } + if (($f = $this->getBuiltinFunction($normalizedName)) && \is_callable($f)) { $libName = $f[1]; $prototype = isset(static::$$libName) ? static::$$libName : null; + // All core functions have a prototype defined. Not finding the + // prototype can mean 2 things: + // - the function comes from a child class (deprecated just after) + // - the function was found with a different case, which relates to calling the + // wrong Sass function due to our camelCase usage (`fade-in()` vs `fadein()`), + // because PHP method names are case-insensitive while property names are + // case-sensitive. + if ($prototype === null || strtolower($normalizedName) !== $normalizedName) { + $r = new \ReflectionMethod($this, $libName); + $actualLibName = $r->name; + + if ($actualLibName !== $libName || strtolower($normalizedName) !== $normalizedName) { + $kebabCaseName = preg_replace('~(?<=\\w)([A-Z])~', '-$1', substr($actualLibName, 3)); + assert($kebabCaseName !== null); + $originalName = strtolower($kebabCaseName); + $warning = "Calling built-in functions with a non-standard name is deprecated since Scssphp 1.8.0 and will not work anymore in 2.0 (they will be treated as CSS function calls instead).\nUse \"$originalName\" instead of \"$name\"."; + @trigger_error($warning, E_USER_DEPRECATED); + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + Warn::deprecation("$warning\n on line $line of $fname"); + + // Use the actual function definition + $prototype = isset(static::$$actualLibName) ? static::$$actualLibName : null; + $f[1] = $libName = $actualLibName; + } + } + if (\get_class($this) !== __CLASS__ && !isset($this->warnedChildFunctions[$libName])) { $r = new \ReflectionMethod($this, $libName); $declaringClass = $r->getDeclaringClass()->name; @@ -4115,7 +4149,7 @@ protected function opColorColor($op, $left, $right) case '%': if ($rval == 0) { - throw $this->errorMsg("color: Can't take modulo by zero"); + throw $this->error("color: Can't take modulo by zero"); } $out[] = $lval % $rval; @@ -4123,7 +4157,7 @@ protected function opColorColor($op, $left, $right) case '/': if ($rval == 0) { - throw $this->errorMsg("color: Can't divide by zero"); + throw $this->error("color: Can't divide by zero"); } $out[] = (int) ($lval / $rval); @@ -4136,7 +4170,7 @@ protected function opColorColor($op, $left, $right) return $this->opNeq($left, $right); default: - throw $this->errorMsg("color: unknown op $op"); + throw $this->error("color: unknown op $op"); } } @@ -4670,7 +4704,7 @@ public function compileValue($value, $quote = true) return $this->compileCommentValue($value); default: - throw $this->errorMsg('unknown value type: ' . json_encode($value)); + throw $this->error('unknown value type: ' . json_encode($value)); } } @@ -5218,7 +5252,7 @@ public function get($name, $shouldThrow = true, Environment $env = null, $unredu } if ($shouldThrow) { - throw $this->errorMsg("Undefined variable \$$name" . ($maxDepth <= 0 ? ' (infinite recursion)' : '')); + throw $this->error("Undefined variable \$$name" . ($maxDepth <= 0 ? ' (infinite recursion)' : '')); } // found nothing @@ -5625,7 +5659,7 @@ protected function importFile($path, OutputBlock $out) $this->sourceLine = 1; $this->sourceColumn = 1; - throw $this->errorMsg('The Sass indented syntax is not implemented.'); + throw $this->error('The Sass indented syntax is not implemented.'); } if (isset($this->importCache[$realPath])) { @@ -5764,7 +5798,7 @@ public function findImport($url, $currentDir = null) } } - throw $this->errorMsg("`$url` file not found for @import"); + throw $this->error("`$url` file not found for @import"); } /** @@ -5813,7 +5847,7 @@ private function checkImportPathConflicts(array $paths) $formattedPrettyPaths[] = ' ' . $this->getPrettyPath($path); } - throw $this->errorMsg("It's not clear which file to import. Found:\n" . implode("\n", $formattedPrettyPaths)); + throw $this->error("It's not clear which file to import. Found:\n" . implode("\n", $formattedPrettyPaths)); } /** @@ -5973,7 +6007,7 @@ public function throwError($msg) E_USER_DEPRECATED ); - throw $this->errorMsg(...func_get_args()); + throw $this->error(...func_get_args()); } /** @@ -5985,7 +6019,7 @@ public function throwError($msg) * * @return CompilerException */ - public function errorMsg($msg, ...$args) + public function error($msg, ...$args) { if ($args) { $msg = sprintf($msg, ...$args); @@ -6038,7 +6072,7 @@ public function errorArgsNumber($functionName, $ExpectedArgs, $nbActual) $nbExpected = \count($ExpectedArgs); if ($nbActual > $nbExpected) { - return $this->errorMsg( + return $this->error( 'Error: Only %d arguments allowed in %s(), but %d were passed.', $nbExpected, $functionName, @@ -6051,7 +6085,7 @@ public function errorArgsNumber($functionName, $ExpectedArgs, $nbActual) array_unshift($missing, array_pop($ExpectedArgs)); } - return $this->errorMsg( + return $this->error( 'Error: %s() argument%s %s missing.', $functionName, count($missing) > 1 ? 's' : '', @@ -6115,7 +6149,7 @@ protected function handleImportLoop($name) } if (realpath($file) === $name) { - throw $this->errorMsg('An @import loop has been found: %s imports %s', $file, basename($file)); + throw $this->error('An @import loop has been found: %s imports %s', $file, basename($file)); } } } @@ -6152,7 +6186,7 @@ protected function callScssFunction($func, $argValues) if (! empty($func->parentEnv)) { $this->env->declarationScopeParent = $func->parentEnv; } else { - throw $this->errorMsg("@function $name() without parentEnv"); + throw $this->error("@function $name() without parentEnv"); } $ret = $this->compileChildren($func->children, $tmp, $this->env->marker . ' ' . $name); @@ -7152,7 +7186,7 @@ protected function compileColorPartValue($value, $min, $max, $isInt = true) } elseif ($value->hasUnit('%')) { $num = $max * $value->getDimension() / 100; } else { - throw $this->errorMsg('Expected %s to have no units or "%%".', $value); + throw $this->error('Expected %s to have no units or "%%".', $value); } $value = $num; @@ -7285,7 +7319,7 @@ public function assertMap($value, $varName = null) public function assertList($value) { if ($value[0] !== Type::T_LIST) { - throw $this->errorMsg('expecting list, %s received', $value[0]); + throw $this->error('expecting list, %s received', $value[0]); } return $value; @@ -7461,7 +7495,7 @@ public function toHSL($red, $green, $blue) } } - return [Type::T_HSL, fmod($h, 360), $s * 100, $l / 5.1]; + return [Type::T_HSL, fmod($h + 360, 360), $s * 100, $l / 5.1]; } /** @@ -7617,7 +7651,7 @@ protected function libCall($args) } if (! in_array($functionReference[0], [Type::T_FUNCTION_REFERENCE, Type::T_FUNCTION])) { - throw $this->errorMsg('Function reference expected, got ' . $functionReference[0]); + throw $this->error('Function reference expected, got ' . $functionReference[0]); } $callArgs = [ @@ -7813,7 +7847,7 @@ protected function alterColor(array $args, $operation, $fn) if (!$scale && $checkPercent) { if (!$number->hasUnit('%')) { - $warning = $this->errorMsg("{$name} Passing a number `$number` without unit % is deprecated."); + $warning = $this->error("{$name} Passing a number `$number` without unit % is deprecated."); $this->logger->warn($warning->getMessage(), true); } } @@ -7974,7 +8008,7 @@ protected function libIeHexStr($args) $color = $this->coerceColor($args[0]); if (\is_null($color)) { - throw $this->errorMsg('Error: argument `$color` of `ie-hex-str($color)` must be a color'); + throw $this->error('Error: argument `$color` of `ie-hex-str($color)` must be a color'); } $color[4] = isset($color[4]) ? round(255 * $color[4]) : 255; @@ -7988,7 +8022,7 @@ protected function libRed($args) $color = $this->coerceColor($args[0]); if (\is_null($color)) { - throw $this->errorMsg('Error: argument `$color` of `red($color)` must be a color'); + throw $this->error('Error: argument `$color` of `red($color)` must be a color'); } return new Number((int) $color[1], ''); @@ -8000,7 +8034,7 @@ protected function libGreen($args) $color = $this->coerceColor($args[0]); if (\is_null($color)) { - throw $this->errorMsg('Error: argument `$color` of `green($color)` must be a color'); + throw $this->error('Error: argument `$color` of `green($color)` must be a color'); } return new Number((int) $color[2], ''); @@ -8012,7 +8046,7 @@ protected function libBlue($args) $color = $this->coerceColor($args[0]); if (\is_null($color)) { - throw $this->errorMsg('Error: argument `$color` of `blue($color)` must be a color'); + throw $this->error('Error: argument `$color` of `blue($color)` must be a color'); } return new Number((int) $color[3], ''); @@ -8148,7 +8182,7 @@ protected function libHsl($args, $kwargs, $funcName = 'hsl') } } - $hueValue = $hue->getDimension() % 360; + $hueValue = fmod($hue->getDimension(), 360); while ($hueValue < 0) { $hueValue += 360; @@ -8212,20 +8246,20 @@ protected function libHwb($args, $kwargs, $funcName = 'hwb') if (\count($args) == 1) { if ($args[0][0] !== Type::T_LIST) { - throw $this->errorMsg("Missing elements \$whiteness and \$blackness"); + throw $this->error("Missing elements \$whiteness and \$blackness"); } if (\trim($args[0][1])) { - throw $this->errorMsg("\$channels must be a space-separated list."); + throw $this->error("\$channels must be a space-separated list."); } if (! empty($args[0]['enclosing'])) { - throw $this->errorMsg("\$channels must be an unbracketed list."); + throw $this->error("\$channels must be an unbracketed list."); } $args = $args[0][2]; if (\count($args) > 3) { - throw $this->errorMsg("hwb() : Only 3 elements are allowed but ". \count($args) . "were passed"); + throw $this->error("hwb() : Only 3 elements are allowed but ". \count($args) . "were passed"); } $args_to_check = $this->extractSlashAlphaInColorFunction($kwargs['channels'][2]); @@ -8235,13 +8269,13 @@ protected function libHwb($args, $kwargs, $funcName = 'hwb') } if (\count($args_to_check) < 2) { - throw $this->errorMsg("Missing elements \$whiteness and \$blackness"); + throw $this->error("Missing elements \$whiteness and \$blackness"); } if (\count($args_to_check) < 3) { - throw $this->errorMsg("Missing element \$blackness"); + throw $this->error("Missing element \$blackness"); } if (\count($args_to_check) > 4) { - throw $this->errorMsg("hwb() : Only 4 elements are allowed but ". \count($args) . "were passed"); + throw $this->error("hwb() : Only 4 elements are allowed but ". \count($args) . "were passed"); } foreach ($kwargs as $k => $arg) { @@ -8278,7 +8312,7 @@ protected function libHwb($args, $kwargs, $funcName = 'hwb') if (! \is_numeric($alpha)) { $val = $this->compileValue($args[3]); - throw $this->errorMsg("\$alpha: $val is not a number"); + throw $this->error("\$alpha: $val is not a number"); } } @@ -8572,7 +8606,7 @@ protected function libMin($args) return $min; } - throw $this->errorMsg('At least one argument must be passed.'); + throw $this->error('At least one argument must be passed.'); } protected static $libMax = ['numbers...']; @@ -8595,7 +8629,7 @@ protected function libMax($args) return $max; } - throw $this->errorMsg('At least one argument must be passed.'); + throw $this->error('At least one argument must be passed.'); } protected static $libLength = ['list']; @@ -8654,7 +8688,7 @@ protected function libSetNth($args) } if (! isset($list[2][$n])) { - throw $this->errorMsg('Invalid argument for "n"'); + throw $this->error('Invalid argument for "n"'); } $list[2][$n] = $args[2]; @@ -9009,7 +9043,7 @@ protected function libComparable($args) ! $number1 instanceof Number || ! $number2 instanceof Number ) { - throw $this->errorMsg('Invalid argument(s) for "comparable"'); + throw $this->error('Invalid argument(s) for "comparable"'); } return $this->toBool($number1->isComparableTo($number2)); @@ -9426,11 +9460,11 @@ protected function isSuperSelector($super, $sub) { // one and only one selector for each arg if (! $super) { - throw $this->errorMsg('Invalid super selector for isSuperSelector()'); + throw $this->error('Invalid super selector for isSuperSelector()'); } if (! $sub) { - throw $this->errorMsg('Invalid sub selector for isSuperSelector()'); + throw $this->error('Invalid sub selector for isSuperSelector()'); } if (count($sub) > 1) { @@ -9530,7 +9564,7 @@ protected function libSelectorAppend($args) $args = $args[2]; if (\count($args) < 1) { - throw $this->errorMsg('selector-append() needs at least 1 argument'); + throw $this->error('selector-append() needs at least 1 argument'); } $selectors = []; @@ -9555,14 +9589,14 @@ protected function selectorAppend($selectors) $lastSelectors = array_pop($selectors); if (! $lastSelectors) { - throw $this->errorMsg('Invalid selector list in selector-append()'); + throw $this->error('Invalid selector list in selector-append()'); } while (\count($selectors)) { $previousSelectors = array_pop($selectors); if (! $previousSelectors) { - throw $this->errorMsg('Invalid selector list in selector-append()'); + throw $this->error('Invalid selector list in selector-append()'); } // do the trick, happening $lastSelector to $previousSelector @@ -9605,7 +9639,7 @@ protected function libSelectorExtend($args) $extender = $this->getSelectorArg($extender, 'extender'); if (! $selectors || ! $extendee || ! $extender) { - throw $this->errorMsg('selector-extend() invalid arguments'); + throw $this->error('selector-extend() invalid arguments'); } $extended = $this->extendOrReplaceSelectors($selectors, $extendee, $extender); @@ -9626,7 +9660,7 @@ protected function libSelectorReplace($args) $replacement = $this->getSelectorArg($replacement, 'replacement'); if (! $selectors || ! $original || ! $replacement) { - throw $this->errorMsg('selector-replace() invalid arguments'); + throw $this->error('selector-replace() invalid arguments'); } $replaced = $this->extendOrReplaceSelectors($selectors, $original, $replacement, true); @@ -9655,7 +9689,7 @@ protected function extendOrReplaceSelectors($selectors, $extendee, $extender, $r foreach ($extendee as $es) { if (\count($es) !== 1) { - throw $this->errorMsg('Can\'t extend complex selector.'); + throw $this->error('Can\'t extend complex selector.'); } // only use the first one @@ -9693,7 +9727,7 @@ protected function libSelectorNest($args) $args = $args[2]; if (\count($args) < 1) { - throw $this->errorMsg('selector-nest() needs at least 1 argument'); + throw $this->error('selector-nest() needs at least 1 argument'); } $selectorsMap = []; @@ -9738,7 +9772,7 @@ protected function libSelectorUnify($args) $selectors2 = $this->getSelectorArg($selectors2, 'selectors2'); if (! $selectors1 || ! $selectors2) { - throw $this->errorMsg('selector-unify() invalid arguments'); + throw $this->error('selector-unify() invalid arguments'); } // only consider the first compound of each diff --git a/Contrib/scssphp/src/Node/Number.php b/Contrib/scssphp/src/Node/Number.php index 78f86bac..b326906b 100644 --- a/Contrib/scssphp/src/Node/Number.php +++ b/Contrib/scssphp/src/Node/Number.php @@ -149,6 +149,7 @@ public function getDenominatorUnits() /** * {@inheritdoc} */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { if ($offset === -3) { @@ -174,6 +175,7 @@ public function offsetExists($offset) /** * {@inheritdoc} */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { switch ($offset) { @@ -200,6 +202,7 @@ public function offsetGet($offset) /** * {@inheritdoc} */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { throw new \BadMethodCallException('Number is immutable'); @@ -208,6 +211,7 @@ public function offsetSet($offset, $value) /** * {@inheritdoc} */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { throw new \BadMethodCallException('Number is immutable'); diff --git a/Contrib/scssphp/src/Parser.php b/Contrib/scssphp/src/Parser.php index 3a3ae628..3ba2f67f 100644 --- a/Contrib/scssphp/src/Parser.php +++ b/Contrib/scssphp/src/Parser.php @@ -15,7 +15,6 @@ use ScssPhp\ScssPhp\Exception\ParserException; use ScssPhp\ScssPhp\Logger\LoggerInterface; use ScssPhp\ScssPhp\Logger\QuietLogger; -use ScssPhp\ScssPhp\Node\Number; /** * Parser @@ -2957,7 +2956,7 @@ protected function unit(&$unit) if (\strlen($this->buffer) === $this->count || ! ctype_digit($this->buffer[$this->count])) { $this->whitespace(); - $unit = new Number($m[1], empty($m[3]) ? '' : $m[3]); + $unit = new Node\Number($m[1], empty($m[3]) ? '' : $m[3]); return true; } diff --git a/Contrib/scssphp/src/Version.php b/Contrib/scssphp/src/Version.php index 4cc0bb68..62c8006a 100644 --- a/Contrib/scssphp/src/Version.php +++ b/Contrib/scssphp/src/Version.php @@ -19,5 +19,5 @@ */ class Version { - const VERSION = '1.7.0'; + const VERSION = '1.8.1'; } 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 309486e2..a471df75 100644 --- a/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/Detail.html +++ b/Resources/Private/Extensions/news/Resources/Private/Partials/Detail/Detail.html @@ -2,6 +2,7 @@ xmlns:n="http://typo3.org/ns/GeorgRinger/News/ViewHelpers" xmlns:rx="http://typo3.org/ns/Reelworx/RxShariff/ViewHelper" data-namespace-typo3-fluid="true"> + @@ -144,7 +145,6 @@

{newsItem.title}

diff --git a/Resources/Private/Extensions/news/Resources/Private/Partials/List/Body/Item.html b/Resources/Private/Extensions/news/Resources/Private/Partials/List/Body/Item.html index 205bd91d..cb682aa2 100644 --- a/Resources/Private/Extensions/news/Resources/Private/Partials/List/Body/Item.html +++ b/Resources/Private/Extensions/news/Resources/Private/Partials/List/Body/Item.html @@ -1,4 +1,5 @@ - +

diff --git a/Resources/Private/Extensions/news/Resources/Private/Templates/News/Detail.html b/Resources/Private/Extensions/news/Resources/Private/Templates/News/Detail.html index d2939986..c6f0a7fd 100644 --- a/Resources/Private/Extensions/news/Resources/Private/Templates/News/Detail.html +++ b/Resources/Private/Extensions/news/Resources/Private/Templates/News/Detail.html @@ -150,7 +150,6 @@

{newsItem.title}

{newsItem.datetime} - diff --git a/Resources/Private/Partials/Content/Swiper/Default.html b/Resources/Private/Partials/Content/Swiper/Default.html index 1df72f8d..79ee3164 100644 --- a/Resources/Private/Partials/Content/Swiper/Default.html +++ b/Resources/Private/Partials/Content/Swiper/Default.html @@ -25,6 +25,7 @@ -ms-flex-align: stretch; -webkit-align-items: stretch; align-items: stretch; + height: auto !important; } #swiper-{data.uid} .swiper-slide img { display: block; @@ -39,7 +40,7 @@ } -#swiper-{data.uid}{width:100%;height:auto}#swiper-{data.uid} .swiper-wrapper{height:auto}#swiper-{data.uid} .swiper-slide{flex-direction:column;display:-webkit-box;display:-ms-flexbox;display:-webkit-flex;display:flex;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:start;justify-content:start;-webkit-box-align:stretch;-ms-flex-align:stretch;-webkit-align-items:stretch;align-items:stretch}#swiper-{data.uid} .swiper-slide img{display:block;width:100%;height:100%;object-fit:cover}#swiper-{data.uid} .swiper-button-next,#swiper-{data.uid} .swiper-button-prev{color:#fff;text-shadow:1px 1px 2px #000,0 0 25px #000,0 0 5px #000} +#swiper-{data.uid}{width:100%;height:auto}#swiper-{data.uid} .swiper-wrapper{height:auto}#swiper-{data.uid} .swiper-slide{flex-direction:column;display:-webkit-box;display:-ms-flexbox;display:-webkit-flex;display:flex;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:start;justify-content:start;-webkit-box-align:stretch;-ms-flex-align:stretch;-webkit-align-items:stretch;align-items:stretch;height:auto !important}#swiper-{data.uid} .swiper-slide img{display:block;width:100%;height:100%;object-fit:cover}#swiper-{data.uid} .swiper-button-next,#swiper-{data.uid} .swiper-button-prev{color:#fff;text-shadow:1px 1px 2px #000,0 0 25px #000,0 0 5px #000} // Swiper Slider - Partials/Content/Swiper/Default.html diff --git a/Resources/Private/Partials/Page/Sub.html b/Resources/Private/Partials/Page/Sub.html index 6a91b965..93229829 100644 --- a/Resources/Private/Partials/Page/Sub.html +++ b/Resources/Private/Partials/Page/Sub.html @@ -28,6 +28,11 @@ smp.style.top = '15px'; } }); + + + + + var navItems = document.querySelectorAll('.submenu .nav-item'); navItems.forEach( navItem => { navItem.addEventListener('click', (item) => { @@ -41,8 +46,67 @@ }); }); + + + + + +
+ + + + + + + + + -
- - + @@ -141,11 +203,19 @@ + + + + + + + +