gridstack-8.x-2.5/src/Plugin/Layout/GridStackLayoutBase.php

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

namespace Drupal\gridstack\Plugin\Layout;

use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformStateInterface;
use Drupal\Core\Layout\LayoutDefault;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\gridstack\GridStackDefault;
use Drupal\gridstack\Entity\GridStack;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a GridStack base class for Layout plugins.
 */
abstract class GridStackLayoutBase extends LayoutDefault implements ContainerFactoryPluginInterface, PluginFormInterface {

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * The gridstack manager service.
   *
   * @var \Drupal\gridstack\GridStackManagerInterface
   */
  protected $manager;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = new static(
      $configuration,
      $plugin_id,
      $plugin_definition
    );

    $instance->currentUser = $container->get('current_user');
    $instance->manager = $container->get('gridstack.manager');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'regions' => [],
    ] + GridStackDefault::layoutSettings() + parent::defaultConfiguration();
  }

  /**
   * {@inheritdoc}
   */
  protected function attributeForm(array $settings = [], $context = 'settings') {
    $elements['wrapper'] = [
      '#type'          => 'select',
      '#options'       => GridStackDefault::wrapperOptions(),
      '#title'         => $this->t('Wrapper'),
      '#default_value' => isset($settings['wrapper']) ? trim($settings['wrapper']) : 'div',
    ];

    $wrapper_classes = [];
    $wrapper_class_value = isset($settings['wrapper_classes']) ? trim($settings['wrapper_classes']) : '';
    if ($wrapper_class_value) {
      $wrapper_classes = array_filter(array_map('trim', explode(" ", $wrapper_class_value)));
    }

    $elements['attributes'] = [
      '#type'          => 'textfield',
      '#title'         => $this->t('Attributes'),
      '#description'   => $this->t('Use comma: role|main,data-key|value'),
      '#default_value' => isset($settings['attributes']) ? Xss::filter(trim($settings['attributes'])) : '',
    ];

    $elements['wrapper_classes'] = [
      '#type'          => 'textfield',
      '#title'         => $this->t('Classes'),
      '#description'   => $this->t('Use space: bg-dark text-white'),
      '#default_value' => $wrapper_class_value,
    ];

    $elements['preset_classes'] = [];
    if ($classes = GridStackLayoutTool::classes()) {
      $desc = $context == 'settings' ? $this->t('Use the <b>Main container settings</b> here to affect all regions once if appropriate.') : $this->t('Use the <b>Main container settings</b> to affect all.');
      $elements['preset_classes'] = [
        '#type'        => 'details',
        '#open'        => FALSE,
        '#title'       => $this->t('Preset classes'),
        '#description' => $this->t('Merged with <b>Classes</b> above once saved.') . ' ' . $desc,
        '#attributes'  => ['class' => ['form-wrapper--preset-classes']],
      ];

      $visibilities = ['hidden', 'visible', 'visibility'];
      foreach ($classes as $key => $options) {
        // Hiding the entire container is likely out of questions, skip.
        if ($context == 'settings' && in_array($key, $visibilities)) {
          continue;
        }
        $title = str_replace('_', ' ', $key);
        $value = '';

        // We don't store these, fecthing from wrapper_classes string instead.
        if ($wrapper_classes) {
          $values = array_values($options);
          $values = array_combine($values, $values);
          foreach ($wrapper_classes as $wrapper_class) {
            if (isset($values[$wrapper_class])) {
              $value = $values[$wrapper_class];
              break;
            }
          }
        }

        $elements['preset_classes'][$key] = [
          '#type'          => 'radios',
          '#title'         => $this->t('@title', ['@title' => Unicode::ucfirst($title)]),
          '#options'       => ['' => $this->t('- None -')] + GridStackLayoutTool::options($options),
          '#default_value' => $value,
        ];
      }
    }
    return $elements;
  }

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

    if ($settings = $form_state->getValue('settings')) {
      foreach ($settings as $key => $value) {
        $value = is_string($value) ? trim($value) : $value;
        $this->configuration[$key] = is_array($value) ? array_filter($value) : $value;
      }
    }
    unset($this->configuration['settings'], $this->configuration['preset_classes']);

    $regions = [];
    foreach ($form_state->getValue('regions') as $name => $region) {
      foreach ($region as $key => $value) {
        $value = is_string($value) ? trim($value) : $value;
        $value = is_array($value) ? array_filter($value) : $value;
        $regions[$name][$key] = $value;
        if (empty($value) || $key == 'preset_classes') {
          unset($regions[$name][$key]);
        }
      }
    }
    $this->configuration['regions'] = $regions;
  }

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

    $gridnative = $form_state->getValue(['settings', 'gridnative']);
    $form_state->setValue(['settings', 'gridnative'], (bool) $gridnative);

    $preset_classes = $form_state->getValue(['settings', 'preset_classes']);
    $wrapper_classes = $form_state->getValue(['settings', 'wrapper_classes']);

    $merged = GridStackLayoutTool::mergedClasses($wrapper_classes, $preset_classes);
    $form_state->setValue(['settings', 'wrapper_classes'], $merged);

    foreach ($form_state->getValue('regions') as $name => $region) {
      $wrapper_classes = isset($region['wrapper_classes']) ? $region['wrapper_classes'] : '';
      $preset_classes = isset($region['preset_classes']) ? $region['preset_classes'] : [];

      $merged = GridStackLayoutTool::mergedClasses($wrapper_classes, $preset_classes);
      $form_state->setValue(['regions', $name, 'wrapper_classes'], $merged);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    // This form may be loaded as a subform by Field Layout, Panels, etc.
    // @see https://www.drupal.org/node/2536646
    // @see https://www.drupal.org/node/2798261
    // @see https://www.drupal.org/node/2774077
    // @todo Remove when no more issues with it.
    $form_state2 = $form_state instanceof SubformStateInterface ? $form_state->getCompleteFormState() : $form_state;
    $form        = parent::buildConfigurationForm($form, $form_state);
    $access      = $this->currentUser->hasPermission('administer gridstack');
    $config      = $this->getConfiguration();
    $definition  = $this->getPluginDefinition();
    $regions     = $definition->getRegions();
    $name        = $definition->get('optionset');
    $optionset   = GridStack::loadWithFallback($name);
    $regions_all = $optionset->prepareRegions(FALSE);
    $extras      = $settings = [];
    $framework   = $optionset->getOption('use_framework');

    /** @var \Drupal\field_ui\Form\EntityViewDisplayEditForm $entity_form */
    $entity_form = $form_state2->getFormObject();

    /* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
    if (method_exists($entity_form, 'getEntity') && ($display = $entity_form->getEntity())) {
      $extras = [
        'bundle'      => $display->getTargetBundle(),
        'entity_type' => $display->getTargetEntityTypeId(),
        'view_mode'   => $display->getMode(),
      ];
    }

    if (isset($form['label'])) {
      $name_nice = Unicode::ucfirst($name);
      $form['label']['#attributes']['placeholder'] = $this->t('@name', ['@name' => $name_nice]);
      $form['label']['#wrapper_attributes']['class'][] = 'is-gs-aside';
      $form['label']['#description'] = $this->t('A region has direct contents. A container contains a single, or multiple regions.');
      $default = isset($config['label']) ? $config['label'] : $name_nice;
      $form['label']['#default_value'] = $form_state2->getValue('label', $default);
    }

    $form['regions'] = [
      '#type' => 'container',
      '#tree' => TRUE,
    ];

    foreach ($regions_all as $region => $info) {
      foreach (GridStackDefault::regionSettings() as $key => $value) {
        $default = isset($config['regions'][$region][$key]) ? $config['regions'][$region][$key] : $value;
        $default = $form_state2->getValue(['regions', $region, $key], $default);
        $settings['regions'][$region][$key] = $default;
      }

      $prefix = !array_key_exists($region, $regions) ? 'Region container' : 'Region';

      $form['regions'][$region] = [
        '#type'       => 'details',
        '#title'      => $this->t('@prefix: <em>@label</em>', ['@prefix' => $prefix, '@label' => $info['label']]),
        '#open'       => FALSE,
        '#tree'       => TRUE,
        '#attributes' => ['data-gs-region' => $region],
      ];

      $form['regions'][$region] += $this->attributeForm($settings['regions'][$region], 'regions');
    }

    foreach (GridStackDefault::layoutSettings() as $key => $value) {
      $default = isset($config[$key]) ? $config[$key] : $value;
      $settings[$key] = $form_state2->getValue(['settings', $key], $default);
    }

    $description = '';
    if ($this->manager->getModuleHandler()->moduleExists('gridstack_ui') && $access) {
      $description = $this->t('[<a href=":url" class="is-gs-edit-link">Edit @id</a>]', [
        ':url' => $optionset->toUrl('edit-form')->toString(),
        '@id' => Xss::filter($optionset->label()),
      ]);
    }
    $form['settings'] = [
      '#type'        => 'details',
      '#tree'        => TRUE,
      '#open'        => TRUE,
      '#weight'      => 30,
      '#title'       => $this->t('Main container settings'),
      '#description' => $description,
      '#attributes'  => ['class' => ['is-gs-main-settings']],
    ];

    $form['settings']['skin'] = [
      '#type'          => 'select',
      '#title'         => $this->t('Skin'),
      '#options'       => $this->manager->skinManager()->getSkinOptions(),
      '#empty_option'  => $this->t('- None -'),
      '#description'   => $this->t('Leave empty to disable a skin.'),
      '#default_value' => $settings['skin'],
    ];

    $form['settings'] += $this->attributeForm($settings, 'settings');

    $form['settings']['vm'] = [
      '#type'          => 'select',
      '#title'         => $this->t('Vertical margin'),
      '#options'       => GridStackDefault::breakpoints(),
      '#empty_option'  => $this->t('- None -'),
      '#description'   => $this->t('Useful to avoid overlapping regions due to backgrounds. Leave empty to disable.'),
      '#default_value' => $settings['vm'],
      '#access'        => !empty($framework),
    ];

    $form['settings']['gridnative'] = [
      '#type'          => 'checkbox',
      '#title'         => $this->t('Use native CSS Grid'),
      '#description'   => $this->t('<b>Experimental!</b> Check to replace any js-driven (gridstack, masonry, packery, isotope) layouts with native browser Grid layout. Check out <a href=":url">CSS Grid browser supports</a> relevant to your visitors. Uncheck if any issue.', [':url' => 'https://caniuse.com/#feat=css-grid']),
      '#default_value' => $settings['gridnative'],
      '#access'        => empty($framework),
    ];

    if ($uri = $optionset->getIconUri()) {
      $image = [
        '#theme' => 'image',
        '#uri'   => $uri,
        '#alt'   => $this->t('Thumbnail'),
      ];
      $form['settings']['icon'] = [
        '#theme'      => 'container',
        '#children'   => $this->manager->getRenderer()->render($image),
        '#attributes' => ['class' => ['form-wrapper--icon']],
        '#weight'     => 40,
      ];
    }

    $form['settings']['extras'] = [
      '#type'  => 'hidden',
      '#value' => empty($extras) ? '' : Json::encode($extras),
    ];

    $form['#attached']['library'][] = 'gridstack/admin_layout';
    return $form;
  }

}

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

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