toolshed-8.x-1.x-dev/src/Form/ThemeBreakpointSettingsForm.php

src/Form/ThemeBreakpointSettingsForm.php
<?php

namespace Drupal\toolshed\Form;

use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\breakpoint\BreakpointManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Create configuration form for Toolshed JS events.
 */
class ThemeBreakpointSettingsForm extends ConfigFormBase implements ContainerInjectionInterface {

  /**
   * Service to fetch and manage breakpoints for various themes.
   *
   * @var \Drupal\breakpoint\BreakpointManagerInterface&\Drupal\Component\Plugin\PluginManagerInterface
   */
  protected BreakpointManagerInterface&PluginManagerInterface $bpsManager;

  /**
   * Service handler for managing and loading themes.
   *
   * @var \Drupal\Core\Extension\ThemeHandlerInterface
   */
  protected ThemeHandlerInterface $themeHandler;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    $instance = parent::create($container)
      ->setThemeHandler($container->get('theme_handler'))
      ->setBreakpointManager($container->get('breakpoint.manager'));

    return $instance;
  }

  /**
   * Set the form theme handler service.
   *
   * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
   *   The theme extension handler.
   *
   * @return self
   *   Returns self for method chaining.
   */
  public function setThemeHandler(ThemeHandlerInterface $theme_handler): self {
    $this->themeHandler = $theme_handler;
    return $this;
  }

  /**
   * Set the config form breakpoint manager service.
   *
   * @param \Drupal\breakpoint\BreakpointManagerInterface&\Drupal\Component\Plugin\PluginManagerInterface $breakpoint_manager
   *   The breakpoint manager.
   *
   * @return self
   *   Returns self for method chaining.
   */
  public function setBreakpointManager(BreakpointManagerInterface&PluginManagerInterface $breakpoint_manager): self {
    $this->bpsManager = $breakpoint_manager;
    return $this;
  }

  /**
   * Get the title to use as the form or page title.
   *
   * @param string $theme
   *   Name of the theme to use the title of.
   *
   * @return \Stringable|string
   *   Translatable markup of the form title.
   */
  public static function getFormTitle($theme = NULL): \Stringable|string {
    $themeHandler = \Drupal::service('theme_handler');
    $theme = $theme ?: $themeHandler->getDefault();

    return t('@theme_name Breakpoints', [
      '@theme_name' => $themeHandler->getName($theme),
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'toolshed_theme_breakpoint_settings_form';
  }

  /**
   * {@inheritdoc}
   */
  public function getEditableConfigNames(): array {
    $configNames = [];
    foreach ($this->themeHandler->listInfo() as $info) {
      $configNames[] = 'toolshed.breakpoints.' . $info->getName();
    }

    return $configNames;
  }

  /**
   * Get the available JS Events which are triggered for this media query.
   *
   * The available set of events is limited so that JS event handlers can have
   * a consistent set of event names to watch for. These event names should
   * be reviewed to ensure that they make sense to other developers.
   *
   * @return array
   *   An array that can be used as the select form elements '#options' value.
   */
  public function getAvailableEvents(): array {
    return [
      '' => $this->t('- No alias -'),
      'screenSm' => $this->t('onScreenSm'),
      'screenMd' => $this->t('onScreenMd'),
      'screenLg' => $this->t('onScreenLg'),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $theme = NULL): array {
    if (!isset($theme) || !is_string($theme)) {
      $theme = $this->themeHandler->getDefault();
    }
    $form_state->set('theme', $theme);

    // List the breakpoints settings for the themes.
    $form['breakpoints'] = [
      '#type' => 'table',
      '#empty' => $this->t('There are currently no defined breakpoints for this theme. Define them in the *.breakpoints.yml file for this theme.'),
      '#header' => [
        $this->t('Breakpoint'),
        $this->t('Media query'),
        $this->t('Inverted'),
        $this->t('Alias'),
        $this->t('Sort order'),
        $this->t('Actions'),
      ],
      '#attributes' => ['id' => 'breakpoints-manage-table'],
      '#tabledrag' => [
        'options' => [
          'action' => 'order',
          'group' => 'bp-sort-weight',
          'relationship' => 'sibling',
        ],
      ],
    ];

    // Get existing configurations if they exist.
    $configs = $this->config("toolshed.breakpoints.{$theme}")->get('settings') ?: [];

    // Fetch the correct breakpoints for the current theme.
    $bps = array_filter($this->bpsManager->getDefinitions(), function ($bp) use ($theme) {
      return isset($bp['provider']) && ($bp['provider'] === $theme);
    });

    // Iterate through the currently configured items.
    foreach ($configs as $bpConfig) {
      if (!isset($bps[$bpConfig['name']])) {
        continue;
      }

      $bpId = $bpConfig['name'];
      $form['breakpoints'][$bpId] = [
        '#attributes' => [
          'id' => Html::cleanCssIdentifier("bp-{$bpId}"),
          'class' => ['draggable'],
        ],

        'breakpoint' => ['#plain_text' => $bps[$bpId]['label']],
        'mediaQuery' => ['#plain_text' => $bps[$bpId]['mediaQuery']],
        'inverted' => [
          '#type' => 'checkbox',
          '#default_value' => $bpConfig['inverted'],
        ],
        'event' => [
          '#type' => 'select',
          '#options' => $this->getAvailableEvents(),
          '#default_value' => $bpConfig['event'],
        ],
        'weight' => [
          '#type' => 'number',
          '#value' => $bpConfig['weight'],
          '#attributes' => ['class' => ['bp-sort-weight']],
        ],
        'actions' => [
          '#type' => 'submit',
          '#bp_key' => $bpId,
          '#name' => 'delete_' . Html::cleanCssIdentifier($bpId),
          '#value' => $this->t('Remove'),
          '#attributes' => [
            'class' => ['button', 'button--cancel'],
          ],
          '#submit' => [
            [$this, 'submitRemoveBreakpoint'],
            [$this, 'submitForm'],
          ],
        ],
      ];
    }

    $bpDiff = array_diff_key($bps, $form['breakpoints']);
    if (!empty($bpDiff)) {
      foreach ($bpDiff as $bp => $bpInfo) {
        $bpOpts[$bp] = $bpInfo['label'] . ' -- ' . $bpInfo['mediaQuery'];
      }

      $form['breakpoints']['__add_breakpoint'] = [
        '#attributes' => [
          'id' => "add-new-breapoint",
          'class' => ['draggable'],
        ],

        'breakpoint' => [
          '#type' => 'select',
          '#field_prefix' => $this->t('<strong>Add:</strong>'),
          '#options' => $bpOpts,
          '#wrapper_attributes' => ['colspan' => 2],
        ],
        'inverted' => [
          '#type' => 'checkbox',
          '#default_value' => FALSE,
        ],
        'event' => [
          '#type' => 'select',
          '#options' => $this->getAvailableEvents(),
        ],
        'weight' => [
          '#type' => 'number',
          '#value' => 99,
          '#attributes' => ['class' => ['bp-sort-weight']],
        ],
        'actions' => [
          '#type' => 'submit',
          '#value' => $this->t('Add'),
          '#submit' => [
            [$this, 'submitAddBreakpoint'],
            [$this, 'submitForm'],
          ],
        ],
      ];
    }

    $form['actions'] = [
      '#type' => 'actions',

      'submit' => [
        '#type' => 'submit',
        '#value' => $this->t('Save'),
      ],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $theme = $form_state->get('theme');
    $values = $form_state->getValue('breakpoints');

    // This table row is only for adding new breakpoints, and shouldn't be
    // removed before cleaning the breakpoints for this theme configuration.
    unset($values['__add_breakpoint']);

    $breakpoints = [];
    foreach ($values as $bp => $bpVal) {
      $breakpoints[] = [
        'name' => $bp,
        'event' => $bpVal['event'],
        'inverted' => $bpVal['inverted'],
        'weight' => $bpVal['weight'],
      ];
    }

    // Save the changes to the theme setup.
    $this->config("toolshed.breakpoints.{$theme}")
      ->set('settings', $breakpoints)
      ->save();
  }

  /**
   * Form submit callback to add a breakpoint into the settings.
   *
   * @param array $form
   *   Reference to the complete form structure.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state and submission values for the form.
   */
  public function submitAddBreakpoint(array &$form, FormStateInterface $form_state): void {
    $values = $form_state->getValue('breakpoints');

    $addValues = $values['__add_breakpoint'];
    $values[$addValues['breakpoint']] = [
      'name' => $addValues['breakpoint'],
      'event' => $addValues['event'],
      'inverted' => $addValues['inverted'],
      'weight' => $addValues['weight'],
    ];

    $form_state->setValue('breakpoints', $values);
  }

  /**
   * Form submit callback to remove a breakpoint from the settings.
   *
   * @param array $form
   *   Reference to the complete form structure.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state and submission values for the form.
   */
  public function submitRemoveBreakpoint(array &$form, FormStateInterface $form_state): void {
    $element = $form_state->getTriggeringElement();
    $values = $form_state->getValue('breakpoints');

    if (!empty($element['#bp_key']) && isset($values[$element['#bp_key']])) {
      unset($values[$element['#bp_key']]);
      $form_state->setValue('breakpoints', $values);
    }
  }

}

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

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