io-8.x-1.x-dev/modules/io_browser/src/IoBrowserAlter.php

modules/io_browser/src/IoBrowserAlter.php
<?php

namespace Drupal\io_browser;

use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\WidgetInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\entity_browser\Entity\EntityBrowser;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides IoBrowserAlter service.
 */
class IoBrowserAlter implements IoBrowserAlterInterface {

  use StringTranslationTrait;

  /**
   * The slick browser.
   *
   * @var \Drupal\io_browser\IoBrowser
   */
  protected $ioBrowser;

  /**
   * Constructs a IoBrowserAlter instance.
   */
  public function __construct(IoBrowserInterface $io_browser) {
    $this->ioBrowser = $io_browser;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('io_browser')
    );
  }

  /**
   * Implements hook_form_alter().
   */
  public function formAlter(&$form, FormStateInterface &$form_state, $form_id) {
    $form['#attached']['library'][] = 'io_browser/form';
    $form['#attributes']['class'][] = 'ib ib--root form form--ib blazy clearfix';
    $form['#prefix'] = '<a id="ib-target" tabindex="-1"></a>';

    // Adds header, and footer wrappers to hold navigations and thumbnails.
    $this->addHeaderFooter($form);

    // "Select entities" button.
    $widget = $this->addWidgetSelectEntities($form);

    // Adds IO Browser library, and helper data attributes or classes.
    $this->addFooterHint($form, $form_state, $widget);

    // Selected items.
    $this->addSelectionDisplay($form);

    // Extracts SB plugin IDs from the form ID. Any better?
    $this->addWidgetClasses($form, $form_id, $widget);
  }

  /**
   * Adds header and footer wrappers to hold navigations and thumbnails.
   */
  private function addHeaderFooter(array &$form) {
    foreach (['header', 'footer', 'counter'] as $key) {
      $form[$key] = [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['ib__aside', 'ib__' . $key],
        ],
        '#weight' => $key == 'header' ? -9 : -8,
      ];

      // Adds Blazy marker for lazyloading selection thumbnails.
      if ($key == 'footer') {
        $form['footer']['#attributes']['data-blazy'] = '';
      }
    }
  }

  /**
   * Adds widget "Select entities" button.
   */
  private function addWidgetSelectEntities(array &$form) {
    $view = FALSE;
    $select_title = $this->t('Select');

    if (isset($form['widget'])) {
      if ($actions = $form['widget']['actions'] ?? []) {
        $actions['#weight'] = -7;
        if (!empty($actions['submit']['#value'])) {
          $select_title = $actions['submit']['#value'];
        }
        $actions['#attributes']['class'][] = 'button-group button-group--select button-group--text';

        $form['header']['actions'] = $actions;
        unset($form['widget']['actions']);
      }

      // Adds relevant classes for the current step identified by active widget.
      $attributes = &$form['#attributes'];
      foreach (Element::children($form['widget']) as $widget) {
        $widget_css = str_replace('_', '-', $widget);
        $attributes['class'][] = 'form--' . $widget_css;
        $attributes['data-dialog'] = $widget_css;

        if ($widget == 'view') {
          $view = TRUE;
          break;
        }
      }
    }
    return ['view' => $view, 'title' => $select_title];
  }

  /**
   * Adds widget Selected items.
   */
  private function addSelectionDisplay(array &$form) {
    if ($selection = $form['selection_display'] ?? []) {
      // Attach Blazy here once to avoid multiple Blazy invocations.
      $form['#attached']['library'][] = 'blazy/dblazy';

      // Must be below .entities-list due to sibling selector.
      if (isset($selection['ajax_commands_handler'])) {
        $selection['ajax_commands_handler']['#weight'] = 201;
      }

      // Wraps self-closed input elements for easy styling, or iconing.
      foreach (['show_selection', 'use_selected'] as $key) {
        if ($input = $selection[$key] ?? []) {
          $access = $input['#access'];

          // Enforces visibility regarless empty or not, we use JS, not AJAX,
          // for faster selections.
          $input['#attributes']['class'][] = $access
            ? 'is-btn-visible' : 'is-btn-hidden';
          $input['#access'] = TRUE;

          // Enforces visibility for dynamic items, and let JS takes care of it.
          if ($key == 'show_selection') {
            IoBrowserUtil::wrapButton($input, $key);
          }
          if ($key == 'use_selected') {
            $input['#weight'] = -9;
            $input['#attributes']['class'][] = 'button--primary';

            $form['header']['actions'][$key] = $input;
            unset($selection[$key]);
          }
        }
      }

      if (isset($selection['selected'])) {
        $selection['selected']['#weight'] = 200;

        // Wraps self-closed input elements for easy styling, or iconing.
        foreach (Element::children($selection['selected']) as $key) {
          if (isset($selection['selected'][$key]['remove_button'])) {
            $remove = &$selection['selected'][$key]['remove_button'];
            IoBrowserUtil::wrapButton($remove, 'remove');
          }
        }
      }

      $form['footer']['selection_display'] = $selection;
      unset($form['selection_display']);
    }
    else {
      $form['#attributes']['class'][] = 'is-no-selection';
    }
  }

  /**
   * Adds widget footer hint.
   */
  private function addFooterHint(array &$form, FormStateInterface $form_state, $widget) {
    $storage = $form_state->getStorage();
    $validators = $storage['entity_browser']['validators'] ?? [];
    $target_type = $validators['entity_type']['type'] ?? '';
    $attributes = &$form['#attributes'];

    // @todo figure out why sometimes not available here?
    $cardinality = $validators['cardinality']['cardinality'] ?? NULL;
    $cardinality = $cardinality ?: ($storage['entity_browser']['widget_context']['cardinality'] ?? NULL);
    $cardinality = $cardinality ?: -1;

    $attributes['data-target-type'] = $target_type;
    $attributes['data-cardinality'] = $cardinality;

    $count = $cardinality == -1 ? 'Unlimited' : $cardinality;
    $text = $this->formatPlural($count, 'One item allowed.', '@count items allowed.');

    if ($cardinality != -1) {
      $text .= ' ' . $this->t('Remove one to select another.');
    }

    $hints[] = $text;

    $hints[] = $this->t('Hit <b>@select</b> button to temporarily store selection. Otherwise lost on changing pages, or tabs.', ['@select' => $widget['title']]);
    if (isset($form['selection_display']['use_selected'])) {
      $hints[] = $this->t('Hit <b>@add</b> to store and add to the page quickly.', ['@add' => $form['selection_display']['use_selected']['#value']]);
    }

    $classes = ['ib__cardinality', 'ib__help', 'visible-help'];
    $form['footer']['cardinality_hint'] = [
      '#theme' => 'item_list',
      '#items' => $hints,
      '#attributes' => ['class' => $classes],
      '#weight' => -9,
    ];

    if (isset($storage['dropzonejs'])) {
      $attributes['class'][] = 'is-ib-dz';
    }

    // Adds empty attributes.
    if (empty($storage['entity_browser']['selected_entities'])) {
      $attributes['class'][] = 'is-ib-empty';
    }
  }

  /**
   * Adds widget classes.
   */
  private function addWidgetClasses(array &$form, $form_id, $widget) {
    $id = str_replace(['entity_browser_', '_form'], '', $form_id);

    // Adds contextual classes based on SB entity browser entity.
    if ($eb = EntityBrowser::load($id)) {
      $attrs = &$form['#attributes'];
      // Modal, iframe, etc.
      $attrs['class'][] = 'form--' . str_replace('_', '-', $eb->getDisplay()->getPluginId());
      $attrs['class'][] = 'form--' . str_replace('_', '-', $eb->getWidgetSelector()->getPluginId());

      // Entity display plugins: io_browser_file, io_browser_media, etc.
      // Has selection_position.
      $selections = $eb->getSelectionDisplay()->getConfiguration() ?: [];

      // Has buttons_position, tabs_position.
      $selectors = $eb->getWidgetSelector()->getConfiguration() ?: [];
      $position = $selections['display_settings']['selection_position'] ?? NULL;

      // @todo empty for file?
      if ($position) {
        // BC for over-bottom replaced with just bottom to avoid complexity.
        if ($position == 'over-bottom') {
          $position = 'bottom';
        }

        $vert = in_array($position, ['left', 'right']);
        $attrs['class'][] = 'form--selection-' . $position;
        $attrs['class'][] = $vert ? 'form--selection-v' : 'form--selection-h';
      }

      if ($tabs = ($selectors['tabs_position'] ?? NULL)) {
        $buttons = $selectors['buttons_position'];
        $tabs_pos = '';

        // Tabs at sidebars within selection display.
        if (($tabs == 'left' && $position == 'left')
          || ($tabs == 'right' && $position == 'right')) {
          $tabs_pos = 'footer';
        }
        // Tabs at header along with navigation buttons/ arrows.
        elseif (($tabs == 'bottom' && $buttons == 'bottom')
          || ($tabs == 'top' && $buttons == 'top')) {
          $tabs_pos = 'header';
        }

        $attrs['data-tabs-pos'] = $tabs_pos;

        // Adds classes to identify the amount of tabs, etc.
        if (isset($widget['view']) && $selector = $form['widget_selector'] ?? []) {
          $count = count(Element::children($selector));
          $attrs['class'][] = $count > 2 ? 'form--tabs-stacked' : 'form--tabs-inline';
        }
      }
    }
  }

  /**
   * Implements hook_form_BASE_FORM_ID_alter().
   */
  public function formViewsUiAddHandlerFormAlter(&$form, FormStateInterface &$form_state, $form_id) {
    $view = $form_state->get('view');

    // Excludes IO Browser filter from not-easily doable style plugins.
    $executable = $view->getExecutable();
    $plugins = ['blazy', 'io_browser', 'html_list'];
    $style = $executable ? $executable->getStyle() : NULL;

    if ($style && !in_array($style->getPluginId(), $plugins)) {
      unset($form['options']['name']['#options']['views.io_browser_switch']);
    }
  }

  /**
   * Implements hook_form_views_exposed_form_alter().
   */
  public function formViewsExposedFormAlter(&$form, FormStateInterface $form_state) {
    if (strpos($form['#id'], 'views-exposed-form-io-browser-media') !== FALSE) {
      if (isset($form['bundle'])) {
        $form['bundle']['#type'] = 'radios';
        $form['bundle']['#weight'] = 120;
        $form['bundle']['#title_display'] = 'hidden';
        $form['bundle']['#attributes']['class'][] = 'ib__radios';

        if (isset($form['bundle']['#options']['All'])) {
          $form['bundle']['#options']['All'] = $this->t('- All -');
        }

        $form['#attributes']['class'][] = 'ib__autosubmit';
        $form['#attached']['library'][] = 'io_browser/autosubmit';
      }
    }
  }

  /**
   * Implements hook_field_widget_third_party_settings_form().
   *
   * Specific to Image with file entity, not provided by EB.
   * This form is loaded at /admin/structure/ENTITY/manage/BUNDLE/form-display.
   * Cases:
   *   - EB File with cardinality 1 or > 1, not -1, via entity_browser_file.
   *   - Media Library via media_library_widget, -1, etc.
   * Those not in cases are loaded via EntityBrowserFieldWidgetDisplay instead.
   */
  public function widgetThirdPartySettingsForm(
    WidgetInterface $plugin,
    FieldDefinitionInterface $field,
    $form_mode,
    $form,
    FormStateInterface $form_state,
  ) {

    $element = [];
    $triggers = $form_state->getTriggeringElement() ?: [];
    $field_name = $triggers['#field_name'] ?? $field->getname();
    $selected = $triggers['#value'] ?? NULL;
    $plugin_id = $plugin->getPluginId();
    $mlw = $plugin_id == 'media_library_widget';

    // @fixme unreliable here, -1 become 1, field_type string while media.
    $cardinality = $field->getFieldStorageDefinition()->getCardinality();
    $definition = [
      'cardinality'      => $cardinality,
      'field_definition' => $field,
      'field_name'       => $field_name,
      'settings'         => $plugin->getThirdPartySettings('io_browser') + IoBrowserDefault::widgetMediaSettings(),
      'target_type'      => $field->getSetting('target_type'),
      'plugin_id_widget' => $plugin_id,
      'view_mode'        => 'io_browser',
    ] + IoBrowserUtil::scopedFormElements();

    // @todo entity_browser_file is not using AJAX, use states instead.
    // entity_browser_file, media_library_widget
    $eb = $plugin->getSetting('entity_browser');
    $disabled = $selected && strpos($selected, 'io_browser') === FALSE;
    $others = $eb && strpos($eb, 'io_browser') === FALSE;

    if (!$mlw) {
      if ($others || $disabled) {
        $element['warning'] = [
          '#prefix' => '<p>',
          '#suffix' => '</p>',
          '#markup' => $this->t('To use the IO Browser form, please hit Update button first whenever changing Entity browser option to any IO Browser.'),
        ];
        return $element;
      }
    }

    $this->ioBrowser->checkFieldDefinitions($definition);
    $this->ioBrowser->buildWigetSettingsForm($element, $definition);

    return $element;
  }

}

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

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