lory-8.x-1.x-dev/modules/ui/src/Form/LoryForm.php

modules/ui/src/Form/LoryForm.php
<?php

namespace Drupal\lory_ui\Form;

use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\lory\LoryDefault;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Extends base form for lory instance configuration form.
 */
class LoryForm extends EntityForm {

  /**
   * The lory admin service.
   *
   * @var \Drupal\lory\Form\LoryAdminInterface
   */
  protected $admin;

  /**
   * The lory manager service.
   *
   * @var \Drupal\lory\LoryManagerInterface
   */
  protected $manager;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    $instance = parent::create($container);
    $instance->admin = $container->get('lory.admin');
    $instance->manager = $container->get('lory.manager');
    return $instance;
  }

  /**
   * Returns the lory admin.
   */
  public function admin() {
    return $this->admin;
  }

  /**
   * Returns the lory manager.
   */
  public function manager() {
    return $this->manager;
  }

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

    // Change page title for the duplicate operation.
    if ($this->operation == 'duplicate') {
      $form['#title'] = $this->t('<em>Duplicate lory optionset</em>: @label', ['@label' => $this->entity->label()]);
      $this->entity = $this->entity->createDuplicate();
    }

    // Change page title for the edit operation.
    if ($this->operation == 'edit') {
      $form['#title'] = $this->t('<em>Edit lory optionset</em>: @label', ['@label' => $this->entity->label()]);
    }

    $lory      = $this->entity;
    $tooltip   = ['class' => ['is-tooltip']];
    $options   = $lory->getOptions() ?: [];
    $defaults  = LoryDefault::jsOptionsetSettings();
    $admin_css = $this->manager->configLoad('admin_css', 'blazy.settings');

    $form['#attributes']['class'][] = 'form--lory';
    $form['#attributes']['class'][] = 'form--slick';
    $form['#attributes']['class'][] = 'form--optionset';

    if ($admin_css) {
      $form['#attached']['library'][] = 'blazy/admin';
    }

    $form['label'] = [
      '#type'          => 'textfield',
      '#title'         => $this->t('Label'),
      '#default_value' => $lory->label(),
      '#maxlength'     => 255,
      '#required'      => TRUE,
      '#description'   => $this->t("Label for the Lory optionset."),
      '#attributes'    => $tooltip,
      '#prefix'        => '<div class="form__header form__half form__half--first has-tooltip clearfix">',
    ];

    // Keep the legacy CTools ID, i.e.: name as ID.
    $form['name'] = [
      '#type'          => 'machine_name',
      '#default_value' => $lory->id(),
      '#maxlength'     => EntityTypeInterface::BUNDLE_MAX_LENGTH,
      '#machine_name'  => [
        'source' => ['label'],
        'exists' => '\Drupal\lory\Entity\Lory::load',
      ],
      '#attributes'    => $tooltip,
      '#disabled'      => !$lory->isNew(),
      '#suffix'        => '</div>',
    ];

    $form['group'] = [
      '#type'          => 'select',
      '#title'         => $this->t('Group'),
      '#options'       => [
        'main' => $this->t('Main'),
        'nav'  => $this->t('Nav/ Thumbnail'),
      ],
      '#empty_option'  => $this->t('- None -'),
      '#default_value' => $lory->getGroup(),
      '#description'   => $this->t('Group this optionset to avoid confusion for optionset selections. Leave empty to make it available for all.'),
      '#access'        => $lory->id() != 'default',
      '#attributes'    => $tooltip,
      '#prefix'        => '<div class="form__header form__half form__half--last has-tooltip clearfix">',
    ];

    $form['optimized'] = [
      '#type'          => 'checkbox',
      '#title'         => $this->t('Optimized'),
      '#default_value' => $lory->optimized(),
      '#description'   => $this->t('Check to optimize the stored options. Anything similar to defaults will not be stored, except those required by sub-modules and theme_lory(). Like you hand-code/ cherry-pick the needed options, and are smart enough to not repeat defaults, and free up memory. The rest are taken care of by JS. Uncheck only if theme_lory() can not satisfy the needs, and more hand-coded preprocess is needed which is less likely in most cases.'),
      '#access'        => $lory->id() != 'default',
      '#attributes'    => $tooltip,
      '#wrapper_attributes' => ['class' => ['form-item--tooltip-wide']],
      '#suffix'        => '</div>',
    ];

    // Main JS options.
    $form['options'] = [
      '#type'        => 'container',
      '#tree'        => TRUE,
      '#open'        => TRUE,
      '#collapsed'   => FALSE,
      '#attributes'  => ['class' => ['details--settings', 'has-tooltip']],
      '#description' => $this->t('Lory is a touch enabled minimalistic slider written in vanilla JavaScript. Non-core library features are experimental, not battle-tested, yet. Use them at your own risk!'),
    ];

    $definition['settings'] = $options;
    $definition['defaults'] = $defaults;
    $this->optionsetForm($form['options'], $definition);

    if ($admin_css) {
      $form['optimized']['#field_suffix'] = '&nbsp;';
      $form['optimized']['#title_display'] = 'before';
    }

    $excludes = ['container', 'details', 'item', 'hidden', 'submit'];
    foreach ($defaults as $name => $default) {
      if (!isset($form['options'][$name])) {
        continue;
      }
      if ($admin_css) {
        if ($form['options'][$name]['#type'] == 'checkbox' && $form['options'][$name]['#type'] != 'checkboxes') {
          $form['options'][$name]['#field_suffix'] = '&nbsp;';
          $form['options'][$name]['#title_display'] = 'before';
        }
        elseif ($form['options'][$name]['#type'] == 'checkboxes' && !empty($form['options'][$name]['#options'])) {
          foreach ($form['options'][$name]['#options'] as $i => $option) {
            $form['options'][$name][$i]['#field_suffix'] = '&nbsp;';
            $form['options'][$name][$i]['#title_display'] = 'before';
          }
        }
      }

      if (in_array($form['options'][$name]['#type'], $excludes) || !isset($form['options'][$name])) {
        continue;
      }
      if (!isset($form['options'][$name]['#default_value'])) {
        $form['options'][$name]['#default_value'] = (NULL !== $lory->getOption($name)) ? $lory->getOption($name) : $default;
      }
    }

    return $form;
  }

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

    // Optimized if so configured.
    $lory    = $this->entity;
    $default = $lory->id() == 'default';
    $options = $form_state->getValue('options');

    // Cast the values.
    $this->typecastOptionset($options);

    if (!$default && !$form_state->isValueEmpty('optimized')) {
      $defaults = $lory::defaultSettings();

      $options = array_diff_assoc($options, $defaults);
    }

    $lory->setOptions($options, FALSE);
  }

  /**
   * Overrides Drupal\Core\Entity\EntityFormController::save().
   */
  public function save(array $form, FormStateInterface $form_state) {
    parent::save($form, $form_state);
    $lory = $this->entity;

    // Prevent leading and trailing spaces in lory names.
    $lory->set('label', trim($lory->label()));
    $lory->set('id', $lory->id());

    $status        = $lory->save();
    $label         = $lory->label();
    $edit_link     = $lory->toLink($this->t('Edit'), 'edit-form')->toString();
    $config_prefix = $lory->getEntityType()->getConfigPrefix();
    $message       = ['@config_prefix' => $config_prefix, '%label' => $label];

    $notice = [
      '@config_prefix' => $config_prefix,
      '%label' => $label,
      'link' => $edit_link,
    ];

    if ($status == SAVED_UPDATED) {
      // If we edited an existing entity.
      // @todo #2278383.
      $this->messenger()->addMessage($this->t('@config_prefix %label has been updated.', $message));
      $this->logger('lory')->notice('@config_prefix %label has been updated.', $notice);
    }
    else {
      // If we created a new entity.
      $this->messenger()->addMessage($this->t('@config_prefix %label has been added.', $message));
      $this->logger('lory')->notice('@config_prefix %label has been added.', $notice);
    }

    $form_state->setRedirectUrl($lory->toUrl('collection'));
  }

  /**
   * Returns the typecast values.
   *
   * @param array $settings
   *   An array of Optionset settings.
   */
  public function typecastOptionset(array &$settings = []) {
    if (empty($settings)) {
      return;
    }

    $lory     = $this->entity;
    $defaults = $lory::defaultSettings();

    foreach ($defaults as $name => $value) {
      if (isset($settings[$name])) {
        // Seems double is ignored, and causes a missing schema, unlike float.
        $type = gettype($defaults[$name]);
        $type = $type == 'double' ? 'float' : $type;

        settype($settings[$name], $type);
      }
    }
  }

  /**
   * Returns the closing ending form elements.
   */
  public function optionsetForm(array &$form, $definition = []) {
    $settings     = isset($definition['settings']) ? $definition['settings'] : [];
    $defaults     = isset($definition['defaults']) ? $definition['defaults'] : [];
    $descriptions = $this->getDescriptions();

    foreach ($defaults as $key => $value) {
      $type = gettype($value);
      $form_type = $type == 'boolean' ? 'checkbox' : 'textfield';

      if (in_array($key, ['ease'])) {
        $form_type = 'select';
      }

      // @todo: Enable when ready.
      if (in_array($key, ['autoWidth', 'vertical'])) {
        $form_type = 'hidden';
      }

      $title = $key;

      $form[$key] = [
        '#type'          => $form_type,
        '#title'         => $this->t('@title', ['@title' => $title]),
        '#default_value' => isset($settings[$key]) ? $settings[$key] : $value,
        '#weight'        => 100,
        '#description'   => isset($descriptions[$key]) ? $descriptions[$key] : '',
      ];

      switch ($key) {
        case 'arrowDown':
          if (!function_exists('jumper_help')) {
            $form[$key]['#disabled'] = TRUE;
          }
          break;

        case 'ease':
          $form[$key]['#options'] = $this->getCssEasingOptions();
          break;

        case 'rewindSpeed':
        case 'slideSpeed':
        case 'snapBackSpeed':
          $form[$key]['#field_suffix'] = $this->t('<abbr title="Millisecond">ms</abbr>');
          break;

        default:
          break;
      }
    }
  }

  /**
   * Returns default classes.
   */
  public function getDescriptions() {
    $features = $this->manager->assetManager()->getAssets()['features'];
    $descriptions = [];

    foreach ($features as $key => $feature) {
      $hidden = isset($feature['type']) && $feature['type'] == 'hidden';
      if ($hidden) {
        continue;
      }

      if (!isset($features[$key]['description'])) {
        continue;
      }

      $option = isset($feature['name']) ? $feature['name'] : $key;
      $descriptions[$option] = $features[$key]['description'];
    }

    return [
      'adaptiveHeight'    => $this->t('Enable adaptive height for SINGLE slide horizontal carousels.'),
      'draggable'         => $this->t('Use dragging and touch swiping.'),
      'enableMouseEvents' => $this->t('Enabled mouse events aka desktop draggable.'),
      'ease'              => $this->t('Cubic bezier easing functions: http://easings.net/de.'),
      'focusOnSelect'     => $this->t('Enable focus on selected element (click). The slide will change when clicked.'),
      'infinite'          => $this->t('Like carousel, works with multiple slides. (do not combine with rewind). The number of slides to be shown per slide. To have responsive displays, use comma-separated key:value (<strong>viewport : visible slides amount</strong>) pairs, e.g.: <br /><strong>210:1, 767:3, 1023:5</strong> <br />which means 3 items per slide for window greater than 767, etc. At below 767, it will show 1. This is mobile first, or min-width, which require explicit min-width viewport. Works best with odd numbers, Width = Fixed grid, and centerMode.'),
      'randomize'         => $this->t('Randomize slide orders, useful to rotate ads/product displays within cached pages.'),
      'rewind'            => $this->t('If slider reached the last slide, with next click the slider goes back to the startindex. (do not combine with infinite).'),
      'rewindSpeed'       => $this->t('Time in milliseconds for the animation of the rewind after the last slide.'),
      'slideSpeed'        => $this->t('Time in milliseconds for the animation of a valid slide attempt.'),
      'snapBackSpeed'     => $this->t('Time for the snapBack of the slider if the slide attempt was not valid.'),
      'initialSlide'      => $this->t('Index of the starting slide (zero-based).'),
      'slidesToScroll'    => $this->t('Slides scrolled at once.'),
      'autoWidth'         => $this->t('WIP! Variable width. (NOT WORKING YET!)'),
      'width'             => $this->t('Defines width to control individual slide, or slide container width as needed in the format: <strong>WIDTHxHEIGHT</strong>. This is a rare case, used to define slide container, such as 3d container. Do not do this unless supported by the provided 3d skins/effect. You can also define this via CSS to have a better control with media queries, and leave it empty here.'),
    ] + $descriptions;
  }

  /**
   * List of available CSS easing methods.
   *
   * @return array
   *   An array of CSS easings for select options, or all for the mappings.
   *
   * @see https://github.com/kenwheeler/slick/issues/118
   * @see http://matthewlein.com/ceaser/
   * @see http://www.w3.org/TR/css3-transitions/
   */
  public function getCssEasingOptions() {
    return [
      // Defaults/ Native.
      'ease'     => 'ease',
      'linear'   => 'linear',
      'ease-in'  => 'ease-in',
      'ease-out' => 'ease-out',
      'swing'    => 'swing|ease-in-out',

      // Penner Equations (approximated).
      'cubic-bezier(0.550, 0.085, 0.680, 0.530)'  => 'easeInQuad',
      'cubic-bezier(0.550, 0.055, 0.675, 0.190)'  => 'easeInCubic',
      'cubic-bezier(0.895, 0.030, 0.685, 0.220)'  => 'easeInQuart',
      'cubic-bezier(0.755, 0.050, 0.855, 0.060)'  => 'easeInQuint',
      'cubic-bezier(0.470, 0.000, 0.745, 0.715)'  => 'easeInSine',
      'cubic-bezier(0.950, 0.050, 0.795, 0.035)'  => 'easeInExpo',
      'cubic-bezier(0.600, 0.040, 0.980, 0.335)'  => 'easeInCirc',
      'cubic-bezier(0.600, -0.280, 0.735, 0.045)' => 'easeInBack',
      'cubic-bezier(0.250, 0.460, 0.450, 0.940)'  => 'easeOutQuad',
      'cubic-bezier(0.215, 0.610, 0.355, 1.000)'  => 'easeOutCubic',
      'cubic-bezier(0.165, 0.840, 0.440, 1.000)'  => 'easeOutQuart',
      'cubic-bezier(0.230, 1.000, 0.320, 1.000)'  => 'easeOutQuint',
      'cubic-bezier(0.390, 0.575, 0.565, 1.000)'  => 'easeOutSine',
      'cubic-bezier(0.190, 1.000, 0.220, 1.000)'  => 'easeOutExpo',
      'cubic-bezier(0.075, 0.820, 0.165, 1.000)'  => 'easeOutCirc',
      'cubic-bezier(0.175, 0.885, 0.320, 1.275)'  => 'easeOutBack',
      'cubic-bezier(0.455, 0.030, 0.515, 0.955)'  => 'easeInOutQuad',
      'cubic-bezier(0.645, 0.045, 0.355, 1.000)'  => 'easeInOutCubic',
      'cubic-bezier(0.770, 0.000, 0.175, 1.000)'  => 'easeInOutQuart',
      'cubic-bezier(0.860, 0.000, 0.070, 1.000)'  => 'easeInOutQuint',
      'cubic-bezier(0.445, 0.050, 0.550, 0.950)'  => 'easeInOutSine',
      'cubic-bezier(1.000, 0.000, 0.000, 1.000)'  => 'easeInOutExpo',
      'cubic-bezier(0.785, 0.135, 0.150, 0.860)'  => 'easeInOutCirc',
      'cubic-bezier(0.680, -0.550, 0.265, 1.550)' => 'easeInOutBack',
    ];
  }

}

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

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