Loading gutenberg.api.php +26 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ use Drupal\Core\Entity\Query\Sql\Query; use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Routing\RouteMatchInterface; /** * @addtogroup hooks Loading Loading @@ -134,6 +135,31 @@ function hook_gutenberg_block_view_BASE_BLOCK_ID_alter(array &$build, &$block_co $build['#pre_render'][] = 'hook_gutenberg_BASE_BLOCK_ID_pre_render'; } /** * Provide the appropriate Gutenberg content type for a given route. * * Gutenberg fetches the node type through route match. If for custom routes, * it's necessary to resolve the content type. * Below is an example to handle Group Node module (part of Group module). * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The current route instance. * * @return string|null * The content type. */ function hook_gutenberg_node_type_route(RouteMatchInterface $route_match) { $route_name = $route_match->getRouteName(); if ($route_name == 'entity.group_content.create_form') { /** @var string @parameter */ $parameter = $route_match->getParameter('plugin_id'); return explode(':', $parameter)[1]; } return NULL; } /** * @} End of "addtogroup hooks". */ gutenberg.module +6 −30 Original line number Diff line number Diff line Loading @@ -707,21 +707,9 @@ function gutenberg_entity_presave($entity) { * Implements hook_theme_suggestions_HOOK_alter(). */ function gutenberg_theme_suggestions_node_edit_form_alter(array &$suggestions, array $variables) { $config = \Drupal::service('config.factory')->getEditable('gutenberg.settings'); $node = \Drupal::routeMatch()->getParameter('node'); if (!$node) { $route_match = \Drupal::service('current_route_match'); if (!$route_match->getParameter('node_type')) { return; } $node_type = $route_match->getParameter('node_type')->get('type'); } else { $node_type = $node->type->getString(); } $gutenberg_enabled = $config->get($node_type . '_enable_full'); $contentTypeManager = \Drupal::service('gutenberg.content_type_manager'); $node_type = $contentTypeManager->getGutenbergNodeTypeFromRoute(\Drupal::routeMatch()); $gutenberg_enabled = $contentTypeManager->isContentTypeSupported($node_type); if (!$gutenberg_enabled) { return; Loading @@ -739,21 +727,9 @@ function gutenberg_theme_suggestions_page_alter(array &$suggestions, array $vari return; } $config = \Drupal::service('config.factory')->getEditable('gutenberg.settings'); $node = \Drupal::routeMatch()->getParameter('node'); if (!$node) { $route_match = \Drupal::service('current_route_match'); if (!$route_match->getParameter('node_type')) { return; } $node_type = $route_match->getParameter('node_type')->get('type'); } else { $node_type = $node->type->getString(); } $gutenberg_enabled = $config->get($node_type . '_enable_full'); $contentTypeManager = \Drupal::service('gutenberg.content_type_manager'); $node_type = $contentTypeManager->getGutenbergNodeTypeFromRoute(\Drupal::routeMatch()); $gutenberg_enabled = $contentTypeManager->isContentTypeSupported($node_type); if ($gutenberg_enabled) { if (in_array('page__node__edit', $suggestions)) { Loading gutenberg.services.yml +3 −0 Original line number Diff line number Diff line Loading @@ -101,3 +101,6 @@ services: arguments: ['@entity_type.manager'] tags: - { name: media_selection_processor, processor_name: default } gutenberg.content_type_manager: class: Drupal\gutenberg\GutenbergContentTypeManager arguments: ['@module_handler', '@config.factory', '@entity_field.manager'] src/GutenbergContentTypeManager.php 0 → 100644 +136 −0 Original line number Diff line number Diff line <?php namespace Drupal\gutenberg; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Config\ConfigFactoryInterface; /** * Manager for Gutenberg content types. * * @package Drupal\gutenberg */ class GutenbergContentTypeManager { /** * The module handler to invoke the alter hook. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ protected $moduleHandler; /** * The config factory. * * @var \Drupal\Core\Config\ConfigFactoryInterface */ protected $configFactory; /** * The entity field manager. * * @var \Drupal\Core\Entity\EntityFieldManagerInterface */ protected $entityFieldManager; /** * Constructs a new GutenbergEntityTypeManager. * * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The entity field manager. */ public function __construct( ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, EntityFieldManagerInterface $entity_field_manager ) { $this->moduleHandler = $module_handler; $this->configFactory = $config_factory; $this->entityFieldManager = $entity_field_manager; } /** * Check if content type supports Gutenberg. * * @param string|null $content_type * The content type. * * @return bool|null * True or false or null */ public function isContentTypeSupported($content_type = NULL) { $config = $this->configFactory->getEditable('gutenberg.settings'); $gutenberg_enabled = $config->get($content_type . '_enable_full'); return $gutenberg_enabled; } /** * {@inheritdoc} * * @return mixed[] * The fields. */ public function getGutenbergCompatibleFields(string $content_type) { $compatible_fields = []; $field_definitions = $this->entityFieldManager->getFieldDefinitions('node', $content_type); foreach ($field_definitions as $name => $definition) { if ($definition && !$definition->isComputed()) { $storage_definition = $definition->getFieldStorageDefinition(); $supported_types = ['text', 'text_long', 'text_with_summary']; if ( $storage_definition && $storage_definition->getCardinality() === 1 && in_array($storage_definition->getType(), $supported_types) ) { $compatible_fields[$name] = $definition->getLabel(); } } } return $compatible_fields; } /** * {@inheritdoc} * * @return string|null * Content type or null. */ public function getGutenbergNodeTypeFromRoute(RouteMatchInterface $route_match) { /** @var \Drupal\node\Entity\Node|null $node */ $node = $route_match->getParameter('node'); /** @var \Drupal\node\Entity\NodeType|null $node_type */ $node_type = $route_match->getParameter('node_type'); // Do we have a node defined on the route? if ($node) { // Then just return its type. return $node->getType(); } // Do we have a content type defined on the route? if ($node_type) { // Then just return it. return $node_type->get('type'); } // Otherwise, go through all hooks to resolve the content type. $hook = 'gutenberg_node_type_route'; foreach ($this->moduleHandler->getImplementations($hook) as $module) { $function = $module . '_' . $hook; if (is_callable($function)) { return $function($route_match); } } // No content type found. return NULL; } } src/Plugin/Editor/Gutenberg.php +56 −15 Original line number Diff line number Diff line Loading @@ -13,6 +13,9 @@ use Drupal\editor\Plugin\EditorBase; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\editor\Entity\Editor; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\gutenberg\GutenbergContentTypeManager; use Drupal\Core\Config\ConfigFactoryInterface; /** * Defines a Gutenberg-based text editor for Drupal. Loading Loading @@ -58,6 +61,27 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { */ protected $renderer; /** * The content type manager. * * @var \Drupal\gutenberg\GutenbergContentTypeManager */ protected $contentTypeManager; /** * The route match. * * @var \Drupal\Core\Routing\RouteMatchInterface */ protected $routeMatch; /** * The config factory. * * @var \Drupal\Core\Config\ConfigFactoryInterface */ protected $configFactory; /** * Constructs a Gutenberg object. * Loading @@ -75,13 +99,33 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { * The language manager. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer. * @param \Drupal\gutenberg\GutenbergContentTypeManager $content_type_manager * The content type manager. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, GutenbergPluginManager $gutenberg_plugin_manager, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, RendererInterface $renderer) { public function __construct( array $configuration, $plugin_id, $plugin_definition, GutenbergPluginManager $gutenberg_plugin_manager, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, RendererInterface $renderer, GutenbergContentTypeManager $content_type_manager, RouteMatchInterface $route_match, ConfigFactoryInterface $config_factory ) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->gutenbergPluginManager = $gutenberg_plugin_manager; $this->moduleHandler = $module_handler; $this->languageManager = $language_manager; $this->renderer = $renderer; $this->contentTypeManager = $content_type_manager; $this->routeMatch = $route_match; $this->configFactory = $config_factory; } /** Loading @@ -95,7 +139,10 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { $container->get('plugin.manager.gutenberg.plugin'), $container->get('module_handler'), $container->get('language_manager'), $container->get('renderer') $container->get('renderer'), $container->get('gutenberg.content_type_manager'), $container->get('current_route_match'), $container->get('config.factory') ); } Loading Loading @@ -146,28 +193,22 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { * * @param \Drupal\editor\Entity\Editor $editor * A configured text editor object. * * @return array|null * The settings. */ public function getJsSettings(Editor $editor) { $config = \Drupal::service('config.factory')->getEditable('gutenberg.settings'); $node = \Drupal::routeMatch()->getParameter('node'); $node_type = $this->contentTypeManager->getGutenbergNodeTypeFromRoute($this->routeMatch); if (!$node) { $route_match = \Drupal::service('current_route_match'); if (!$route_match->getParameter('node_type')) { return; } $node_type = $route_match->getParameter('node_type')->get('type'); } else { $node_type = $node->type->getString(); if (!$node_type) { return NULL; } $blocks_settings = UtilsController::getBlocksSettings(); $settings = [ 'contentType' => $node_type, 'allowedBlocks' => $config->get($node_type . '_allowed_blocks'), 'allowedBlocks' => $this->configFactory->get($node_type . '_allowed_blocks'), 'blackList' => $blocks_settings['blacklist'], ]; Loading Loading
gutenberg.api.php +26 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ use Drupal\Core\Entity\Query\Sql\Query; use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Routing\RouteMatchInterface; /** * @addtogroup hooks Loading Loading @@ -134,6 +135,31 @@ function hook_gutenberg_block_view_BASE_BLOCK_ID_alter(array &$build, &$block_co $build['#pre_render'][] = 'hook_gutenberg_BASE_BLOCK_ID_pre_render'; } /** * Provide the appropriate Gutenberg content type for a given route. * * Gutenberg fetches the node type through route match. If for custom routes, * it's necessary to resolve the content type. * Below is an example to handle Group Node module (part of Group module). * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The current route instance. * * @return string|null * The content type. */ function hook_gutenberg_node_type_route(RouteMatchInterface $route_match) { $route_name = $route_match->getRouteName(); if ($route_name == 'entity.group_content.create_form') { /** @var string @parameter */ $parameter = $route_match->getParameter('plugin_id'); return explode(':', $parameter)[1]; } return NULL; } /** * @} End of "addtogroup hooks". */
gutenberg.module +6 −30 Original line number Diff line number Diff line Loading @@ -707,21 +707,9 @@ function gutenberg_entity_presave($entity) { * Implements hook_theme_suggestions_HOOK_alter(). */ function gutenberg_theme_suggestions_node_edit_form_alter(array &$suggestions, array $variables) { $config = \Drupal::service('config.factory')->getEditable('gutenberg.settings'); $node = \Drupal::routeMatch()->getParameter('node'); if (!$node) { $route_match = \Drupal::service('current_route_match'); if (!$route_match->getParameter('node_type')) { return; } $node_type = $route_match->getParameter('node_type')->get('type'); } else { $node_type = $node->type->getString(); } $gutenberg_enabled = $config->get($node_type . '_enable_full'); $contentTypeManager = \Drupal::service('gutenberg.content_type_manager'); $node_type = $contentTypeManager->getGutenbergNodeTypeFromRoute(\Drupal::routeMatch()); $gutenberg_enabled = $contentTypeManager->isContentTypeSupported($node_type); if (!$gutenberg_enabled) { return; Loading @@ -739,21 +727,9 @@ function gutenberg_theme_suggestions_page_alter(array &$suggestions, array $vari return; } $config = \Drupal::service('config.factory')->getEditable('gutenberg.settings'); $node = \Drupal::routeMatch()->getParameter('node'); if (!$node) { $route_match = \Drupal::service('current_route_match'); if (!$route_match->getParameter('node_type')) { return; } $node_type = $route_match->getParameter('node_type')->get('type'); } else { $node_type = $node->type->getString(); } $gutenberg_enabled = $config->get($node_type . '_enable_full'); $contentTypeManager = \Drupal::service('gutenberg.content_type_manager'); $node_type = $contentTypeManager->getGutenbergNodeTypeFromRoute(\Drupal::routeMatch()); $gutenberg_enabled = $contentTypeManager->isContentTypeSupported($node_type); if ($gutenberg_enabled) { if (in_array('page__node__edit', $suggestions)) { Loading
gutenberg.services.yml +3 −0 Original line number Diff line number Diff line Loading @@ -101,3 +101,6 @@ services: arguments: ['@entity_type.manager'] tags: - { name: media_selection_processor, processor_name: default } gutenberg.content_type_manager: class: Drupal\gutenberg\GutenbergContentTypeManager arguments: ['@module_handler', '@config.factory', '@entity_field.manager']
src/GutenbergContentTypeManager.php 0 → 100644 +136 −0 Original line number Diff line number Diff line <?php namespace Drupal\gutenberg; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Config\ConfigFactoryInterface; /** * Manager for Gutenberg content types. * * @package Drupal\gutenberg */ class GutenbergContentTypeManager { /** * The module handler to invoke the alter hook. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ protected $moduleHandler; /** * The config factory. * * @var \Drupal\Core\Config\ConfigFactoryInterface */ protected $configFactory; /** * The entity field manager. * * @var \Drupal\Core\Entity\EntityFieldManagerInterface */ protected $entityFieldManager; /** * Constructs a new GutenbergEntityTypeManager. * * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The entity field manager. */ public function __construct( ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, EntityFieldManagerInterface $entity_field_manager ) { $this->moduleHandler = $module_handler; $this->configFactory = $config_factory; $this->entityFieldManager = $entity_field_manager; } /** * Check if content type supports Gutenberg. * * @param string|null $content_type * The content type. * * @return bool|null * True or false or null */ public function isContentTypeSupported($content_type = NULL) { $config = $this->configFactory->getEditable('gutenberg.settings'); $gutenberg_enabled = $config->get($content_type . '_enable_full'); return $gutenberg_enabled; } /** * {@inheritdoc} * * @return mixed[] * The fields. */ public function getGutenbergCompatibleFields(string $content_type) { $compatible_fields = []; $field_definitions = $this->entityFieldManager->getFieldDefinitions('node', $content_type); foreach ($field_definitions as $name => $definition) { if ($definition && !$definition->isComputed()) { $storage_definition = $definition->getFieldStorageDefinition(); $supported_types = ['text', 'text_long', 'text_with_summary']; if ( $storage_definition && $storage_definition->getCardinality() === 1 && in_array($storage_definition->getType(), $supported_types) ) { $compatible_fields[$name] = $definition->getLabel(); } } } return $compatible_fields; } /** * {@inheritdoc} * * @return string|null * Content type or null. */ public function getGutenbergNodeTypeFromRoute(RouteMatchInterface $route_match) { /** @var \Drupal\node\Entity\Node|null $node */ $node = $route_match->getParameter('node'); /** @var \Drupal\node\Entity\NodeType|null $node_type */ $node_type = $route_match->getParameter('node_type'); // Do we have a node defined on the route? if ($node) { // Then just return its type. return $node->getType(); } // Do we have a content type defined on the route? if ($node_type) { // Then just return it. return $node_type->get('type'); } // Otherwise, go through all hooks to resolve the content type. $hook = 'gutenberg_node_type_route'; foreach ($this->moduleHandler->getImplementations($hook) as $module) { $function = $module . '_' . $hook; if (is_callable($function)) { return $function($route_match); } } // No content type found. return NULL; } }
src/Plugin/Editor/Gutenberg.php +56 −15 Original line number Diff line number Diff line Loading @@ -13,6 +13,9 @@ use Drupal\editor\Plugin\EditorBase; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\editor\Entity\Editor; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\gutenberg\GutenbergContentTypeManager; use Drupal\Core\Config\ConfigFactoryInterface; /** * Defines a Gutenberg-based text editor for Drupal. Loading Loading @@ -58,6 +61,27 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { */ protected $renderer; /** * The content type manager. * * @var \Drupal\gutenberg\GutenbergContentTypeManager */ protected $contentTypeManager; /** * The route match. * * @var \Drupal\Core\Routing\RouteMatchInterface */ protected $routeMatch; /** * The config factory. * * @var \Drupal\Core\Config\ConfigFactoryInterface */ protected $configFactory; /** * Constructs a Gutenberg object. * Loading @@ -75,13 +99,33 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { * The language manager. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer. * @param \Drupal\gutenberg\GutenbergContentTypeManager $content_type_manager * The content type manager. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, GutenbergPluginManager $gutenberg_plugin_manager, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, RendererInterface $renderer) { public function __construct( array $configuration, $plugin_id, $plugin_definition, GutenbergPluginManager $gutenberg_plugin_manager, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, RendererInterface $renderer, GutenbergContentTypeManager $content_type_manager, RouteMatchInterface $route_match, ConfigFactoryInterface $config_factory ) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->gutenbergPluginManager = $gutenberg_plugin_manager; $this->moduleHandler = $module_handler; $this->languageManager = $language_manager; $this->renderer = $renderer; $this->contentTypeManager = $content_type_manager; $this->routeMatch = $route_match; $this->configFactory = $config_factory; } /** Loading @@ -95,7 +139,10 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { $container->get('plugin.manager.gutenberg.plugin'), $container->get('module_handler'), $container->get('language_manager'), $container->get('renderer') $container->get('renderer'), $container->get('gutenberg.content_type_manager'), $container->get('current_route_match'), $container->get('config.factory') ); } Loading Loading @@ -146,28 +193,22 @@ class Gutenberg extends EditorBase implements ContainerFactoryPluginInterface { * * @param \Drupal\editor\Entity\Editor $editor * A configured text editor object. * * @return array|null * The settings. */ public function getJsSettings(Editor $editor) { $config = \Drupal::service('config.factory')->getEditable('gutenberg.settings'); $node = \Drupal::routeMatch()->getParameter('node'); $node_type = $this->contentTypeManager->getGutenbergNodeTypeFromRoute($this->routeMatch); if (!$node) { $route_match = \Drupal::service('current_route_match'); if (!$route_match->getParameter('node_type')) { return; } $node_type = $route_match->getParameter('node_type')->get('type'); } else { $node_type = $node->type->getString(); if (!$node_type) { return NULL; } $blocks_settings = UtilsController::getBlocksSettings(); $settings = [ 'contentType' => $node_type, 'allowedBlocks' => $config->get($node_type . '_allowed_blocks'), 'allowedBlocks' => $this->configFactory->get($node_type . '_allowed_blocks'), 'blackList' => $blocks_settings['blacklist'], ]; Loading