better_messages.module 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <?php
  2. /**
  3. * Implements hook_theme().
  4. */
  5. function better_messages_theme() {
  6. return [
  7. 'better_messages_wrapper' => [
  8. 'render element' => 'element',
  9. 'variables' => [
  10. 'children' => '',
  11. 'message_list' => [],
  12. ],
  13. ],
  14. ];
  15. }
  16. /**
  17. * Implements hook_element_info_alter().
  18. */
  19. function better_messages_element_info_alter(array &$info) {
  20. // Replace the default pre_render for status_messages with our custom one.
  21. $info['status_messages']['#pre_render'][0] = 'better_messages_status_messages_pre_render';
  22. }
  23. /**
  24. * Pre render callback for 'status_messages' render element.
  25. */
  26. function better_messages_status_messages_pre_render(array $element) {
  27. // The code below is heavily copied from StatusMessages::renderMessages().
  28. $element = [
  29. '#lazy_builder' => ['better_messages_status_messages_lazy_builder', [$element['#display']]],
  30. '#create_placeholder' => TRUE,
  31. ];
  32. // Directly create a placeholder as we need this to be placeholdered
  33. // regardless if this is a POST or GET request.
  34. // @todo remove this when https://www.drupal.org/node/2367555 lands.
  35. return \Drupal::service('render_placeholder_generator')->createPlaceholder($element);
  36. }
  37. /**
  38. * Lazy builder for 'status_messages'.
  39. *
  40. * Improved version of StatusMessages::renderMessages() that additionally wraps
  41. * the output into an overlay markup whenever necessary.
  42. *
  43. * @param string|null $type
  44. * Limit the messages returned by type. Defaults to NULL, meaning all types.
  45. * Passed on to drupal_get_messages(). These values are supported:
  46. * - NULL
  47. * - 'status'
  48. * - 'warning'
  49. * - 'error'
  50. *
  51. * @return array
  52. * A renderable array containing the messages.
  53. */
  54. function better_messages_status_messages_lazy_builder($type) {
  55. $render = \Drupal\Core\Render\Element\StatusMessages::renderMessages($type);
  56. if (!empty($render)) {
  57. $render['#theme_wrappers'][] = 'better_messages_wrapper';
  58. $render['#attached']['library'][] = 'better_messages/better_messages';
  59. $render['#attached']['drupalSettings']['better_messages'] = \Drupal::config('better_messages.settings')->get();
  60. }
  61. return $render;
  62. }
  63. /**
  64. * Preprocess for 'better_messages_wrapper' theme hook.
  65. */
  66. function template_preprocess_better_messages_wrapper(&$variables) {
  67. $settings = \Drupal::config('better_messages.settings');
  68. $cache = \Drupal\Core\Cache\CacheableMetadata::createFromRenderArray($variables);
  69. $cache->addCacheTags($settings->getCacheTags());
  70. $cache->addCacheContexts($settings->getCacheContexts());
  71. $cache->mergeCacheMaxAge($settings->getCacheMaxAge());
  72. // Inject the messages from $variables into our "better_messages" context
  73. // since now we have crossed beyond the point where "current" messages are
  74. // retrievable via drupal_get_messages().
  75. \Drupal::service('better_messages.context')->setMessages($variables['message_list']);
  76. /** @var \Drupal\Core\Condition\ConditionManager $condition_manager */
  77. $condition_manager = \Drupal::service('plugin.manager.condition');
  78. /** @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository */
  79. $context_repository = \Drupal::service('context.repository');
  80. /** @var \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler */
  81. $context_handler = \Drupal::service('context.handler');
  82. $pass = TRUE;
  83. foreach ($settings->get('visibility') as $condition_id => $condition) {
  84. $condition = $condition_manager->createInstance($condition_id, $condition);
  85. if ($condition instanceof \Drupal\Core\Plugin\ContextAwarePluginInterface) {
  86. try {
  87. $contexts = $context_repository->getRuntimeContexts(array_values($condition->getContextMapping()));
  88. $context_handler->applyContextMapping($condition, $contexts);
  89. }
  90. catch (\Drupal\Component\Plugin\Exception\ContextException $e) {
  91. // We couldn't initialize the condition, so it just cannot participate.
  92. continue;
  93. }
  94. }
  95. try {
  96. $pass = $condition->execute();
  97. }
  98. catch (\Drupal\Component\Plugin\Exception\ContextException $e) {
  99. // Condition couldn't evaluate itself. Let's skip it.
  100. continue;
  101. }
  102. if ($condition instanceof \Drupal\Core\Cache\CacheableDependencyInterface) {
  103. $cache->addCacheTags($condition->getCacheTags());
  104. $cache->addCacheContexts($condition->getCacheContexts());
  105. $cache->mergeCacheMaxAge($condition->getCacheMaxAge());
  106. }
  107. if (!$pass) {
  108. break;
  109. }
  110. }
  111. $cache->applyTo($variables);
  112. if ($pass && !empty($variables['message_list'])) {
  113. $variables['attributes']['class'][] = 'better-messages-overlay';
  114. if (\Drupal::config('better_messages.settings')->get('fixed')) {
  115. $variables['attributes']['class'][] = 'better-messages-position-fixed';
  116. }
  117. if (isset($variables['message_list']['error'])) {
  118. $variables['attributes']['class'][] = 'better-messages-has-errors';
  119. }
  120. }
  121. }