paragraphs_tabs_widget-1.0.0/src/Plugin/Field/FieldWidget/ParagraphsTabWidgetVerticalTabs.php

src/Plugin/Field/FieldWidget/ParagraphsTabWidgetVerticalTabs.php
<?php

namespace Drupal\paragraphs_tabs_widget\Plugin\Field\FieldWidget;

use Drupal\Component\Utility\Html;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\paragraphs\Plugin\Field\FieldWidget\InlineParagraphsWidget;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Paragraphs vertical tab widget.
 *
 * @FieldWidget(
 *   id = "paragraphs_tabs_widget_vertical_tabs",
 *   label = @Translation("Vertical tabs"),
 *   description = @Translation("Displays each paragraph's widget in a vertical tab."),
 *   field_types = {
 *     "entity_reference_revisions"
 *   }
 * )
 */
class ParagraphsTabWidgetVerticalTabs extends InlineParagraphsWidget {

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

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->currentUser = $container->get('current_user');
    return $instance;
  }

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

    // By default, the form element adds a div.ajax-new-content around the
    // newest item to be added - but this breaks vertical tabs because the
    // details elements need to be children (i.e.: not descendants) of the
    // vertical tab element. Remove the wrapper and set a default vertical tab
    // instead.
    $newestDelta = $element['#max_delta'];
    unset($element[$newestDelta]['#prefix']);
    unset($element[$newestDelta]['#suffix']);
    $element['#default_tab'] = $element[$newestDelta]['#id'] ?? '';

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return [
      // Widget settings defined by this module.
      'summary_selector' => '',

      // Collapsing a paragraph inside a vertical tab hides useful controls
      // behind extra clicks, so set defaults under the assumption that a user
      // won't want to collapse paragraphs.
      'edit_mode' => 'open',
    ] + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
    // Delete the "Active tab" form value that the vertical tab widget adds
    // before trying to extract the rest of the form values. This prevents the
    // widget from trying to extract paragraph sub-form data from the tab name
    // (which doesn't work).
    $field_name = $this->fieldDefinition->getName();
    $path = array_merge($form['#parents'], [$field_name]);
    $path[] = implode('__', $path) . '__active_tab';
    $form_state->unsetValue($path);

    return parent::extractFormValues($items, $form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
    // Ask the base widget to render all the elements of the form in the way it
    // normally does get the field name, which will eventually become the
    // #group for all tabs in the widget.
    $widget = parent::formMultipleElements($items, $form, $form_state);
    $groupPrefix = !empty($form['#parents']) ? implode('][', $form["#parents"]) . '][' : '';
    $group = $groupPrefix . $widget['#field_name'];

    // Attach our library and the data it needs to complete its operation.
    $widget['#attached']['library'][] = 'paragraphs_tabs_widget/vertical_tabs';
    $widget['#attached']['drupalSettings']['paragraphs_tabs_widget_vertical_tabs'][$group]['summarySelector']
      = $this->getSetting('summary_selector');
    $widget['#attributes']['data-paragraphs-tabs-widget-group'] = $group;
    $widgetId = Html::getUniqueId($group);
    $widget['#prefix'] = '<div id="' . $widgetId . '" data-paragraphs-tabs-widget-group-wrapper="' . Html::escape($group) . '">';
    $widget['#suffix'] = '</div>';

    // Replace the default way of rendering the widget with a vertical tabs
    // widget.
    unset($widget['#theme']);
    $widget['#type'] = 'vertical_tabs';

    // Loop through each single-element form.
    foreach (Element::children($widget) as $delta) {
      if (is_numeric($delta)) {
        // Transform the single-element form into a details element, with a
        // title and a group so it can be placed into the correct vertical tabs
        // element.
        $widget[$delta]['#type'] = 'details';
        $widget[$delta]['#title'] = $this->getSetting('title') ?: $this->t('Paragraph');
        $widget[$delta]['#group'] = $group;

        // Add a data attribute so the paragraphs_tabs_widget/vertical_tabs
        // library can find the tab.
        $widget[$delta]['#attributes']['data-paragraph-tabs-widget-tab-group'] = $group;

        // The default prefix and suffix define an HTML tag wrapper, which
        // interferes with the core/drupal.vertical-tabs library JavaScript,
        // which requires tabs to be children (i.e.: not descendants) of the
        // vertical tabs widget.
        unset($widget[$delta]['#prefix']);
        unset($widget[$delta]['#suffix']);

        // Hide the paragraph title, since that's already in the tab.
        if (isset($widget[$delta]['top']['paragraph_type_title'])) {
          $widget[$delta]['top']['paragraph_type_title']['#printed'] = TRUE;
        }

        // Temporarily hide the weight element, as it doesn't display properly.
        if (isset($widget[$delta]['_weight'])) {
          $widget[$delta]['_weight']['#printed'] = TRUE;
        }

        // Modify the "Remove" button (and its follow-up "Confirm removal" and
        // "Restore" buttons) for the tab: tell AJAX to replace the whole field
        // wrapper - otherwise its wrapper selector doesn't refer to anything.
        $removeButtonNames = [
          'remove_button',
          'confirm_remove_button',
          'restore_button',
        ];
        foreach ($removeButtonNames as $removeButtonName) {
          if (isset($widget[$delta]['top']['links'][$removeButtonName]['#ajax']['wrapper'])) {
            $widget[$delta]['top']['links'][$removeButtonName]['#ajax']['wrapper'] = $widgetId;
          }
        }
      }
    }

    // Update the "add more" button for better compatibility with vertical tabs:
    // remove the default theme wrappers, remove the default "to field" suffix
    // (which ends up outside the wrapper and therefore at the top of every
    // tab), add an attribute to the add_more button so JavaScript can move it
    // into the vertical tabs menu, and loop through each "add more" button and
    // tell AJAX to replace the whole field wrapper - otherwise its wrapper
    // selector doesn't refer to anything.
    unset($widget['add_more']['#theme_wrappers']);
    unset($widget['add_more']['#suffix']);
    $widget['add_more']['#attributes']['data-paragraphs-tabs-widget-addmore-group'] = $group;
    foreach (Element::children($widget['add_more']) as $addMoreButtonKey) {
      if (isset($widget['add_more'][$addMoreButtonKey]['#ajax']['wrapper'])) {
        $widget['add_more'][$addMoreButtonKey]['#ajax']['wrapper'] = $widgetId;
      }
    }

    return $widget;
  }

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

    // Collapsing a paragraph inside a vertical tab hides useful controls behind
    // extra clicks, so hide controls under the assumption that a user won't
    // want to collapse paragraphs.
    $elements['edit_mode']['#access'] = FALSE;

    // A jQuery selector for an HTML element inside the tab whose value will be
    // used as the tab summary.
    // Warning: This selector will be evaluated by jQuery in the client's
    // browser and therefore has security implications.
    $elements['summary_selector'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Tab summary selector'),
      '#description' => $this->t("A <a href='@jquery_api_selectors'>jQuery selector</a> for an HTML element inside the tab whose value will be used as the tab summary. Warning: This selector will be evaluated by jQuery in the client's browser and therefore has security implications.", [
        '@jquery_api_selectors' => 'https://api.jquery.com/category/selectors/',
      ]),
      '#default_value' => $this->getSetting('summary_selector'),
      '#access' => $this->currentUser->hasPermission('change paragraphs_tabs_widget summary_selector'),
    ];

    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = [];

    // Widget settings inherited from field.widget.settings.paragraphs.
    $summary[] = $this->t('Title: @title', ['@title' => $this->getSetting('title')]);
    $summary[] = $this->t('Plural title: @title_plural', [
      '@title_plural' => $this->getSetting('title_plural'),
    ]);
    switch ($this->getSetting('add_mode')) {
      case 'select':
      default:
        $add_mode = $this->t('Select list');
        break;

      case 'button':
        $add_mode = $this->t('Buttons');
        break;

      case 'dropdown':
        $add_mode = $this->t('Dropdown button');
        break;
    }
    $summary[] = $this->t('Add mode: @add_mode', ['@add_mode' => $add_mode]);
    $summary[] = $this->t('Form display mode: @form_display_mode', [
      '@form_display_mode' => $this->getSetting('form_display_mode'),
    ]);
    if ($this->getDefaultParagraphTypeLabelName() !== NULL) {
      $summary[] = $this->t('Default paragraph type: @default_paragraph_type', [
        '@default_paragraph_type' => $this->getDefaultParagraphTypeLabelName(),
      ]);
    }

    // Widget settings defined by this module.
    if (!empty($this->getSetting('summary_selector'))) {
      $summary[] = $this->t('Tab summary selector: @summary_selector', [
        '@summary_selector' => $this->getSetting('summary_selector'),
      ]);
    }

    return $summary;
  }

}

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

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