bootstrap_five_layouts-1.0.x-dev/bootstrap_five_layouts.module

bootstrap_five_layouts.module
<?php

/**
 * @file
 * Contains bootstrap_five_layouts.module.
 */

use Drupal\bootstrap_five_layouts\BootstrapFiveLayout;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Render\Element;
use Drupal\Core\Template\Attribute;

/**
 * Implements hook_theme_registry_alter().
 */
function bootstrap_five_layouts_theme_registry_alter(&$theme_registry) {
  // Immediately return if the layout manager cannot be loaded.
  // This can happen during the update process.
  if (!\Drupal::hasService('plugin.manager.core.layout')) {
    return;
  }

  // Find all Bootstrap Layouts.
  $layouts = \Drupal::service('plugin.manager.core.layout')->getDefinitions();
  $layout_theme_hooks = [];
  /** @var \Drupal\Core\Layout\LayoutDefinition $info */
  foreach ($layouts as $info) {
    if (is_a($info->getClass(), 'Drupal\bootstrap_five_layouts\Plugin\Layout\BootstrapFiveLayoutsBase', TRUE)) {
      $layout_theme_hooks[] = $info->getThemeHook();
    }
  }

  // Add a special internal preprocess function.
  foreach ($theme_registry as $theme_hook => $info) {
    if (in_array($theme_hook, $layout_theme_hooks) || (!empty($info['base hook']) && in_array($info['base hook'], $layout_theme_hooks))) {
      $theme_registry[$theme_hook]['preprocess functions'][] = '_bootstrap_five_layouts_preprocess_layout';
    }
  }
}

/**
 * Parses an attribute string saved in the UI.
 *
 * @param string $string
 *   The attribute string to parse.
 * @param array $tokens
 *   An associative array of token data to use.
 *
 * @return array
 *   A parsed attributes array.
 */
function _bootstrap_five_layouts_parse_attributes($string = NULL, array $tokens = []) {
  static $token;
  if (!isset($token)) {
    /** @var \Drupal\Core\Utility\Token $token */
    $token = \Drupal::service('token');
  }
  $attributes = [];
  if (!empty($string)) {
    $parts = explode(',', $string);
    foreach ($parts as $attribute) {
      if (strpos($attribute, '|') !== FALSE) {
        list($key, $value) = explode('|', $token->replace($attribute, $tokens, ['clear' => TRUE]));
        $attributes[$key] = $value;
      }
    }
  }
  return $attributes;
}

/**
 * Internal preprocess callback.
 *
 * This is used to determine standardize variables to use in Bootstrap Layouts
 * templates based on whatever implementation is used (i.e. Display Suite or
 * Panels, etc.).
 *
 * @param array $variables
 *   Variables array, passed by reference.
 */
function _bootstrap_five_layouts_preprocess_layout(array &$variables) {
  /** @var \Drupal\Core\Layout\LayoutDefinition $layout_definition */
  $layout_definition = $variables['layout'];

      // Utilize the BootstrapFiveLayout utility class to normalize DX readability here.
    $layout = new BootstrapFiveLayout($layout_definition->id(), [], $variables['settings']);

  // Determine the entity, entity type and bundle.
  /** @var \Drupal\Core\Entity\EntityInterface $entity */
  $entity = isset($variables['content']['#entity']) ? $variables['content']['#entity'] : FALSE;
  $entity_type = isset($variables['content']['#entity_type']) ? $variables['content']['#entity_type'] : FALSE;
  $bundle = isset($variables['content']['#bundle']) ? $variables['content']['#bundle'] : FALSE;
  $view_mode = isset($variables['content']['#view_mode']) ? $variables['content']['#view_mode'] : FALSE;

  $tokens = [];
  if ($entity_type && $entity) {
    $tokens[$entity_type] = $entity;

    // Copy entity to top level to improve theme experience.
    $variables[$entity_type] = $entity;
  }

  // Build 'decor'.
  $decor_attributes = new Attribute();
  $container_theme = $layout->getSetting('container.container_theme', NULL);
  if ($container_theme){
    $decor_attributes->addClass($container_theme);
  }

  $container_visibility = $layout->getSetting('container.container_visibility', []);
  if (!empty($container_visibility)){
    // Extract all selected visibility class names (handles multiple breakpoint options)
    // Visibility options store keys as space-separated class strings: ['d-sm-none d-md-block' => 'Hide on sm', ...]
    // Need to split each key by spaces to get individual classes
    $visibility_classes = [];
    foreach (array_keys($container_visibility) as $class_string) {
      // Split space-separated classes and merge into flat array
      $classes = preg_split('/\s+/', trim($class_string));
      $visibility_classes = array_merge($visibility_classes, array_filter($classes));
    }
    if (!empty($visibility_classes)) {
      $decor_attributes->addClass($visibility_classes);
    }
  }
  $variables['decor'] = $decor_attributes;

  // Build 'container'.
  // Compute build_classes using the same logic as BootstrapFiveLayoutsBase::build()
  $build_classes = [];
  $container_type = $layout->getSetting('container.container_type', NULL);
  if (!empty($container_type)) {
    $build_classes[] = $container_type;
  }

  $container_visibility = $layout->getSetting('container.container_visibility', []);
  if (!empty($container_visibility)) {
    $build_classes = array_merge($build_classes, array_keys($container_visibility));
  }

  // Process dynamic utility classes from addFormZoneInstances
  $container_settings = $layout->getSetting('container', []);
  if (is_array($container_settings)) {
    foreach ($container_settings as $config_key => $config_value) {
      if (strpos($config_key, 'classes_') === 0 && !empty($config_value)) {
        $value_to_merge = is_array($config_value) ? $config_value : [$config_value];
        $build_classes = array_merge($build_classes, $value_to_merge);
      }
    }
  }

  // Handle container classes (string, split by spaces)
  $container_classes = $layout->getSetting('container.classes', '');
  if (!empty($container_classes)) {
    if (is_array($container_classes)) {
      $build_classes = array_merge($build_classes, $container_classes);
    } else {
      $build_classes = array_merge($build_classes, preg_split('/\s+/', $container_classes));
    }
  }

  // Remove empty values and implode
  $build_classes = array_filter($build_classes, function($item) { return $item !== ''; });
  $build_classes_string = implode(' ', $build_classes);

  $container_attributes = new Attribute();
  if (!empty($build_classes_string)) {
    $container_attributes->addClass($build_classes_string);
  }
  $variables['container_attributes'] = $container_attributes;


  // Build 'Row'.
  $variables['wrapper'] = $layout->getSetting('row.wrapper', 'div');
  $row_attributes = isset($variables['attributes']) ? $variables['attributes'] : [];
  $row_attributes = NestedArray::mergeDeep(_bootstrap_five_layouts_parse_attributes($layout->getSetting('row.attributes'), $tokens), $row_attributes);

  $attributes = new Attribute($row_attributes);
  // Add row id if set.
  if ($layout->getSetting('row.id')) {
    $attributes->setAttribute('id', Html::getUniqueId($layout->getSetting('row.id')));
  }
  $attributes->addClass(array_keys($layout->getSetting('row.classes', [])));
  if ($layout->getSetting('row.add_row_classes')) {
    $attributes->addClass(Html::cleanCssIdentifier('row-' . $layout->getId()) );
  }

  // Unfortunately since Display Suite doesn't abstract this bit of code, it
  // must be duplicated in this module to support it from the UI.
  if ($entity_type && isset($variables['content']['#ds_configuration'])) {
    // Add theming-classes to template.
    $entity_classes = !empty($variables['content']['#ds_configuration']['layout']['entity_classes']) ? $variables['content']['#ds_configuration']['layout']['entity_classes'] : 'old_view_mode';
    if ($entity_classes !== 'no_classes') {
      if ($entity_classes === 'all_classes') {
        $entity_type_class = Html::cleanCssIdentifier($entity_type);
        $entity_classes = [$entity_type_class];
        if ($bundle) {
          $entity_classes[] = "$entity_type_class--type-" . Html::cleanCssIdentifier($bundle);
        }
        if ($view_mode) {
          $entity_classes[] = "$entity_type_class--view-mode-" . Html::cleanCssIdentifier($view_mode);
        }
        $attributes->addClass($entity_classes);
      }
      // Add (old style, non cleaned) view-mode-{name} to classes.
      elseif ($entity_classes === 'old_view_mode' && $view_mode && !$attributes->hasClass("view-mode-$view_mode")) {
        $attributes->addClass("view-mode-$view_mode");
      }
    }

    // Let other modules know we have rendered.
    $variables['rendered_by_ds'] = TRUE;

    // Let other modules alter the ds array before rendering.
    $context = [
      'entity' => $entity,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'view_mode' => $view_mode,
    ];
    \Drupal::moduleHandler()->alter('ds_pre_render', $variables['content'], $context, $variables);
  }

  // Set the 'row' attributes variable.
  $variables['attributes'] = $attributes;

  // Check if CSS loader should attach Bootstrap CSS when layout detection is enabled.
  if (\Drupal::moduleHandler()->moduleExists('bootstrap_five_layouts_css_loader')) {
    $css_config = \Drupal::config('bootstrap_five_layouts_css_loader.settings');
    $load_method = $css_config->get('load_method') ?: 'page_attachments';
    if ($load_method === 'layout_detection') {
      $library = 'bootstrap_five_layouts_css_loader/toolkit' ;
      if (!isset($variables['#attached']['library'])) {
        $variables['#attached']['library'] = [];
      }
      if (!in_array($library, $variables['#attached']['library'])) {
        $variables['#attached']['library'][] = $library;
      }
    }
  }

  // Create regions/column variables based on the layout settings.
  foreach ($layout->getSetting('regions', []) as $region => $region_settings) {
    $parsed_attributes = _bootstrap_five_layouts_parse_attributes($region_settings['attributes'], $tokens);
    if (!empty($variables['region_attributes'][$region])) {
      $parsed_attributes = NestedArray::mergeDeep($parsed_attributes, $variables['region_attributes'][$region]);
    }
    $region_attributes = new Attribute($parsed_attributes);
    // Add region id if set.
    if (!empty($region_settings['id'])) {
      $region_attributes->setAttribute('id', Html::getUniqueId($region_settings['id']));
    }

    $region_attributes->addClass($region_settings['classes']);

    if (!empty($region_settings['add_region_classes'])) {
      $layout_id = $variables['layout']->id();
      $region_attributes->addClass([Html::cleanCssIdentifier("$layout_id-row"), Html::cleanCssIdentifier("$layout_id-region-$region")]);
    }
   // unset($region_settings['classes']);
    $region_settings['attributes'] = $region_attributes;
    $region_settings['content'] = isset($variables['content'][$region]) && !Element::isEmpty($variables['content'][$region]) ? $variables['content'][$region] : NULL;
    $variables[$region] = $region_settings;
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc