Skip to content
Snippets Groups Projects
Commit fd09bb40 authored by paul121's avatar paul121 Committed by Sascha Eggenberger
Browse files

Issue #3188521: Improve content form detection

parent a5779883
No related branches found
No related tags found
1 merge request!40Issue #3188521: Improve content form detection
<?php
/**
* @file
* Hooks for gin theme.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Register routes to apply Gin’s content edit form layout.
*
* Leverage this hook to achieve a consistent user interface layout on
* administrative edit forms, similar to the node edit forms. Any module
* providing a custom entity type or form mode may wish to implement this
* hook for their form routes. Please note that not every content entity
* form route should enable the Gin edit form layout, for example the
* delete entity form does not need it.
*
* @return array
* An array of route names.
*
* @see GinContentFormHelper->isContentForm()
* @see hook_gin_content_form_routes_alter()
*/
function hook_gin_content_form_routes() {
return [
// Layout a custom node form.
'entity.node.my_custom_form',
// Layout a custom entity type edit form.
'entity.my_type.edit_form',
];
}
/**
* Alter the registered routes to enable or disable Gin’s edit form layout.
*
* @param array $routes
* The list of routes.
*
* @return array
* An array of route names.
*
* @see GinContentFormHelper->isContentForm()
* @see hook_gin_content_form_routes()
*/
function hook_gin_content_form_routes_alter(array &$routes) {
// Example: disable Gin edit form layout customizations for an entity type.
$routes = array_diff($routes, ['entity.my_type.edit_form']);
}
/**
* @} End of "addtogroup hooks".
*/
......@@ -6,86 +6,14 @@
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\gin\GinContentFormHelper;
use Drupal\gin\GinSettings;
/**
* Implements form_alter_HOOK() for some major form changes.
*/
function gin_form_alter(&$form, $form_state, $form_id) {
// Are we on an edit form?
if (_gin_is_content_form($form, $form_state, $form_id)) {
// Action buttons.
if (isset($form['actions'])) {
if (isset($form['actions']['preview'])) {
// Put Save after Preview.
$save_weight = $form['actions']['preview']['#weight'] ? $form['actions']['preview']['#weight'] + 1 : 11;
$form['actions']['submit']['#weight'] = $save_weight;
}
// Move entity_save_and_addanother_node after preview.
if (isset($form['actions']['entity_save_and_addanother_node'])) {
// Put Save after Preview.
$save_weight = $form['actions']['entity_save_and_addanother_node']['#weight'];
$form['actions']['preview']['#weight'] = $save_weight - 1;
}
// Create gin_actions group.
$form['gin_actions'] = [
'#type' => 'container',
'#weight' => -1,
'#multilingual' => TRUE,
'#attributes' => [
'class' => [
'gin-sticky',
],
],
];
// Assign status to gin_actions.
$form['status']['#group'] = 'gin_actions';
// Create actions group.
$form['gin_actions']['actions'] = [
'#type' => 'actions',
'#weight' => 130,
];
// Move all actions over.
$form['gin_actions']['actions'] = ($form['actions']) ?? [];
// Now let's just remove delete, as we'll move that over to gin_sidebar.
unset($form['gin_actions']['actions']['delete']);
// Create gin_sidebar group.
$form['gin_sidebar'] = [
'#group' => 'meta',
'#type' => 'container',
'#weight' => 99,
'#multilingual' => TRUE,
'#attributes' => [
'class' => [
'gin-sidebar',
],
],
];
// Copy footer over.
$form['gin_sidebar']['footer'] = ($form['footer']) ?? [];
// Copy delete action.
$form['gin_sidebar']['actions'] = [];
$form['gin_sidebar']['actions']['#type'] = ($form['actions']['#type']) ?? [];
$form['gin_sidebar']['actions']['delete'] = ($form['actions']['delete']) ?? [];
}
// Attach library.
$form['#attached']['library'][] = 'gin/edit_form';
}
// If not logged in hide changed and author node info on add forms.
$not_logged_in = \Drupal::currentUser()->isAnonymous();
$route = \Drupal::routeMatch()->getRouteName();
if ($not_logged_in && $route == 'node.add') {
unset($form['meta']['changed']);
unset($form['meta']['author']);
}
\Drupal::classResolver(GinContentFormHelper::class)->formAlter($form, $form_state, $form_id);
// User form (Login, Register or Forgot password).
if (strpos($form_id, 'user_login') !== FALSE || strpos($form_id, 'user_register') !== FALSE || strpos($form_id, 'user_pass') !== FALSE) {
......
......@@ -135,49 +135,3 @@ function _gin_validate_path_logo($path) {
}
return FALSE;
}
/**
* Check if were on a content edit form.
*/
function _gin_is_content_form($form = NULL, $form_state = NULL, $form_id = NULL) {
$is_content_form = FALSE;
// Get route name.
$route_name = \Drupal::routeMatch()->getRouteName();
// Routes to include.
$route_names = [
'node.add',
'entity.node.content_translation_add',
'entity.node.content_translation_edit',
'quick_node_clone.node.quick_clone',
'entity.node.edit_form',
];
if (
in_array($route_name, $route_names, TRUE) ||
($form_state && ($form_state->getBuildInfo()['base_form_id'] ?? NULL) === 'node_form') ||
($route_name === 'entity.group_content.create_form' && strpos($form_id, 'group_node') === FALSE)
) {
$is_content_form = TRUE;
}
// Forms to exclude.
// If media library widget, don't use new content edit form.
// gin_preprocess_html is not triggered here, so checking
// the form id is enough.
$form_ids_to_ignore = [
'media_library_add_form_',
'views_form_media_library_widget_',
'views_exposed_form',
'date_recur_modular_sierra_occurrences_modal',
];
foreach ($form_ids_to_ignore as $form_id_to_ignore) {
if ($form_id && strpos($form_id, $form_id_to_ignore) !== FALSE) {
$is_content_form = FALSE;
}
}
return $is_content_form;
}
......@@ -5,6 +5,7 @@
* html.theme
*/
use Drupal\gin\GinContentFormHelper;
use Drupal\gin\GinSettings;
/**
......@@ -32,7 +33,7 @@ function gin_preprocess_html(&$variables) {
}
// Edit form? Use the new Gin Edit form layout.
if (_gin_is_content_form()) {
if (\Drupal::classResolver(GinContentFormHelper::class)->isContentForm()) {
$variables['attributes']['class'][] = 'gin--edit-form';
}
......
......@@ -5,6 +5,7 @@
* page.theme
*/
use Drupal\gin\GinContentFormHelper;
use Drupal\Core\Entity\EntityInterface;
use Drupal\gin\GinSettings;
......@@ -46,6 +47,12 @@ function gin_theme_suggestions_page_alter(&$suggestions, $variables) {
$arg = str_replace(["/", '-'], ['_', '_'], $path);
$suggestions[] = 'page__' . $arg;
}
// The node page template is required to use the node content form.
if (\Drupal::classResolver(GinContentFormHelper::class)->isContentForm()
&& !in_array('page__node', $suggestions)) {
$suggestions[] = 'page__node';
}
}
/**
......
<?php
namespace Drupal\gin;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Theme\ThemeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Service to handle content form overrides.
*/
class GinContentFormHelper implements ContainerInjectionInterface {
use StringTranslationTrait;
/**
* The current user object.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The current route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* The theme manager.
*
* @var \Drupal\Core\Theme\ThemeManagerInterface
*/
protected $themeManager;
/**
* GinContentFormHelper constructor.
*
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The current route match.
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
* The theme manager.
*/
public function __construct(AccountInterface $current_user, ModuleHandlerInterface $module_handler, RouteMatchInterface $route_match, ThemeManagerInterface $theme_manager) {
$this->currentUser = $current_user;
$this->moduleHandler = $module_handler;
$this->routeMatch = $route_match;
$this->themeManager = $theme_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_user'),
$container->get('module_handler'),
$container->get('current_route_match'),
$container->get('theme.manager'),
);
}
/**
* Add some major form overrides.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param string $form_id
* The form id.
*
* @see hook_form_alter()
*/
public function formAlter(array &$form, FormStateInterface $form_state, $form_id) {
// Are we on an edit form?
if (!$this->isContentForm($form, $form_state, $form_id)) {
return;
}
// Provide a default meta form element if not already provided.
// @see NodeForm::form()
$form['advanced']['#attributes']['class'][] = 'entity-meta';
if (!isset($form['meta'])) {
$form['meta'] = [
'#type' => 'container',
'#group' => 'advanced',
'#weight' => -10,
'#title' => $this->t('Status'),
'#attributes' => ['class' => ['entity-meta__header']],
'#tree' => TRUE,
'#access' => TRUE,
];
}
// Specify necessary node form theme and library.
// @see claro_form_node_form_alter
$form['#theme'] = ['node_edit_form'];
$form['#attached']['library'][] = 'claro/node-form';
$form['#attached']['library'][] = 'gin/edit_form';
// Ensure correct settings for advanced, meta and revision form elements.
$form['advanced']['#type'] = 'container';
$form['advanced']['#accordion'] = TRUE;
$form['meta']['#type'] = 'container';
$form['meta']['#access'] = TRUE;
$form['revision_information']['#type'] = 'container';
$form['revision_information']['#group'] = 'meta';
$form['revision_information']['#attributes']['class'][] = 'entity-meta__revision';
// Action buttons.
if (isset($form['actions'])) {
if (isset($form['actions']['preview'])) {
// Put Save after Preview.
$save_weight = $form['actions']['preview']['#weight'] ? $form['actions']['preview']['#weight'] + 1 : 11;
$form['actions']['submit']['#weight'] = $save_weight;
}
// Create gin_actions group.
$form['gin_actions'] = [
'#type' => 'container',
'#weight' => -1,
'#multilingual' => TRUE,
'#attributes' => [
'class' => [
'gin-sticky',
],
],
];
// Assign status to gin_actions.
$form['status']['#group'] = 'gin_actions';
// Create actions group.
$form['gin_actions']['actions'] = [
'#type' => 'actions',
'#weight' => 130,
];
// Add Preview to gin_actions actions.
$form['gin_actions']['actions']['preview'] = ($form['actions']['preview']) ?? [];
// Add Submit to gin_actions actions.
$form['gin_actions']['actions']['submit'] = ($form['actions']['submit']) ?? [];
// Create gin_sidebar group.
$form['gin_sidebar'] = [
'#group' => 'meta',
'#type' => 'container',
'#weight' => 99,
'#multilingual' => TRUE,
'#attributes' => [
'class' => [
'gin-sidebar',
],
],
];
// Copy footer over.
$form['gin_sidebar']['footer'] = ($form['footer']) ?? [];
// Copy actions over.
$form['gin_sidebar']['actions'] = ($form['actions']) ?? [];
// Unset previous added preview & submit.
unset($form['gin_sidebar']['actions']['preview']);
unset($form['gin_sidebar']['actions']['submit']);
}
// Attach library.
$form['#attached']['library'][] = 'gin/gin_editform';
// If not logged in hide changed and author node info on add forms.
$not_logged_in = $this->currentUser->isAnonymous();
$route = $this->routeMatch->getRouteName();
if ($not_logged_in && $route == 'node.add') {
unset($form['meta']['changed']);
unset($form['meta']['author']);
}
}
/**
* Check if we´re on a content edit form.
*
* _gin_is_content_form() is replaced by
* \Drupal::classResolver(GinContentFormHelper::class)->isContentForm().
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param string $form_id
* The form id.
*/
public function isContentForm(array $form = NULL, FormStateInterface $form_state = NULL, $form_id = NULL) {
$is_content_form = FALSE;
// Get route name.
$route_name = $this->routeMatch->getRouteName();
// Routes to include.
$route_names = [
'node.add',
'entity.node.content_translation_add',
'quick_node_clone.node.quick_clone',
'entity.node.edit_form',
];
$additional_routes = $this->moduleHandler->invokeAll('gin_content_form_routes');
$route_names = array_merge($additional_routes, $route_names);
$this->moduleHandler->alter('gin_content_form_routes', $route_names);
$this->themeManager->alter('gin_content_form_routes', $route_names);
if (
in_array($route_name, $route_names, TRUE) ||
($form_state && ($form_state->getBuildInfo()['base_form_id'] ?? NULL) === 'node_form') ||
($route_name === 'entity.group_content.create_form' && strpos($form_id, 'group_node') === FALSE)
) {
$is_content_form = TRUE;
}
// Forms to exclude.
// If media library widget, don't use new content edit form.
// gin_preprocess_html is not triggered here, so checking
// the form id is enough.
$form_ids_to_ignore = [
'media_library_add_form_',
'views_form_media_library_widget_',
'views_exposed_form',
'date_recur_modular_sierra_occurrences_modal',
];
foreach ($form_ids_to_ignore as $form_id_to_ignore) {
if ($form_id && strpos($form_id, $form_id_to_ignore) !== FALSE) {
$is_content_form = FALSE;
}
}
return $is_content_form;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment