diff --git a/Classes/CodeGenerator/TyposcriptCodeGenerator.php b/Classes/CodeGenerator/TyposcriptCodeGenerator.php
index 9053bba4..c6f09808 100644
--- a/Classes/CodeGenerator/TyposcriptCodeGenerator.php
+++ b/Classes/CodeGenerator/TyposcriptCodeGenerator.php
@@ -214,21 +214,24 @@ public function generateSetupTyposcript(): string
// for base paths to fluid templates configured in extension settings
$paths = [];
if ($this->maskExtensionConfiguration['content'] ?? false) {
- $paths['templateRootPaths'] = [
- 10 => $this->maskExtensionConfiguration['content'],
- ];
+ $paths['templateRootPaths'] = $this->getTyposcriptPathArray(
+ $this->maskExtensionConfiguration['content'],
+ 10
+ );
}
if ($this->maskExtensionConfiguration['partials'] ?? false) {
- $paths['partialRootPaths'] = [
- 10 => $this->maskExtensionConfiguration['partials'],
- ];
+ $paths['partialRootPaths'] = $this->getTyposcriptPathArray(
+ $this->maskExtensionConfiguration['partials'],
+ 10
+ );
}
if ($this->maskExtensionConfiguration['layouts'] ?? false) {
- $paths['layoutRootPaths'] = [
- 10 => $this->maskExtensionConfiguration['layouts'],
- ];
+ $paths['layoutRootPaths'] = $this->getTyposcriptPathArray(
+ $this->maskExtensionConfiguration['layouts'],
+ 10
+ );
}
$setupContent[] = ArrayToTypoScriptConverter::convert($paths, 'lib.maskContentElement');
@@ -250,4 +253,19 @@ public function generateSetupTyposcript(): string
return implode("\n\n", $setupContent) . "\n\n";
}
+
+ /**
+ * @return string[]
+ */
+ protected function getTyposcriptPathArray(string $commaSeparatedPaths, int $startKey): array
+ {
+ $paths = TemplatePathUtility::getPaths($commaSeparatedPaths);
+ if (count($paths) === 0) {
+ return [];
+ }
+ return array_combine(
+ range($startKey, $startKey + count($paths) - 1),
+ $paths
+ );
+ }
}
diff --git a/Classes/Controller/AjaxController.php b/Classes/Controller/AjaxController.php
index 7d1ed51e..545031dc 100644
--- a/Classes/Controller/AjaxController.php
+++ b/Classes/Controller/AjaxController.php
@@ -1128,12 +1128,21 @@ protected function getMissingFolders(): array
if (!isset($this->maskExtensionConfiguration[$key])) {
continue;
}
- $path = GeneralUtility::getFileAbsFileName($this->maskExtensionConfiguration[$key]);
- if ($path === '') {
+ $origPaths = TemplatePathUtility::getPaths($this->maskExtensionConfiguration[$key]);
+ if (count($origPaths) === 0) {
continue;
}
- if (!file_exists($path)) {
- $missingFolders[$key] = $this->maskExtensionConfiguration[$key];
+ foreach ($origPaths as $origPath) {
+ $path = GeneralUtility::getFileAbsFileName($origPath);
+ if (!file_exists($path)) {
+ $suffix = '';
+ $num = 1;
+ while (isset($missingFolders[$key . $suffix])) {
+ $num++;
+ $suffix = ' #' . $num;
+ }
+ $missingFolders[$key . $suffix] = $origPath;
+ }
}
}
diff --git a/Classes/EventListeners/MaskBackendPreviewEventListener.php b/Classes/EventListeners/MaskBackendPreviewEventListener.php
index 76c72924..c5077751 100644
--- a/Classes/EventListeners/MaskBackendPreviewEventListener.php
+++ b/Classes/EventListeners/MaskBackendPreviewEventListener.php
@@ -93,12 +93,12 @@ public function __invoke(PageContentPreviewRenderingEvent $event): void
$view = GeneralUtility::makeInstance(StandaloneView::class, $renderingContext);
$view->setTemplatePathAndFilename($templatePathAndFilename);
if (!empty($this->maskExtensionConfiguration['layouts_backend'])) {
- $layoutRootPath = GeneralUtility::getFileAbsFileName($this->maskExtensionConfiguration['layouts_backend']);
- $view->setLayoutRootPaths([$layoutRootPath]);
+ $layoutRootPaths = TemplatePathUtility::getAbsolutePaths($this->maskExtensionConfiguration['layouts_backend']);
+ $view->setLayoutRootPaths($layoutRootPaths);
}
if (!empty($this->maskExtensionConfiguration['partials_backend'])) {
- $partialRootPath = GeneralUtility::getFileAbsFileName($this->maskExtensionConfiguration['partials_backend']);
- $view->setPartialRootPaths([$partialRootPath]);
+ $partialRootPaths = TemplatePathUtility::getAbsolutePaths($this->maskExtensionConfiguration['partials_backend']);
+ $view->setPartialRootPaths($partialRootPaths);
}
// Fetch and assign some useful variables
diff --git a/Classes/Imaging/PreviewIconResolver.php b/Classes/Imaging/PreviewIconResolver.php
index cf8e5d46..bf5ed352 100644
--- a/Classes/Imaging/PreviewIconResolver.php
+++ b/Classes/Imaging/PreviewIconResolver.php
@@ -17,6 +17,7 @@
namespace MASK\Mask\Imaging;
+use MASK\Mask\Utility\TemplatePathUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
@@ -43,20 +44,23 @@ public function isPreviewIconAvailable(string $key): bool
public function getPreviewIconPath(string $key): string
{
- if (!($this->maskExtensionConfiguration['preview'] ?? false)) {
+ $previewPaths = TemplatePathUtility::getPaths($this->maskExtensionConfiguration['preview']);
+ if (!count($previewPaths)) {
return '';
}
// search a fitting png or svg file in this path
$fileExtensions = ['png', 'svg'];
- $previewPath = rtrim($this->maskExtensionConfiguration['preview'], '/');
- foreach ($fileExtensions as $fileExtension) {
- $extPathToIcon = $previewPath . '/' . $key . '.' . $fileExtension;
- $absolutePathToIcon = GeneralUtility::getFileAbsFileName($extPathToIcon);
- if ($absolutePathToIcon === '' || !file_exists($absolutePathToIcon)) {
- continue;
+ foreach ($previewPaths as $previewPath) {
+ $previewPath = rtrim($previewPath, '/');
+ foreach ($fileExtensions as $fileExtension) {
+ $extPathToIcon = $previewPath . '/' . $key . '.' . $fileExtension;
+ $absolutePathToIcon = GeneralUtility::getFileAbsFileName($extPathToIcon);
+ if ($absolutePathToIcon === '' || !file_exists($absolutePathToIcon)) {
+ continue;
+ }
+ $resource = PathUtility::getPublicResourceWebPath($extPathToIcon);
+ return '/' . ltrim($resource, '/');
}
- $resource = PathUtility::getPublicResourceWebPath($extPathToIcon);
- return '/' . ltrim($resource, '/');
}
return '';
diff --git a/Classes/Utility/TemplatePathUtility.php b/Classes/Utility/TemplatePathUtility.php
index 9971910c..748e94cf 100644
--- a/Classes/Utility/TemplatePathUtility.php
+++ b/Classes/Utility/TemplatePathUtility.php
@@ -33,33 +33,50 @@ public static function getTemplatePath(
array $settings,
string $elementKey,
bool $onlyTemplateName = false,
- ?string $path = null,
+ ?string $commaSeparatedPaths = null,
bool $removeExtension = false
): string {
- if ($path === null) {
- $path = GeneralUtility::getFileAbsFileName(rtrim($settings['content'] ?? '', '/') . '/');
+ if ($commaSeparatedPaths === null) {
+ $paths = static::getAbsolutePaths($settings['content']);
+ } else {
+ $paths = static::getAbsolutePaths($commaSeparatedPaths);
}
- if ($path === '' || $elementKey === '') {
+ if (count($paths) === 0 || $elementKey === '') {
return '';
}
- $path = rtrim($path, '/') . '/';
- $fileExtension = '.html';
- // check if a html file with underscores exist
- if (file_exists($path . GeneralUtility::underscoredToUpperCamelCase($elementKey) . $fileExtension)) {
- $fileName = GeneralUtility::underscoredToUpperCamelCase($elementKey);
- } elseif (file_exists($path . ucfirst($elementKey) . $fileExtension)) {
- $fileName = ucfirst($elementKey);
- } elseif (file_exists($path . $elementKey . $fileExtension)) {
- $fileName = $elementKey;
- } else {
- $fileName = GeneralUtility::underscoredToUpperCamelCase($elementKey);
- }
+ foreach ($paths as $path) {
+ $path = rtrim($path, '/') . '/';
+ $fileExtension = '.html';
+
+ // check if a html file with underscores exist
+ $exists = false;
+ if (file_exists($path . GeneralUtility::underscoredToUpperCamelCase($elementKey) . $fileExtension)) {
+ $fileName = GeneralUtility::underscoredToUpperCamelCase($elementKey);
+ $exists = true;
+ } elseif (file_exists($path . ucfirst($elementKey) . $fileExtension)) {
+ $fileName = ucfirst($elementKey);
+ $exists = true;
+ } elseif (file_exists($path . $elementKey . $fileExtension)) {
+ $fileName = $elementKey;
+ $exists = true;
+ } else {
+ $fileName = GeneralUtility::underscoredToUpperCamelCase($elementKey);
+ }
- if ($removeExtension) {
- $fileExtension = '';
+ if ($removeExtension) {
+ $fileExtension = '';
+ }
+
+ if ($exists) {
+ if ($onlyTemplateName) {
+ return $fileName . $fileExtension;
+ }
+ return $path . $fileName . $fileExtension;
+ }
}
+ //non-existing template file
if ($onlyTemplateName) {
return $fileName . $fileExtension;
}
@@ -80,4 +97,16 @@ public static function getAbsolutePaths(string $commaSeparatedPaths): array
}
return array_filter($paths);
}
+
+ /**
+ * Split a string of comma-separated paths into an array.
+ * Remove empty values.
+ *
+ * @return string[]
+ */
+ public static function getPaths(string $commaSeparatedPaths): array
+ {
+ $paths = GeneralUtility::trimExplode(',', $commaSeparatedPaths);
+ return array_filter($paths);
+ }
}
diff --git a/Resources/Private/Language/locallang_mask.xlf b/Resources/Private/Language/locallang_mask.xlf
index 3eaa3c76..6b8bfd7f 100644
--- a/Resources/Private/Language/locallang_mask.xlf
+++ b/Resources/Private/Language/locallang_mask.xlf
@@ -31,25 +31,25 @@
Override shared fields per content element.:Careful! As soon as this option is enabled and you save content elements, the fields are not synced anymore and this action can not be undone! Please back up your Mask element definitions before.
- Folder for Content Fluid Templates
+ Folder for Content Fluid Templates: Multiple folders comma-separated
- Folder for Backend Preview Templates
+ Folder for Backend Preview Templates: Multiple folders comma-separated
- Folder for 32x32px png/svg content element preview icons (e.g. mykey.(png|svg))
+ Folder for content element preview icons: 32x32px png/svg files, e.g. mykey.(png|svg). Multiple folders comma-separated
- Folder for Content Fluid Layouts
+ Folder for Content Fluid Layouts: Multiple folders comma-separated
- Folder for Content Fluid Partials
+ Folder for Content Fluid Partials: Multiple folders comma-separated
- Folder for Backend Preview Layouts
+ Folder for Backend Preview Layouts: Multiple folders comma-separated
- Folder for Backend Preview Partials
+ Folder for Backend Preview Partials: Multiple folders comma-separated
PageIds from where the in PageTS defined backend layouts should be loaded (comma separated)
diff --git a/Tests/Unit/CodeGenerator/TypoScriptCodeGeneratorTest.php b/Tests/Unit/CodeGenerator/TypoScriptCodeGeneratorTest.php
index d89fb41a..7cac7278 100644
--- a/Tests/Unit/CodeGenerator/TypoScriptCodeGeneratorTest.php
+++ b/Tests/Unit/CodeGenerator/TypoScriptCodeGeneratorTest.php
@@ -74,6 +74,51 @@ public static function generateSetupTyposcriptDataProvider(): iterable
templateName = Element1
}
+',
+ ];
+
+ yield 'comma-separated paths' => [
+ 'json' => [
+ 'tt_content' => [
+ 'elements' => [
+ 'element1' => [
+ 'label' => 'Element 1',
+ 'key' => 'element1',
+ ],
+ 'element2' => [
+ 'label' => 'Element 2',
+ 'key' => 'element2',
+ 'hidden' => true,
+ ],
+ ],
+ ],
+ ],
+ 'configuration' => [
+ 'content' => 'EXT:sitepackage/Resources/Private/Mask/Templates,EXT:sitepackage/Resources/Private/Mask/Templates2',
+ 'layouts' => 'EXT:sitepackage/Resources/Private/Mask/Layouts,EXT:sitepackage/Resources/Private/Mask/Layouts2',
+ 'partials' => 'EXT:sitepackage/Resources/Private/Mask/Partials,EXT:sitepackage/Resources/Private/Mask/Partials2',
+ ],
+ 'expected' =>
+'lib.maskContentElement {
+ templateRootPaths {
+ 10 = EXT:sitepackage/Resources/Private/Mask/Templates
+ 11 = EXT:sitepackage/Resources/Private/Mask/Templates2
+ }
+ partialRootPaths {
+ 10 = EXT:sitepackage/Resources/Private/Mask/Partials
+ 11 = EXT:sitepackage/Resources/Private/Mask/Partials2
+ }
+ layoutRootPaths {
+ 10 = EXT:sitepackage/Resources/Private/Mask/Layouts
+ 11 = EXT:sitepackage/Resources/Private/Mask/Layouts2
+ }
+}
+
+tt_content.mask_element1 =< lib.maskContentElement
+tt_content.mask_element1 {
+ templateName = Element1
+}
+
',
];
diff --git a/Tests/Unit/Fixtures/Templates2/UpperExists2.html b/Tests/Unit/Fixtures/Templates2/UpperExists2.html
new file mode 100644
index 00000000..e69de29b
diff --git a/Tests/Unit/Utility/TemplatePathUtilityTest.php b/Tests/Unit/Utility/TemplatePathUtilityTest.php
index 13f398cb..728126b9 100644
--- a/Tests/Unit/Utility/TemplatePathUtilityTest.php
+++ b/Tests/Unit/Utility/TemplatePathUtilityTest.php
@@ -36,6 +36,14 @@ public static function getTemplatePathDataProvider(): iterable
false,
Environment::getProjectPath() . '/Tests/Unit/Fixtures/Templates/UpperExists.html',
],
+ 'Comma-separated content path' => [
+ ['content' => 'EXT:mask/Tests/Unit/Fixtures/Templates/,EXT:mask/Tests/Unit/Fixtures/Templates2/'],
+ 'upper_exists2',
+ false,
+ null,
+ false,
+ Environment::getProjectPath() . '/Tests/Unit/Fixtures/Templates2/UpperExists2.html',
+ ],
'File does not exist' => [
['content' => 'EXT:mask/Tests/Unit/Fixtures/Templates/'],
'noelement',
@@ -66,7 +74,7 @@ public static function getTemplatePathDataProvider(): iterable
false,
'typo3conf/ext/mask/Tests/Unit/Fixtures/Templates/',
false,
- 'typo3conf/ext/mask/Tests/Unit/Fixtures/Templates/UpperExists.html',
+ Environment::getProjectPath() . '/.Build/Web/typo3conf/ext/mask/Tests/Unit/Fixtures/Templates/UpperExists.html',
],
'Manually configured absolute path works' => [
['content' => ''],
@@ -76,6 +84,14 @@ public static function getTemplatePathDataProvider(): iterable
false,
Environment::getProjectPath() . '/Tests/Unit/Fixtures/Templates/UpperExists.html',
],
+ 'Manually configured comma-separated path works' => [
+ ['content' => ''],
+ 'upper_exists2',
+ false,
+ 'typo3conf/ext/mask/Tests/Unit/Fixtures/Templates/,EXT:mask/Tests/Unit/Fixtures/Templates2/',
+ false,
+ Environment::getProjectPath() . '/Tests/Unit/Fixtures/Templates2/UpperExists2.html',
+ ],
'Only template is returned' => [
['content' => 'EXT:mask/Tests/Unit/Fixtures/Templates/'],
'upper_exists',