views_faceted_filters_js-0.0.18/src/Plugin/views/style/ViewsFacetedFiltersJsGrid.php

src/Plugin/views/style/ViewsFacetedFiltersJsGrid.php
<?php

namespace Drupal\views_faceted_filters_js\Plugin\views\style;

use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\style\Grid;

/**
 * Grid with Client-Side Faceted Filters style plugin.
 *
 * @ViewsStyle(
 *   id = "views_view_faceted_filters_js_grid",
 *   title = @Translation("Grid, with Client-Side Faceted Filters"),
 *   help = @Translation("Provides a very simple data-attributes based client-side JavaScript Faceted Search capabilities for views."),
 *   theme = "views_view_faceted_filters_js_grid",
 *   display_types = {"normal"}
 * )
 */
class ViewsFacetedFiltersJsGrid extends Grid {

  /**
   * Does the style plugin for itself support to add fields to its output.
   *
   * @var bool
   */
  protected $usesFields = TRUE;

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();

    $options['injection_selector'] = ['default' => '#your-facets-container'];
    $options['injection_method'] = ['default' => 'beforeend'];

    $options['facets_show'] = ['default' => TRUE];
    $options['facets'] = ['default' => []];

    $options['fulltext_search_show'] = ['default' => FALSE];
    $options['fulltext_search_title'] = ['default' => 'Search'];
    $options['fulltext_search_description'] = ['default' => ''];
    $options['fulltext_search_placeholder'] = ['default' => ''];
    $options['fulltext_search_delay'] = ['default' => 500];

    $options['reset_button_show'] = ['default' => TRUE];
    $options['reset_button_label'] = ['default' => 'Reset'];

    $options['results_empty_text'] = ['default' => 'No matching results.'];

    return $options;
  }

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

    // @todo POSTPONED on: https://www.drupal.org/project/drupal/issues/2190333
    // $form['csff'] = [
    // '#type' => 'details',
    // '#title' => t('client-side faceted filters'),
    // '#open' => TRUE,
    // ];.
    $form['injection_selector'] = [
      '#type' => 'textfield',
      // '#group' => 'csff',
      '#title' => $this->t('Injection selector'),
      '#description' => $this->t('Enter a unique CSS (preferrably "#id") selector where to inject the facets in the DOM. Region example: ".region-sidebar-first"'),
      '#size' => '30',
      '#required' => TRUE,
      '#default_value' => $this->options['injection_selector'],
    ];
    $form['injection_method'] = [
      '#type' => 'radios',
      // '#group' => 'csff',
      '#title' => $this->t('Injection method'),
      '#options' => [
        'afterbegin' => $this->t('Prepend'),
        'beforeend' => $this->t('Append (Default)'),
        'beforebegin' => $this->t('Before'),
        'afterend' => $this->t('After'),
        'replace' => $this->t('Replace'),
      ],
      '#required' => TRUE,
      '#default_value' => $this->options['injection_method'],
      '#description' => $this->t('Select how to inject the facets on the selected DOM element.'),
    ];

    // Facets:
    // @todo POSTPONED on: https://www.drupal.org/project/drupal/issues/2190333
    // $form['facets'] = [
    // '#type' => 'details',
    // '#title' => t('Faceted Filters'),
    // '#open' => TRUE,
    // '#group' => 'csff',
    // ];.
    $form['facets_show'] = [
      '#type' => 'checkbox',
      // '#group' => 'facets',
      '#title' => $this->t('Show faceted filters'),
      '#description' => $this->t('Shows as the faceted filters'),
      '#default_value' => $this->options['facets_show'],
    ];

    // To create the complex facets selection table
    // we use a helper method for better readability:
    $this->buildOptionsFormFacetsTable($form, $form_state);

    // Fulltext search:
    // @todo POSTPONED on: https://www.drupal.org/project/drupal/issues/2190333
    // $form['fulltext_search'] = [
    // '#type' => 'details',
    // '#title' => t('Fulltext search'),
    // '#open' => TRUE,
    // '#group' => 'csff',
    // ];.
    $form['fulltext_search_show'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Show fulltext search'),
      // '#group' => 'fulltext_search',
      '#description' => $this->t('Show the fulltext search input field.'),
      '#default_value' => $this->options['fulltext_search_show'],
    ];
    $form['fulltext_search_title'] = [
      '#type' => 'textfield',
      // '#group' => 'fulltext_search',
      '#title' => $this->t('Fulltext search block label'),
      '#description' => $this->t('Label of the fulltext search block.'),
      '#size' => '30',
      '#default_value' => $this->options['fulltext_search_title'],
      '#states' => [
        'visible' => [
          ':input[name="style_options[fulltext_search_show]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    $form['fulltext_search_description'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Fulltext search block description'),
      // '#group' => 'fulltext_search',
      '#description' => $this->t('Description text of the fulltext search block.'),
      '#size' => '30',
      '#default_value' => $this->options['fulltext_search_description'],
      '#states' => [
        'visible' => [
          ':input[name="style_options[fulltext_search_show]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    $form['fulltext_search_placeholder'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Fulltext search placeholder'),
      // '#group' => 'fulltext_search',
      '#description' => $this->t('Placeholder text for the fulltext search input field.'),
      '#size' => '30',
      '#default_value' => $this->options['fulltext_search_placeholder'],
      '#states' => [
        'visible' => [
          ':input[name="style_options[fulltext_search_show]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    $form['fulltext_search_delay'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Fulltext search delay (ms)'),
      // '#group' => 'fulltext_search',
      '#description' => $this->t('The delay in miliseconds, before the search input value is submitted.'),
      '#required' => TRUE,
      '#size' => '5',
      '#default_value' => $this->options['fulltext_search_delay'],
      '#states' => [
        'visible' => [
          ':input[name="style_options[fulltext_search_show]"]' => ['checked' => TRUE],
        ],
      ],
    ];

    // Reset button:
    // @todo POSTPONED on: https://www.drupal.org/project/drupal/issues/2190333
    // $form['reset_button'] = [
    // '#type' => 'details',
    // '#title' => t('Reset button'),
    // '#open' => TRUE,
    // '#group' => 'csff',
    // ];.
    $form['reset_button_show'] = [
      '#type' => 'checkbox',
      // '#group' => 'reset_button',
      '#title' => $this->t('Show reset button'),
      '#description' => $this->t('Displays a reset button.'),
      '#default_value' => $this->options['reset_button_show'],
    ];
    $form['reset_button_title'] = [
      '#type' => 'textfield',
      // '#group' => 'fulltext_search',
      '#title' => $this->t('Reset button block label'),
      '#description' => $this->t('Label of the reset button block.'),
      '#size' => '30',
      '#default_value' => $this->options['reset_button_title'],
      '#states' => [
        'visible' => [
          ':input[name="style_options[reset_button_show]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    $form['reset_button_description'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Reset button block description'),
      // '#group' => 'fulltext_search',
      '#description' => $this->t('Description text of the reset button block.'),
      '#size' => '30',
      '#default_value' => $this->options['reset_button_description'],
      '#states' => [
        'visible' => [
          ':input[name="style_options[reset_button_show]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    $form['reset_button_label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Reset button label'),
      // '#group' => 'reset_button',
      '#description' => $this->t('Label of the reset button.'),
      '#size' => '30',
      '#required' => TRUE,
      '#default_value' => $this->options['reset_button_label'],
      // Only show if reset button is used:
      '#states' => [
        'visible' => [
          ':input[name="style_options[reset_button_show]"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['results_empty_text'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Empty results text'),
      '#description' => $this->t('Text to display when there are no matching results.'),
      '#required' => TRUE,
      '#default_value' => $this->options['results_empty_text'],
    ];
  }

  /**
   * Builds the Options Form Facets Table.
   *
   * @param mixed $form
   *   The form.
   * @param Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  protected function buildOptionsFormFacetsTable(&$form, FormStateInterface $form_state) {
    $facets = $this->sanitizeColumns($this->options['facets']);
    $field_names = $this->displayHandler->getFieldLabels();
    $form['facets'] = [
      '#type' => 'table',
      '#caption' => $this
        ->t('Expose Fields as Client-side Facets:'),
      '#description' => $this->t('Select and configure the fields you want to expose as Client-side facets.'),
      '#header' => [
        $this->t('Field name'),
        $this->t('Expose as facet'),
        $this->t('Facet title'),
        $this->t('Facet description'),
        $this->t('Show result count'),
        $this->t('Sort values by'),
        $this->t('Sort order'),
        $this->t('Multivalue separator'),
        $this->t('Facet weight'),
      ],
      // Does not work as expected, hides the whole form:
      // '#states' => [
      //   'visible' => [
      //     ':input[name="style_options[facets_show]"]' => ['checked' => TRUE],
      //   ],
      // ],
    ];
    foreach ($facets as $field_id => $facet) {
      $form['facets'][$field_id]['name'] = [
        '#type' => 'markup',
        '#markup' => $field_names[$field_id] . ' (' . $field_id . ')',
        '#title' => $this->t('Field name'),
        '#title_display' => 'invisible',
      ];
      $form['facets'][$field_id]['enabled'] = [
        '#type' => 'checkbox',
        '#title' => $this->t('Expose as facet'),
        '#title_display' => 'invisible',
        '#default_value' => $this->options['facets'][$field_id]['enabled'],
      ];
      $form['facets'][$field_id]['title'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Facet title'),
        '#title_display' => 'invisible',
        '#default_value' => $this->options['facets'][$field_id]['title'] ?: '',
        '#states' => [
          'visible' => [
            ':input[name="style_options[facets][' . $field_id . '][enabled]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['facets'][$field_id]['description'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Facet description'),
        '#title_display' => 'invisible',
        '#default_value' => $this->options['facets'][$field_id]['description'] ?: '',
        '#states' => [
          'visible' => [
            ':input[name="style_options[facets][' . $field_id . '][enabled]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['facets'][$field_id]['count_show'] = [
        '#type' => 'checkbox',
        '#title' => $this->t('Show result count'),
        '#title_display' => 'invisible',
        '#default_value' => $this->options['facets'][$field_id]['count_show'] ?? TRUE,
        '#states' => [
          'visible' => [
            ':input[name="style_options[facets][' . $field_id . '][enabled]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['facets'][$field_id]['values_sort'] = [
        '#type' => 'radios',
        // '#group' => 'facets',
        '#title' => $this->t('Sort values by'),
        '#title_display' => 'invisible',
        '#options' => [
          '' => $this->t('None'),
          'value' => $this->t('Value (natural)'),
          'count' => $this->t('Count'),
        ],
        // '#description' => $this->t('Select if / how to sort the facet values.'),
        '#default_value' => $this->options['facets'][$field_id]['values_sort'] ?: '',
        '#states' => [
          'visible' => [
            ':input[name="style_options[facets][' . $field_id . '][enabled]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['facets'][$field_id]['values_sort_direction'] = [
        '#type' => 'radios',
        // '#group' => 'facets',
        '#title' => $this->t('Sort ascending / descending'),
        '#title_display' => 'invisible',
        '#options' => [
          'asc' => $this->t('Ascending'),
          'desc' => $this->t('Descending'),
        ],
        // '#description' => $this->t('Select the sort order.'),
        '#default_value' => $this->options['facets'][$field_id]['values_sort_direction'] ?: 'asc',
        '#states' => [
          'visible' => [
            ':input[name="style_options[facets][' . $field_id . '][enabled]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['facets'][$field_id]['multivalue_separator'] = [
        '#type' => 'textfield',
        // '#group' => 'csff',
        '#title' => $this->t('Multivalue separator'),
        '#title_display' => 'invisible',
        // '#description' => $this->t('Separator for multi-value fields. Do not use a string that is used in regular facets texts or they might be split.'),
        '#size' => '5',
        '#required' => TRUE,
        '#default_value' => $this->options['facets'][$field_id]['multivalue_separator'] ?: ', ',
        '#states' => [
          'visible' => [
            ':input[name="style_options[facets][' . $field_id . '][enabled]"]' => ['checked' => TRUE],
          ],
        ],
      ];
      $form['facets'][$field_id]['weight'] = [
        '#type' => 'select',
        '#title' => $this->t('Facet weight'),
        '#title_display' => 'invisible',
        '#options' => range(0, 500),
        '#default_value' => !empty($this->options['facets'][$field_id]['weight']) ? $this->options['facets'][$field_id]['weight'] : 0,
        '#states' => [
          'visible' => [
            ':input[name="style_options[facets][' . $field_id . '][enabled]"]' => ['checked' => TRUE],
          ],
        ],
      ];
    }
  }

  /**
   * Returns the value for the given facet (=field) id.
   *
   * Returns the value for the given facet (=field) id for
   * the current row to build data attributes.
   *
   * Internally uses tokens as there's currently no better way to retrieve the
   * field values.
   *
   * @param string $facet_id
   *   The facet (=field) id.
   * @param bool $row_index
   *   The current row index.
   *
   * @return string
   *   The facet value for the current row.
   */
  public function getFacetValue(string $facet_id, $row_index) {
    return trim($this->tokenizeValue('{{ ' . $facet_id . ' }}', $row_index));
  }

  /**
   * Copied from Drupal\views\Plugin\views\style\Table::sanitizeColumns()!
   *
   * Normalize a list of columns based upon the fields that are
   * available. This compares the fields stored in the style handler
   * to the list of fields actually in the view, removing fields that
   * have been removed and adding new fields in their own column.
   *
   * - Each field must be in a column.
   * - Each column must be based upon a field, and that field
   *   is somewhere in the column.
   * - Any fields not currently represented must be added.
   * - Columns must be re-ordered to match the fields.
   *
   * @param string[] $columns
   *   An array of all fields; the key is the id of the field and the
   *   value is the id of the column the field should be in.
   * @param array $fields
   *   The fields to use for the columns. If not provided, they will
   *   be requested from the current display. The running render should
   *   send the fields through, as they may be different than what the
   *   display has listed due to access control or other changes.
   *
   * @return array
   *   An array of all the sanitized columns.
   */
  public function sanitizeColumns(array $columns, array $fields = NULL) {
    $sanitized = [];
    if ($fields === NULL) {
      $fields = $this->displayHandler->getOption('fields');
    }

    // Preconfigure the sanitized array so that the order is retained.
    foreach ($fields as $field => $info) {
      // Set to itself so that if it isn't touched, it gets column
      // status automatically.
      $sanitized[$field] = $field;
    }
    foreach ($columns as $field => $column) {
      // first, make sure the field still exists.
      if (!isset($sanitized[$field])) {
        continue;
      }

      // If the field is the column, mark it so, or the column
      // it's set to is a column, that's ok.
      if ($field == $column) {
        $sanitized[$field] = $column;
      }
      // Since we set the field to itself initially, ignoring
      // the condition is ok; the field will get its column
      // status back.
    }

    return $sanitized;
  }

}

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

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