better_exposed_filters-8.x-4.x-dev/src/Plugin/better_exposed_filters/filter/Sliders.php
src/Plugin/better_exposed_filters/filter/Sliders.php
<?php namespace Drupal\better_exposed_filters\Plugin\better_exposed_filters\filter; use Drupal\Component\Utility\Html; use Drupal\Core\Form\FormStateInterface; /** * Sliders widget implementation. * * @BetterExposedFiltersFilterWidget( * id = "bef_sliders", * label = @Translation("Sliders"), * ) */ class Sliders extends FilterWidgetBase { // Slider animation options. const ANIMATE_NONE = 0; const ANIMATE_SLOW = 600; const ANIMATE_NORMAL = 400; const ANIMATE_FAST = 200; const ANIMATE_CUSTOM = 'custom'; // Slider orientation options. const ORIENTATION_HORIZONTAL = 'horizontal'; const ORIENTATION_VERTICAL = 'vertical'; /** * {@inheritdoc} */ public function defaultConfiguration(): array { return parent::defaultConfiguration() + [ 'min' => 0, 'max' => 99999, 'step' => 1, 'animate' => self::ANIMATE_NONE, 'animate_ms' => 0, 'orientation' => self::ORIENTATION_HORIZONTAL, ]; } /** * {@inheritdoc} */ public static function isApplicable(mixed $handler = NULL, array $options = []): bool { /** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $handler */ $is_applicable = FALSE; // The date filter handler extends the numeric filter handler, so we have // to exclude it specifically. $is_numeric_filter = is_a($handler, 'Drupal\views\Plugin\views\filter\NumericFilter'); $is_range_filter = is_a($handler, 'Drupal\range\Plugin\views\filter\Range'); $is_date_filter = is_a($handler, 'Drupal\views\Plugin\views\filter\Date'); if (($is_numeric_filter || $is_range_filter) && !$is_date_filter && !$handler->isAGroup()) { $is_applicable = TRUE; } return $is_applicable; } /** * {@inheritdoc} */ public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { /** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $filter */ $filter = $this->handler; $form = parent::buildConfigurationForm($form, $form_state); $form['min'] = [ '#type' => 'number', '#title' => $this->t('Range minimum'), '#default_value' => $this->configuration['min'], '#description' => $this->t('The minimum allowed value for the range slider. It can be positive, negative, or zero and have up to 11 decimal places.'), ]; $form['max'] = [ '#type' => 'number', '#title' => $this->t('Range maximum'), '#default_value' => $this->configuration['max'], '#description' => $this->t('The maximum allowed value for the range slider. It can be positive, negative, or zero and have up to 11 decimal places.'), ]; $form['step'] = [ '#type' => 'number', '#title' => $this->t('Step'), '#default_value' => $this->configuration['step'], '#description' => $this->t('Determines the size or amount of each interval or step the slider takes between the min and max.') . '<br />' . $this->t('The full specified value range of the slider (Range maximum - Range minimum) must be evenly divisible by the step.') . '<br />' . $this->t('The step must be a positive number of up to 5 decimal places.'), '#min' => 0, ]; $form['animate'] = [ '#type' => 'select', '#title' => $this->t('Animation speed'), '#options' => [ self::ANIMATE_NONE => $this->t('None'), self::ANIMATE_SLOW => $this->t('Slow (600 ms)'), self::ANIMATE_NORMAL => $this->t('Normal (400 ms)'), self::ANIMATE_FAST => $this->t('Fast (200 ms)'), self::ANIMATE_CUSTOM => $this->t('Custom'), ], '#default_value' => $this->configuration['animate'], '#description' => $this->t('Whether to slide handle smoothly when user click outside handle on the bar.'), ]; $form['animate_ms'] = [ '#type' => 'number', '#title' => $this->t('Animation speed in milliseconds'), '#default_value' => $this->configuration['animate_ms'], '#description' => $this->t('The number of milliseconds to run the animation (e.g. 1000).'), '#states' => [ 'visible' => [ ':input[name="exposed_form_options[bef][filter][' . $filter->field . '][configuration][animate]"]' => ['value' => self::ANIMATE_CUSTOM], ], ], ]; $form['orientation'] = [ '#type' => 'select', '#title' => $this->t('Orientation'), '#options' => [ self::ORIENTATION_HORIZONTAL => $this->t('Horizontal'), self::ORIENTATION_VERTICAL => $this->t('Vertical'), ], '#default_value' => $this->configuration['orientation'], '#description' => $this->t('The orientation of the range slider.'), ]; return $form; } /** * {@inheritdoc} */ public function validateConfigurationForm(array &$form, FormStateInterface $form_state): void { parent::validateConfigurationForm($form, $form_state); // Max must be > min. $min = $form_state->getValue('min'); $max = $form_state->getValue('max'); if (!empty($min) && $max <= $min) { $form_state->setError($form['max'], $this->t('The slider max value must be greater than the slider min value.')); } // Step must have: // - No more than 5 decimal places. // - Slider range must be evenly divisible by step. $step = $form_state->getValue('step'); if (strlen(substr(strrchr((string) $step, '.'), 1)) > 5) { $form_state->setError($form['step'], $this->t('The slider step option for %name cannot have more than 5 decimal places.')); } // Very small step and a very large range can go beyond the max value of // an int in PHP. Thus, we look for a decimal point when casting the result // to a string. if (strpos((string) ($max - $min) / $step, '.')) { $form_state->setError($form['step'], $this->t('The slider range must be evenly divisible by the step option.')); } } /** * {@inheritdoc} */ public function exposedFormAlter(array &$form, FormStateInterface $form_state): void { $field_id = $this->getExposedFilterFieldId(); parent::exposedFormAlter($form, $form_state); // Attach the JS (@see /js/sliders.js) $form[$field_id]['#attached']['library'][] = 'better_exposed_filters/sliders'; // Set the slider settings. $form[$field_id]['#attached']['drupalSettings']['better_exposed_filters']['slider'] = TRUE; $form[$field_id]['#attached']['drupalSettings']['better_exposed_filters']['slider_options'][$field_id] = [ 'min' => $this->configuration['min'], 'max' => $this->configuration['max'], 'step' => $this->configuration['step'], 'animate' => ($this->configuration['animate'] === self::ANIMATE_CUSTOM) ? $this->configuration['animate_ms'] : $this->configuration['animate'], 'orientation' => $this->configuration['orientation'], 'id' => Html::getUniqueId($field_id), 'dataSelector' => Html::getId($field_id), 'viewId' => $form['#id'], ]; } }