uswds_blb_configuration-1.0.0-beta2/src/Plugin/Layout/UswdsLayout.php

src/Plugin/Layout/UswdsLayout.php
<?php

namespace Drupal\uswds_blb_configuration\Plugin\Layout;

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Layout\Attribute\Layout;
use Drupal\Core\Layout\LayoutDefault;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\uswds_blb_configuration\Ajax\RefreshResponsive;
use Drupal\uswds_blb_configuration\Plugin\Deriver\UswdsLayoutDeriver;
use Drupal\uswds_blb_configuration\ResponsiveTrait;
use Drupal\uswds_blb_configuration\StylesGroup\StylesGroupManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Serializer\Encoder\YamlEncoder;
use Drupal\Core\Render\Markup;

/**
 * A layout from our uswds  layout builder.
 */
#[Layout(
  id: 'uswds_blb_configuration',
  deriver: UswdsLayoutDeriver::class
)]
class UswdsLayout extends LayoutDefault implements ContainerFactoryPluginInterface {

  use ResponsiveTrait;

  /**
   * Config settings.
   *
   * @var string
   */
  const CONFIG = 'uswds_blb_configuration.style_settings';

  /**
   * The private tempstore factory.
   *
   * @var \Drupal\Core\TempStore\PrivateTempStoreFactory
   */
  protected $tempstoreFactory;

  /**
   * The Yaml service.
   *
   * @var \Symfony\Component\Serializer\Encoder\YamlEncoder
   */
  protected $yaml;

  /**
   * The extension list module service.
   *
   * @var \Drupal\Core\Extension\ModuleExtensionList
   */
  protected $extensionListModule;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected ConfigFactoryInterface $configFactory;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The styles group plugin manager.
   *
   * @var \Drupal\uswds_blb_configuration\StylesGroup\StylesGroupManager
   */
  protected $stylesGroupManager;

  /**
   * Constructs a new class instance.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param object $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config factory service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\uswds_blb_configuration\StylesGroup\StylesGroupManager $styles_group_manager
   *   The styles group plugin manager.
   * @param \Drupal\Core\Extension\ModuleExtensionList $extension_list_module
   *   The extension list module service.
   * @param \Drupal\Core\Serialization\Yaml $yaml
   *   Yaml service.
   * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_factory
   *   The private tempstore factory.
   */
  public function __construct(array $configuration, $plugin_id, object $plugin_definition, ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, StylesGroupManager $styles_group_manager, ModuleExtensionList $extension_list_module, YamlEncoder $yaml, PrivateTempStoreFactory $tempstore_factory) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->configFactory = $config_factory;
    $this->entityTypeManager = $entity_type_manager;
    $this->stylesGroupManager = $styles_group_manager;
    $this->extensionListModule = $extension_list_module;
    $this->yaml = $yaml;
    $this->tempstoreFactory = $tempstore_factory;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('config.factory'),
      $container->get('entity_type.manager'),
      $container->get('plugin.manager.uswds_styles_group'),
      $container->get('extension.list.module'),
      $container->get('yaml'),
      $container->get('tempstore.private')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build(array $regions) {
    $build = parent::build($regions);

    // Row classes and attributes.
    $section_classes = [];
    if ($this->configuration['section_classes']) {
      $section_classes = explode(' ', $this->configuration['section_classes']);
      $build['#attributes']['class'] = $section_classes;
    }

    if (!empty($this->configuration['section_attributes'])) {
      $section_attributes = $this->configuration['section_attributes'];
      $build['#attributes'] = NestedArray::mergeDeep($build['#attributes'] ?? [], $section_attributes);
    }

    // The default one col layout class.
    if (count($this->getPluginDefinition()->getRegionNames()) == 1) {
      $config = $this->configFactory->get('uswds_blb_configuration.settings');
      $one_col_layout_class = 'col-12';
      if ($config->get('one_col_layout_class')) {
        $one_col_layout_class = $config->get('one_col_layout_class');
      }
      $this->configuration['layout_regions_classes']['uswds_region_col_1'][] = $one_col_layout_class;
    }

    // Regions classes and attributes.
    if ($this->configuration['regions_classes']) {
      foreach ($this->getPluginDefinition()->getRegionNames() as $region_name) {
        $region_classes = $this->configuration['regions_classes'][$region_name];
        if ($this->configuration['layout_regions_classes'] && isset($this->configuration['layout_regions_classes'][$region_name])) {
          $build[$region_name]['#attributes']['class'] = $this->configuration['layout_regions_classes'][$region_name];
        }
        $build[$region_name]['#attributes']['class'][] = $region_classes;
      }
    }

    if ($this->configuration['regions_attributes']) {
      foreach ($this->getPluginDefinition()->getRegionNames() as $region_name) {
        $region_attributes = $this->configuration['regions_attributes'][$region_name];
        if (!empty($region_attributes)) {
          $build[$region_name]['#attributes'] = NestedArray::mergeDeep($build[$region_name]['#attributes'] ?? [], $region_attributes);
        }
      }
    }

    // Container.
    if ($this->configuration['container']) {
      $theme_wrappers = [
        'uswds_container' => [
          '#attributes' => [
            'class' => [$this->configuration['container']],
          ],
        ],
        'uswds_container_wrapper' => [
          '#attributes' => [
            'class' => [],
          ],
        ],
      ];

      if ($this->configuration['container_wrapper_classes']) {
        $theme_wrappers['uswds_container_wrapper']['#attributes']['class'][] = $this->configuration['container_wrapper_classes'];
      }

      if (!empty($this->configuration['container_wrapper_attributes'])) {
        $wrapper_attributes = $this->configuration['container_wrapper_attributes'];
        $theme_wrappers['uswds_container_wrapper']['#attributes'] = NestedArray::mergeDeep($theme_wrappers['uswds_container_wrapper']['#attributes'] ?? [], $wrapper_attributes);
      }

      $build['#theme_wrappers'] = $theme_wrappers;

      // Build dynamic styles.
      $build = $this->stylesGroupManager->buildStyles(
        $build,
        // storage.
        $this->configuration['container_wrapper']['uswds_blb_configuration'],
        // Theme wrapper that we need to apply styles to it.
        'uswds_container_wrapper'
      );
    }

    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    $default_configuration = parent::defaultConfiguration();

    $regions_classes = $regions_attributes = [];
    foreach ($this->getPluginDefinition()->getRegionNames() as $region_name) {
      $regions_classes[$region_name] = '';
      $regions_attributes[$region_name] = [];
    }

    return $default_configuration + [
      // Container wrapper commonly used on container background and
      // minor styling.
      'container_wrapper_classes' => '',
      'container_wrapper_attributes' => [],
      // Container wrapper.
      'container_wrapper' => [
        'uswds_blb_configuration' => [],
      ],
      // Add background color to container wrapper.
      'container_wrapper_bg_color_class' => '',
      // Add background media to container wrapper.
      'container_wrapper_bg_media' => NULL,
      // Container is the section wrapper.
      // Empty means no container else it reflects container type.
      'container' => '',
      // Section refer to the div that contains row in uswds.
      'section_classes' => '',
      'section_attributes' => [],
      // Region refer to the div that contains Col in uswds "Advanced mode".
      'regions_classes' => $regions_classes,
      'regions_attributes' => $regions_attributes,
      // Array of breakpoints and the value of its option.
      'breakpoints' => [],
      // The region refer to the div that contains Col in uswds.
      'layout_regions_classes' => [],
    ];
  }

  /**
   * Helper function to get section settings show/hide status.
   *
   * @return bool
   *   Section settings status.
   */
  public function sectionSettingsIsHidden() {
    $config = $this->configFactory->get('uswds_blb_configuration.settings');
    $hide_section_settings = FALSE;
    if ($config->get('hide_section_settings')) {
      $hide_section_settings = (bool) $config->get('hide_section_settings');
    }
    return $hide_section_settings;
  }

  /**
   * Helper function to get live preview status.
   *
   * @return bool
   *   Live preview status.
   */
  public function livePreviewIsEnabled() {
    $config = $this->configFactory->get('uswds_blb_configuration.settings');
    $live_preview = FALSE;
    if ($config->get('live_preview')) {
      $live_preview = (bool) $config->get('live_preview');
    }
    return $live_preview;
  }

  /**
   * Helper function to get responsive status.
   *
   * @return bool
   *   responsive status.
   */
  public function responsiveIsEnabled() {
    $config = $this->configFactory->get('uswds_blb_configuration.settings');
    $responsive = FALSE;
    if ($config->get('responsive')) {
      $responsive = (bool) $config->get('responsive');
    }
    return $responsive;
  }

  /**
   * Helper function to get the options of given style name.
   *
   * @param string $name
   *   A config style name like background_color.
   *
   * @return array
   *   Array of key => value of style name options.
   */
  public function getStyleOptions(string $name) {
    $config = $this->configFactory->get('uswds_blb_configuration.settings');
    $config_options = $config->get($name);

    $options = ['_none' => $this->t('N/A')];
    $lines = explode(PHP_EOL, $config_options);
    foreach ($lines as $line) {
      $line = explode('|', $line);
      if ($line && isset($line[0]) && isset($line[1])) {
        $options[$line[0]] = $line[1];
      }
    }

    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildConfigurationForm($form, $form_state);

    // Our main set of tabs.
    $form['ui'] = [
      '#type' => 'container',
      '#weight' => -100,
      '#attributes' => [
        'id' => 'uswds_lb_ui',
      ],
    ];

    $tabs = [
      [
        'machine_name' => 'layout',
        'icon' => 'layout.svg',
        'title' => $this->t('Layout'),
        'active' => TRUE,
      ],
      [
        'machine_name' => 'appearance',
        'icon' => 'appearance.svg',
        'title' => $this->t('Style'),
      ],
      [
        'machine_name' => 'settings',
        'icon' => 'settings.svg',
        'title' => $this->t('Settings'),
      ],
    ];

    // Create our tabs from above.
    $form['ui']['nav_tabs'] = [
      '#type' => 'html_tag',
      '#tag' => 'ul',
      '#attributes' => [
        'class' => 'uswds_nav-tabs',
        'id' => 'uswds_nav-tabs',
        'role' => 'tablist',
      ],
    ];

    $form['ui']['tab_content'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => 'uswds_tab-content',
        'id' => 'uswds_tabContent',
      ],
    ];

    // Create our tab & tab panes.
    foreach ($tabs as $tab) {
      $form['ui']['nav_tabs'][$tab['machine_name']] = [
        '#type' => 'inline_template',
        '#template' => '<li><a data-target="{{ target|clean_class }}" class="{{active}}"><span role="img">{% include icon %}</span><div class="uswds_tooltip" data-placement="bottom" role="tooltip">{{ title }}</div></a></li>',
        '#context' => [
          'title' => $tab['title'],
          'target' => $tab['machine_name'],
          'active' => isset($tab['active']) && $tab['active'] ? 'active' : '',
          'icon' => $this->extensionListModule->getPath('uswds_blb_configuration') . '/images/ui/' . ($tab['icon'] ?: 'default.svg'),
        ],
      ];

      $form['ui']['tab_content'][$tab['machine_name']] = [
        '#type' => 'container',
        '#attributes' => [
          'class' => [
            'uswds_tab-pane',
            'uswds_tab-pane--' . $tab['machine_name'],
            isset($tab['active']) && $tab['active'] == TRUE ? 'active' : '',
          ],
        ],
      ];
    }

    // Get Bootstrap Layout Builder deafult layout options and defaults.
    $uswds_layout_defaults = $this->configFactory->get('uswds_blb_configuration.layout_defaults');

    // Container type defaults.
    $container_type_defaults = $uswds_layout_defaults->get('container_type');

    // Container types.
    $container_types = [];
    if (isset($container_type_defaults['form_options'])) {
      $container_types = $container_type_defaults['form_options'];
    }

    // Container type default value.
    $container_type_default_value = '';
    if (!empty($this->configuration['container'])) {
      $container_type_default_value = $this->configuration['container'];
    }
    else {
      if (isset($container_type_defaults['default_value'])) {
        $container_type_default_value = $container_type_defaults['default_value'];
      }
    }

    // Container type weight.
    $container_type_weight = '';
    if (isset($container_type_defaults['weight'])) {
      $container_type_weight = $container_type_defaults['weight'];
    }

    $form['ui']['tab_content']['layout']['container_type'] = [
      '#type' => 'radios',
      '#title' => $this->t('Container type'),
      '#options' => $container_types,
      '#default_value' => $container_type_default_value,
      '#attributes' => [
        'class' => ['uswds_lb_container_type'],
      ],
      "#weight" => $container_type_weight,
    ];

    // Add icons to the container types.
    foreach ($form['ui']['tab_content']['layout']['container_type']['#options'] as $key => $value) {
      $form['ui']['tab_content']['layout']['container_type']['#options'][$key] = '<span class="input-icon ' . $key . '"></span>' . $value;
    }

    // Remove gutters defaults.
    $remove_gutters_defaults = $uswds_layout_defaults->get('remove_gutters');

    // Gutters types.
    $gutter_types = [];
    if (isset($remove_gutters_defaults['form_options'])) {
      $gutter_types = $remove_gutters_defaults['form_options'];
    }

    // Remove gutters default value.
    $remove_gutters_default_value = 0;
    if (isset($this->configuration['remove_gutters'])) {
      $remove_gutters_default_value = (int) $this->configuration['remove_gutters'];
    }
    else {
      if (isset($remove_gutters_defaults['default_value'])) {
        $remove_gutters_default_value = (int) $remove_gutters_defaults['default_value'];
      }
    }

    // Remove gutters weight.
    $remove_gutters_weight = '';
    if (isset($remove_gutters_defaults['weight'])) {
      $remove_gutters_weight = $remove_gutters_defaults['weight'];
    }

    $form['ui']['tab_content']['layout']['remove_gutters'] = [
      '#type' => 'radios',
      '#title' => $this->t('Gutters'),
      '#options' => $gutter_types,
      '#default_value' => $remove_gutters_default_value,
      '#attributes' => [
        'class' => ['blb_gutter_type'],
      ],
      '#weight' => $remove_gutters_weight,
    ];

    // Add icons to the gutter types.
    foreach ($form['ui']['tab_content']['layout']['remove_gutters']['#options'] as $key => $value) {
      $form['ui']['tab_content']['layout']['remove_gutters']['#options'][$key] = '<span class="input-icon gutter-icon-' . $key . '"></span>' . $value;
    }

    $layout_id = $this->getPluginDefinition()->id();
    $breakpoints = $this->entityTypeManager->getStorage('uswds_breakpoint')
      ->accessCheck(FALSE)
      ->getQuery()
      ->sort('weight', 'ASC')
      ->execute();
    foreach ($breakpoints as $breakpoint_id) {
      $breakpoint = $this->entityTypeManager->getStorage('uswds_breakpoint')
        ->load($breakpoint_id);
      $layout_options = $breakpoint->getLayoutOptions($layout_id);
      if ($layout_options) {
        $default_value = NULL;
        if ($this->configuration['breakpoints'] && isset($this->configuration['breakpoints'][$breakpoint_id])) {
          $default_value = $this->configuration['breakpoints'][$breakpoint_id];
        }
        else {
          $options = $this->entityTypeManager->getStorage('uswds_layout_option')
            ->loadByProperties(['layout_id' => $layout_id]);
          foreach ($options as $layoutOption) {
            if (array_search($breakpoint->id(), $layoutOption->getDefaultBreakpointsIds()) !== FALSE) {
              $default_value = $layoutOption->getStructureId();
            }
          }
        }
        $form['ui']['tab_content']['layout']['breakpoints'][$breakpoint_id] = [
          '#type' => 'radios',
          '#title' => $breakpoint->label(),
          '#options' => $layout_options,
          '#default_value' => $default_value,
          '#validated' => TRUE,
          '#attributes' => [
            'class' => ['uswds_breakpoint_cols'],
          ],
        ];

        // Check if the live preview enabled.
        if ($this->livePreviewIsEnabled()) {
          $form['ui']['tab_content']['layout']['breakpoints'][$breakpoint_id]['#ajax']['callback'] = [
            $this,
            'livePreviewCallback',
          ];
          $form['ui']['tab_content']['layout']['breakpoints'][$breakpoint_id]['#ajax']['event'] = 'click';
          $form['ui']['tab_content']['layout']['breakpoints'][$breakpoint_id]['#ajax']['progress'] = ['type' => 'none'];
        }
      }
    }

    if (isset($form['ui']['tab_content']['layout']['breakpoints'])) {
      // Breakpoints defaults.
      $breakpoints_defaults = $uswds_layout_defaults->get('breakpoints');

      // Breakpoints weight.
      if (isset($breakpoints_defaults['weight'])) {
        $form['ui']['tab_content']['layout']['breakpoints']['#weight'] = $breakpoints_defaults['weight'];
      }
    }

    // Container wrapper styling.
    $form['ui']['tab_content']['appearance'] = $this->stylesGroupManager->buildStylesFormElements($form['ui']['tab_content']['appearance'], $form_state, $this->configuration['container_wrapper']['uswds_blb_configuration'], 'uswds_blb_configuration.sections_styles');

    // Move default admin label input to setting tab.
    $form['ui']['tab_content']['settings']['label'] = $form['label'];
    unset($form['label']);

    // Advanced Settings.
    if (!$this->sectionSettingsIsHidden()) {
      $form['ui']['tab_content']['settings']['container'] = [
        '#type' => 'details',
        '#title' => $this->t('Container Settings'),
        '#open' => FALSE,
      ];

      $form['ui']['tab_content']['settings']['container']['container_wrapper_classes'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Container wrapper classes'),
        '#description' => $this->t('Add classes separated by space. Ex: bg-warning py-5.'),
        '#default_value' => $this->configuration['container_wrapper_classes'],
      ];

      $container_attributes = $this->configuration['container_wrapper_attributes'];
      $form['ui']['tab_content']['settings']['container']['container_wrapper_attributes'] = [
        '#type' => 'textarea',
        '#title' => $this->t('Container wrapper attributes (YAML)'),
        '#default_value' => empty($container_attributes) ? '' : $this->yaml->encode($container_attributes),
        '#attributes' => ['class' => ['blb-auto-size']],
        '#rows' => 1,
        '#element_validate' => [[$this, 'validateYaml']],
      ];

      $form['ui']['tab_content']['settings']['row'] = [
        '#type' => 'details',
        '#title' => $this->t('Row Settings'),
        '#description' => $this->t('Add classes separated by space. Ex: col mb-5 py-3.'),
        '#open' => FALSE,
      ];

      $form['ui']['tab_content']['settings']['row']['section_classes'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Row classes'),
        '#description' => $this->t('Row has "row" class, you can add more classes separated by space. Ex: no-gutters py-3.'),
        '#default_value' => $this->configuration['section_classes'],
      ];

      $row_attributes = $this->configuration['section_attributes'];
      $form['ui']['tab_content']['settings']['row']['section_attributes'] = [
        '#type' => 'textarea',
        '#title' => $this->t('Row attributes (YAML)'),
        '#default_value' => empty($row_attributes) ? '' : $this->yaml->encode($row_attributes),
        '#attributes' => ['class' => ['auto-size']],
        '#rows' => 1,
        '#element_validate' => [[$this, 'validateYaml']],
      ];

      $form['ui']['tab_content']['settings']['regions'] = [
        '#type' => 'details',
        '#title' => $this->t('Columns Settings'),
        '#description' => $this->t('Add classes separated by space. Ex: col mb-5 py-3.'),
        '#open' => FALSE,
      ];

      foreach ($this->getPluginDefinition()->getRegionNames() as $region_name) {
        $form['ui']['tab_content']['settings']['regions'][$region_name . '_classes'] = [
          '#type' => 'textfield',
          '#title' => $this->getPluginDefinition()->getRegionLabels()[$region_name] . ' ' . $this->t('classes'),
          '#default_value' => $this->configuration['regions_classes'][$region_name],
        ];

        $region_attributes = $this->configuration['regions_attributes'][$region_name];
        $form['ui']['tab_content']['settings']['regions'][$region_name . '_attributes'] = [
          '#type' => 'textarea',
          '#title' => $this->getPluginDefinition()->getRegionLabels()[$region_name] . ' ' . $this->t('attributes (YAML)'),
          '#default_value' => empty($region_attributes) ? '' : $this->yaml->encode($region_attributes),
          '#attributes' => ['class' => ['auto-size']],
          '#rows' => 1,
          '#element_validate' => [[$this, 'validateYaml']],
        ];

      }
    }

    // Check if the live preview enabled.
    if ($this->livePreviewIsEnabled()) {
      // Add the ajax live preview to form elements.
      $this->addAjaxLivePreviewToElements($form['ui']['tab_content']);
    }
    // Check if the responsive enabled.
    if ($this->responsiveIsEnabled()) {
      // Attach USWDS Styles base library.
      $form['#attached']['library'][] = 'uswds_blb_configuration/layout_builder_form_style';
    }

    return $form;
  }

  /**
   * Add ajax preview element.
   */
  public function addAjaxLivePreviewToElements(array &$element) {
    $types = [
      'radios',
      'radio',
      'checkbox',
      'textfield',
      'textarea',
      'range',
    ];

    if (!isset($element['#type'])) {
      return;
    }

    if (in_array($element['#type'], $types) && !isset($element['#ajax']) && !isset($element['#disable_live_preview'])) {
      $element['#ajax']['callback'] = [$this, 'livePreviewCallback'];
      $element['#ajax']['event'] = 'change';
      $element['#ajax']['progress'] = ['type' => 'none'];
    }

    if (Element::children($element)) {
      foreach (Element::children($element) as $key) {
        $this->addAjaxLivePreviewToElements($element[$key]);
      }
    }
  }

  /**
   * Live preview callback.
   */
  public function livePreviewCallback(array $form, FormStateInterface $form_state) {
    $form_state->getFormObject()->submitForm($form, $form_state);
    $layout = [
      '#type' => 'layout_builder',
      '#section_storage' => $form_state->getFormObject()->getSectionStorage(),
    ];

    $data = [];
    $tempstore = $this->tempstoreFactory
      ->get('uswds_blb_configuration');
    $data['active_device'] = $tempstore->get('active_device');

    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand('#layout-builder', $layout));
    $response->addCommand(new RefreshResponsive('#layout-builder', NULL, $data));

    return $response;
  }

  /**
   * Returns region class of a breakpoint.
   *
   * @param int $key
   *   The position of region.
   * @param array $breakpoints
   *   The layout active breakpoints.
   *
   * @return array
   *   The region classes of all breakpoints.
   */
  public function getRegionClasses(int $key, array $breakpoints) {
    $classes = [];
    foreach ($breakpoints as $breakpoint_id => $strucutre_id) {
      $breakpoint = $this->entityTypeManager->getStorage('uswds_breakpoint')
        ->load($breakpoint_id);
      $classes[] = $breakpoint->getClassByPosition($key, $strucutre_id);
    }
    return $classes;
  }

  /**
   * Save breakpoints to the configuration.
   *
   * @param array $breakpoints
   *   The layout active breakpoints.
   */
  public function saveBreakpoints(array $breakpoints) {
    $this->configuration['breakpoints'] = $breakpoints;
  }

  /**
   * {@inheritdoc}
   */
  public function validateYaml($element, FormStateInterface $form_state, array $form) {
    $value = $element['#value'];
    try {
      $array_values = $this->yaml->decode($value, 'yaml');

      // Fix Classes as strings.
      if (isset($array_values['class']) && !is_array($array_values['class'])) {
        $array_values['class'] = explode(' ', $array_values['class']);
      }
      $form_state->setValueForElement($element, $this->yaml->encode($array_values, 'yaml'));
    }
    catch (\Exception $exception) {
      $form_state->setError($element, $this->t('Invalid YAML entered for %field', ['%field' => $element['#title']]));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function config() {
    return $this->configFactory->getEditable(static::CONFIG);
  }

  /**
   * Helper function to get SVG Markup.
   *
   * @param string $path
   *   The absolute path to the SVG icon.
   *
   * @return string
   *   The icon markup.
   */
  public function getSvgIconMarkup(string $path) {
    $svg = file_get_contents(DRUPAL_ROOT . '/' . $path);
    $svg = preg_replace(['/<\?xml.*\?>/i', '/<!DOCTYPE((.|\n|\r)*?)">/i'], '', $svg);
    $svg = trim($svg);
    return Markup::create($svg);
  }

  /**
   * Helper function to get the class from the options list.
   *
   * @param string $name
   *   A config style name like background_color.
   * @param int $index
   *   The index of the class at the option list.
   *
   * @return string
   *   The class name or null.
   */
  public function getStyleOptionClassByIndex(string $name, int $index) {
    $class = '';
    $options = $this->getStyleOptions($name);
    $count = 0;
    foreach ($options as $key => $value) {
      if ($count == $index) {
        $class = $key;
        break;
      }
      $count++;
    }

    return $class;
  }

  /**
   * Helper function to get the index of the class at options list.
   *
   * @param string $name
   *   A config style name like background_color.
   * @param string $class
   *   The class name.
   *
   * @return int
   *   The index.
   */
  public function getStyleOptionIndexByClass(string $name, string $class) {
    $index = 0;
    $options = $this->getStyleOptions($name);
    $count = 0;
    foreach ($options as $key => $value) {
      if ($key == $class) {
        $index = $count;
        break;
      }
      $count++;
    }

    return $index;
  }

  /**
   * Helper function to get the options of given style name.
   *
   * @param string $name
   *   A config style name like background_color.
   *
   * @return array
   *   Array of key => value of style name options.
   */
  public function getStyleOptionsCount(string $name) {
    // -1 to drop the _none option from the count.
    $count = count($this->getStyleOptions($name)) - 1;
    return $count;
  }

  /**
   * Helper function to add the classes to the build.
   *
   * @param array $build
   *   The build array.
   * @param array $classes
   *   Array of the classes that we need to assign to build.
   * @param string $theme_wrapper
   *   The theme wrapper if exists.
   *
   * @return array
   *   The build array.
   */
  public function addClassesToBuild(array $build, array $classes, $theme_wrapper = NULL) {
    // Assign the style to element or its theme wrapper if exist.
    if ($theme_wrapper && isset($build['#theme_wrappers'][$theme_wrapper])) {
      $build['#theme_wrappers'][$theme_wrapper]['#attributes']['class'] = array_merge($build['#theme_wrappers'][$theme_wrapper]['#attributes']['class'], $classes);
    }
    elseif (isset($build['#attributes']['class'])) {
      $build['#attributes']['class'] = array_merge($build['#attributes']['class'], $classes);
    }
    else {
      $build['#attributes']['class'] = $classes;
    }
    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
  }

  /**
   * {@inheritdoc}
   */
  public function buildStyleFormElements(array &$form, FormStateInterface $form_state, $storage) {
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitStyleFormElements(array $group_elements) {
  }

}

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

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