diff --git a/src/bundle/DependencyInjection/Configuration/Parser/ContentType.php b/src/bundle/DependencyInjection/Configuration/Parser/ContentType.php new file mode 100644 index 0000000000..3881ca1a95 --- /dev/null +++ b/src/bundle/DependencyInjection/Configuration/Parser/ContentType.php @@ -0,0 +1,62 @@ + $config) { + $contextualizer->setContextualParameter("content_type.$identifier", $currentScope, $config); + } + } + + /** + * {@inheritdoc} + */ + public function addSemanticConfig(NodeBuilder $nodeBuilder) + { + $nodeBuilder + ->arrayNode('content_type') + ->useAttributeAsKey('identifier') + ->arrayPrototype() + ->children() + ->scalarNode('thumbnail')->defaultNull()->end() + ->end() + ->end() + ->end(); + } +} diff --git a/src/bundle/EzPlatformAdminUiBundle.php b/src/bundle/EzPlatformAdminUiBundle.php index 443a4a73e6..b042c40fc7 100644 --- a/src/bundle/EzPlatformAdminUiBundle.php +++ b/src/bundle/EzPlatformAdminUiBundle.php @@ -16,6 +16,7 @@ use EzSystems\EzPlatformAdminUiBundle\DependencyInjection\Compiler\ViewBuilderRegistryPass; use EzSystems\EzPlatformAdminUiBundle\DependencyInjection\Configuration\Parser\AdminUiForms; use EzSystems\EzPlatformAdminUiBundle\DependencyInjection\Configuration\Parser\ContentTranslateView; +use EzSystems\EzPlatformAdminUiBundle\DependencyInjection\Configuration\Parser\ContentType; use EzSystems\EzPlatformAdminUiBundle\DependencyInjection\Configuration\Parser\LocationIds; use EzSystems\EzPlatformAdminUiBundle\DependencyInjection\Configuration\Parser\Module; use EzSystems\EzPlatformAdminUiBundle\DependencyInjection\Configuration\Parser\Notifications; @@ -83,6 +84,7 @@ private function getConfigParsers(): array new Notifications(), new ContentTranslateView(), new AdminUiForms(), + new ContentType(), ]; } } diff --git a/src/bundle/Resources/config/default_parameters.yml b/src/bundle/Resources/config/default_parameters.yml index 23f855c766..aedea5e7c3 100644 --- a/src/bundle/Resources/config/default_parameters.yml +++ b/src/bundle/Resources/config/default_parameters.yml @@ -26,6 +26,41 @@ parameters: match: SystemInfo\Identifier: 'symfony_kernel' + ezsettings.default.content_type.about: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#about' + ezsettings.default.content_type.article: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#article' + ezsettings.default.content_type.blog: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#blog' + ezsettings.default.content_type.blog_post: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#blog_post' + ezsettings.default.content_type.folder: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#folder' + ezsettings.default.content_type.form: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#form' + ezsettings.default.content_type.place: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#place' + ezsettings.default.content_type.product: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#product' + ezsettings.default.content_type.field: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#field' + ezsettings.default.content_type.user: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#user' + ezsettings.default.content_type.user_group: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#user_group' + ezsettings.default.content_type.file: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#file' + ezsettings.default.content_type.gallery: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#gallery' + ezsettings.default.content_type.image: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#image' + ezsettings.default.content_type.video: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#video' + ezsettings.default.content_type.landing_page: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#landing_page' + ezsettings.default.content_type.default-config: + thumbnail: '/bundles/ezplatformadminui/img/ez-icons.svg#file' + ezplatform.content_view.tabs.default_template: '@@ezdesign/parts/tab/default.html.twig' ezplatform.multifile_upload.location.mappings: [] diff --git a/src/bundle/Resources/config/services.yml b/src/bundle/Resources/config/services.yml index a6a552b55a..ef3e6096b8 100644 --- a/src/bundle/Resources/config/services.yml +++ b/src/bundle/Resources/config/services.yml @@ -126,3 +126,5 @@ services: - {name: kernel.event_subscriber, priority: -250} EzSystems\EzPlatformAdminUiBundle\Templating\Twig\UserPreferencesGlobalExtension: ~ + + EzSystems\EzPlatformAdminUi\UI\Service\ContentTypeIconResolver: ~ diff --git a/src/bundle/Resources/config/services/ui_config/common.yml b/src/bundle/Resources/config/services/ui_config/common.yml index e79eebfc6f..20eabeca1f 100644 --- a/src/bundle/Resources/config/services/ui_config/common.yml +++ b/src/bundle/Resources/config/services/ui_config/common.yml @@ -97,3 +97,5 @@ services: - { name: ezplatform.admin_ui.config_provider, key: 'dateFormat' } EzSystems\EzPlatformAdminUiBundle\Templating\Twig\PathStringExtension: ~ + + EzSystems\EzPlatformAdminUiBundle\Templating\Twig\ContentTypeIconExtension: ~ diff --git a/src/bundle/Resources/public/js/scripts/helpers/content.type.helper.js b/src/bundle/Resources/public/js/scripts/helpers/content.type.helper.js new file mode 100644 index 0000000000..564328d4a9 --- /dev/null +++ b/src/bundle/Resources/public/js/scripts/helpers/content.type.helper.js @@ -0,0 +1,43 @@ +(function(global, doc, eZ) { + let contentTypesDataMap = null; + + /** + * Creates map with content types identifiers as keys for faster lookup + * + * @function createContentTypeDataMap + * @returns {Object} contentTypesDataMap + */ + const createContentTypeDataMap = () => + Object.values(eZ.adminUiConfig.contentTypes).reduce((contentTypeDataMap, contentTypeGroup) => { + for (const contentTypeData of contentTypeGroup) { + contentTypeDataMap[contentTypeData.identifier] = contentTypeData; + } + + return contentTypeDataMap; + }, {}); + + /** + * Returns an URL to a content type icon + * + * @function getContentTypeIcon + * @param {String} contentTypeIdentifier + * @returns {String|null} url to icon + */ + const getContentTypeIconUrl = (contentTypeIdentifier) => { + if (!contentTypesDataMap) { + contentTypesDataMap = createContentTypeDataMap(); + } + + if (!contentTypeIdentifier || !contentTypesDataMap[contentTypeIdentifier]) { + return null; + } + + const iconUrl = contentTypesDataMap[contentTypeIdentifier].thumbnail; + + return iconUrl; + }; + + eZ.addConfig('helpers.contentType', { + getContentTypeIconUrl, + }); +})(window, document, window.eZ); diff --git a/src/bundle/Resources/views/layout.html.twig b/src/bundle/Resources/views/layout.html.twig index a18a8758d0..1026305467 100644 --- a/src/bundle/Resources/views/layout.html.twig +++ b/src/bundle/Resources/views/layout.html.twig @@ -162,6 +162,7 @@ '@EzPlatformAdminUiBundle/Resources/public/js/scripts/helpers/request.helper.js' '@EzPlatformAdminUiBundle/Resources/public/js/scripts/helpers/notification.helper.js' '@EzPlatformAdminUiBundle/Resources/public/js/scripts/helpers/timezone.helper.js' + '@EzPlatformAdminUiBundle/Resources/public/js/scripts/helpers/content.type.helper.js' '@EzPlatformAdminUiBundle/Resources/public/js/scripts/admin.notifications.js' '@EzPlatformAdminUiModulesBundle/Resources/public/js/UniversalDiscovery.module.js' '@EzPlatformAdminUiBundle/Resources/public/js/scripts/button.trigger.js' diff --git a/src/bundle/Templating/Twig/ContentTypeIconExtension.php b/src/bundle/Templating/Twig/ContentTypeIconExtension.php new file mode 100644 index 0000000000..6977a5844b --- /dev/null +++ b/src/bundle/Templating/Twig/ContentTypeIconExtension.php @@ -0,0 +1,43 @@ +contentTypeIconResolver = $contentTypeIconResolver; + } + + /** + * {@inheritdoc} + */ + public function getFunctions(): array + { + return [ + new Twig_SimpleFunction( + 'ez_content_type_icon', + [$this->contentTypeIconResolver, 'getContentTypeIcon'], + [ + 'is_safe' => ['html'], + ] + ), + ]; + } +} diff --git a/src/lib/Tests/UI/Config/Service/ContentTypeIconResolverTest.php b/src/lib/Tests/UI/Config/Service/ContentTypeIconResolverTest.php new file mode 100644 index 0000000000..c39a440ebe --- /dev/null +++ b/src/lib/Tests/UI/Config/Service/ContentTypeIconResolverTest.php @@ -0,0 +1,121 @@ +configResolver = $this->createMock(ConfigResolverInterface::class); + $this->packages = $this->createMock(Packages::class); + + $this->contentTypeIconResolver = new ContentTypeIconResolver( + $this->configResolver, + $this->packages + ); + } + + /** + * @dataProvider dataProviderForGetContentTypeIcon + */ + public function testGetContentTypeIcon(array $config, string $identifier, string $expected) + { + $this->configResolver + ->expects($this->any()) + ->method('hasParameter') + ->willReturnCallback(function (string $key) use ($config) { + $key = explode('.', $key); + + return isset($config[array_pop($key)]); + }); + + $this->configResolver + ->expects($this->any()) + ->method('getParameter') + ->willReturnCallback(function (string $key) use ($config) { + $key = explode('.', $key); + + return $config[array_pop($key)]; + }); + + $this->packages + ->expects($this->any()) + ->method('getUrl') + ->willReturnCallback(function (string $uri) { + return "https://cdn.example.com/$uri"; + }); + + $this->assertEquals($expected, $this->contentTypeIconResolver->getContentTypeIcon($identifier)); + } + + public function dataProviderForGetContentTypeIcon(): array + { + return [ + [ + [ + 'custom' => [ + 'thumbnail' => 'icon.svg#custom', + ], + 'default-config' => [ + 'thumbnail' => 'icon.svg#default', + ], + ], + 'custom', + 'https://cdn.example.com/icon.svg#custom', + ], + [ + [ + 'custom-without-fragment' => [ + 'thumbnail' => 'icon.png', + ], + 'default-config' => [ + 'thumbnail' => 'icon.svg#default', + ], + ], + 'custom-without-fragment', + 'https://cdn.example.com/icon.png', + ], + [ + [ + 'custom-without-icon' => [ + 'thumbnail' => null, + ], + 'default-config' => [ + 'thumbnail' => 'icon.svg#default', + ], + ], + 'custom-without-icon', + 'https://cdn.example.com/icon.svg#default', + ], + [ + [ + 'default-config' => [ + 'thumbnail' => 'icon.svg#default', + ], + ], + 'custom-with-missing-config', + 'https://cdn.example.com/icon.svg#default', + ], + ]; + } +} diff --git a/src/lib/UI/Config/Provider/ContentTypes.php b/src/lib/UI/Config/Provider/ContentTypes.php index b5cc817801..ff4407e5b2 100644 --- a/src/lib/UI/Config/Provider/ContentTypes.php +++ b/src/lib/UI/Config/Provider/ContentTypes.php @@ -9,6 +9,7 @@ use eZ\Publish\API\Repository\ContentTypeService; use eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface; use EzSystems\EzPlatformAdminUi\UI\Config\ProviderInterface; +use EzSystems\EzPlatformAdminUi\UI\Service\ContentTypeIconResolver; class ContentTypes implements ProviderInterface { @@ -18,14 +19,22 @@ class ContentTypes implements ProviderInterface /** @var \eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface */ private $userLanguagePreferenceProvider; + /** @var \EzSystems\EzPlatformAdminUi\UI\Service\ContentTypeIconResolver */ + private $contentTypeIconResolver; + /** * @param \eZ\Publish\API\Repository\ContentTypeService $contentTypeService * @param \eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface $userLanguagePreferenceProvider + * @param \EzSystems\EzPlatformAdminUi\UI\Service\ContentTypeIconResolver $contentTypeIconResolver */ - public function __construct(ContentTypeService $contentTypeService, UserLanguagePreferenceProviderInterface $userLanguagePreferenceProvider) - { + public function __construct( + ContentTypeService $contentTypeService, + UserLanguagePreferenceProviderInterface $userLanguagePreferenceProvider, + ContentTypeIconResolver $contentTypeIconResolver + ) { $this->contentTypeService = $contentTypeService; $this->userLanguagePreferenceProvider = $userLanguagePreferenceProvider; + $this->contentTypeIconResolver = $contentTypeIconResolver; } /** @@ -48,6 +57,7 @@ public function getConfig() $contentTypeGroups[$contentTypeGroup->identifier][] = [ 'identifier' => $contentType->identifier, 'name' => $contentType->getName(), + 'thumbnail' => $this->contentTypeIconResolver->getContentTypeIcon($contentType->identifier), ]; } } diff --git a/src/lib/UI/Service/ContentTypeIconResolver.php b/src/lib/UI/Service/ContentTypeIconResolver.php new file mode 100644 index 0000000000..399ff49f7c --- /dev/null +++ b/src/lib/UI/Service/ContentTypeIconResolver.php @@ -0,0 +1,93 @@ +configResolver = $configResolver; + $this->packages = $packages; + } + + /** + * Returns path to content type icon. + * + * Path is resolved based on configuration (ezpublish.system..content_type.). If there isn't + * corresponding entry for given content type, then path to default icon will be returned. + * + * @param string $identifier + * + * @return string + */ + public function getContentTypeIcon(string $identifier): string + { + $icon = $this->resolveIcon($identifier); + + $fragment = null; + if (strpos($icon, '#') !== false) { + list($icon, $fragment) = explode('#', $icon); + } + + return $this->packages->getUrl($icon) . ($fragment ? '#' . $fragment : ''); + } + + /** + * @param string $identifier + * + * @return string + */ + private function resolveIcon(string $identifier): string + { + $config = null; + + $parameterName = $this->getConfigParameterName($identifier); + if ($this->configResolver->hasParameter($parameterName)) { + $config = $this->configResolver->getParameter($parameterName); + } + + if ($config === null || empty($config[self::ICON_KEY])) { + $config = $this->configResolver->getParameter( + $this->getConfigParameterName(self::DEFAULT_IDENTIFIER) + ); + } + + return $config[self::ICON_KEY]; + } + + /** + * Return configuration parameter name for given content type identifier. + * + * @param string $identifier + * + * @return string + */ + private function getConfigParameterName(string $identifier): string + { + return sprintf(self::PARAM_NAME_FORMAT, $identifier); + } +}