You are here

views_autocomplete_filters.module in Views Autocomplete Filters 7

File

views_autocomplete_filters.module
View source
<?php

/**
 * Implements hook_menu().
 */
function views_autocomplete_filters_menu() {
  $items = array();
  $items['autocomplete_filter/%/%/%/%'] = array(
    'title' => 'Autocomplete Filters',
    'page callback' => 'views_autocomplete_filter',
    'page arguments' => array(
      1,
      2,
      3,
      4,
    ),
    'access callback' => '_views_autocomplete_filters_access_callback',
    'access arguments' => array(
      2,
      3,
    ),
    'file' => 'views_autocomplete_filters.inc',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Access callback of autocomplete menu item.
 *
 * @param string $view_name
 * @param string $display_name
 *
 * @return bool
 */
function _views_autocomplete_filters_access_callback($view_name, $display_name) {
  $view = views_get_view($view_name);
  if (empty($view) || !$view
    ->set_display($display_name)) {

    // No such view or something is wrong with display
    // (no such display, broken handler, etc.)
    return FALSE;
  }
  return $view
    ->access(array(
    $display_name,
  ));
}

/**
 * Implements hook_views_api().
 */
function views_autocomplete_filters_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'views_autocomplete_filters') . '/views',
  );
}

/**
 * Helper function for option_definition method for autocomplete filter handlers.
 * Needed to avoid code duplicates.
 *
 * @see views_autocomplete_filters_handler_filter_string()
 * @see views_autocomplete_filters_handler_filter_combine()
 */
function views_autocomplete_filters_filter_hander_option_definition(&$options) {
  $options['expose']['contains'] += array(
    'autocomplete_filter' => array(
      'default' => 0,
    ),
    'autocomplete_items' => array(
      'default' => 10,
    ),
    'autocomplete_min_chars' => array(
      'default' => 0,
    ),
    'autocomplete_field' => array(
      'default' => '',
    ),
    'autocomplete_raw_suggestion' => array(
      'default' => TRUE,
    ),
    'autocomplete_raw_dropdown' => array(
      'default' => TRUE,
    ),
    'autocomplete_dependent' => array(
      'default' => FALSE,
    ),
  );
}

/**
 * Helper function for expose_form method for autocomplete filter handlers.
 * Needed to avoid code duplicates.
 *
 * @see views_autocomplete_filters_handler_filter_string()
 * @see views_autocomplete_filters_handler_filter_combine()
 */
function views_autocomplete_filters_filter_hander_expose_form(&$form, &$form_state, $filter_handler) {
  $field_options_all = $filter_handler->view->display_handler
    ->get_field_labels();

  // Limit options to fields with the same name.
  foreach ($filter_handler->view->display_handler
    ->get_handlers('field') as $id => $handler) {
    if ($handler->real_field == $filter_handler->real_field) {
      $field_options[$id] = $field_options_all[$id];
    }
  }
  if (empty($field_options)) {
    $field_options[''] = t('Add some fields to view');
  }
  elseif (empty($filter_handler->options['expose']['autocomplete_field']) && !empty($field_options[$filter_handler->options['id']])) {
    $filter_handler->options['expose']['autocomplete_field'] = $filter_handler->options['id'];
  }

  // Build form elements for the right side of the exposed filter form.
  $form['expose'] += array(
    'autocomplete_filter' => array(
      '#type' => 'checkbox',
      '#title' => t('Use Autocomplete'),
      '#default_value' => $filter_handler->options['expose']['autocomplete_filter'],
      '#description' => t('Use Autocomplete for this filter.'),
    ),
    'autocomplete_items' => array(
      '#type' => 'textfield',
      '#title' => t('Maximum number of items in Autocomplete results'),
      '#default_value' => $filter_handler->options['expose']['autocomplete_items'],
      '#description' => t('Enter 0 or empty for no limit.'),
      '#element_validate' => array(
        'element_validate_integer',
      ),
      '#dependency' => array(
        'edit-options-expose-autocomplete-filter' => array(
          TRUE,
        ),
      ),
    ),
    'autocomplete_min_chars' => array(
      '#type' => 'textfield',
      '#title' => t('Minimum number of characters to start filter'),
      '#default_value' => $filter_handler->options['expose']['autocomplete_min_chars'],
      '#element_validate' => array(
        'element_validate_integer',
      ),
      '#dependency' => array(
        'edit-options-expose-autocomplete-filter' => array(
          TRUE,
        ),
      ),
    ),
    'autocomplete_dependent' => array(
      '#type' => 'checkbox',
      '#title' => t('Suggestions depend on other filter fields'),
      '#default_value' => $filter_handler->options['expose']['autocomplete_dependent'],
      '#description' => t('Autocomplete suggestions will be filtered by other filter fields'),
      '#dependency' => array(
        'edit-options-expose-autocomplete-filter' => array(
          TRUE,
        ),
      ),
    ),
    'autocomplete_field' => array(
      '#type' => 'select',
      '#title' => t('Field with autocomplete results'),
      '#default_value' => $filter_handler->options['expose']['autocomplete_field'],
      '#options' => $field_options,
      '#description' => t('Selected field will be used for dropdown results of autocomplete. In most cases it should be the same field you use for filter.'),
      '#dependency' => array(
        'edit-options-expose-autocomplete-filter' => array(
          TRUE,
        ),
      ),
    ),
    'autocomplete_raw_dropdown' => array(
      '#type' => 'checkbox',
      '#title' => t('Unformatted dropdown'),
      '#default_value' => $filter_handler->options['expose']['autocomplete_raw_dropdown'],
      '#description' => t('Use unformatted data from database for dropdown list instead of field formatter result. Value will be printed as plain text.'),
      '#dependency' => array(
        'edit-options-expose-autocomplete-filter' => array(
          TRUE,
        ),
      ),
    ),
    'autocomplete_raw_suggestion' => array(
      '#type' => 'checkbox',
      '#title' => t('Unformatted suggestion'),
      '#default_value' => $filter_handler->options['expose']['autocomplete_raw_suggestion'],
      '#description' => t('The same as above, but for suggestion (text appearing inside textfield when item is selected).'),
      '#dependency' => array(
        'edit-options-expose-autocomplete-filter' => array(
          TRUE,
        ),
      ),
    ),
  );
}

/**
 * Helper function for value_form method for autocomplete filter handlers.
 * Needed to avoid code duplicates.
 *
 * @see views_autocomplete_filters_handler_filter_string()
 * @see views_autocomplete_filters_handler_filter_combine()
 */
function views_autocomplete_filters_filter_hander_value_form(&$form, &$form_state, $filter_handler) {
  if (empty($form_state['exposed']) || empty($filter_handler->options['expose']['autocomplete_filter'])) {

    // It's not an exposed form or autocomplete is not enabled.
    return;
  }
  if (empty($form['value']['#type']) || $form['value']['#type'] !== 'textfield') {

    // Not a textfield.
    return;
  }

  // Add autocomplete path to the exposed textfield.
  $view_args = !empty($filter_handler->view->args) ? implode('||', $filter_handler->view->args) : 0;
  $form['value']['#autocomplete_path'] = 'autocomplete_filter/' . $filter_handler->options['id'] . '/' . $filter_handler->view->name . '/' . $filter_handler->view->current_display . '/' . $view_args;

  // Add JS script with core autocomplete overrides to the end of JS files
  // list to be sure it is added after the "misc/autocomplete.js" file. Also
  // mark the field with special class.
  if (!empty($filter_handler->options['expose']['autocomplete_dependent'])) {
    $file_path = drupal_get_path('module', 'views_autocomplete_filters') . '/js/views-autocomplete-filters-dependent.js';
    drupal_add_js($file_path, array(
      'weight' => 99,
    ));
    $form['value']['#attributes']['class'][] = 'views-ac-dependent-filter';
  }
}

/**
 * Helper function for validate method for autocomplete filter handlers.
 * Needed to avoid code duplicates.
 *
 * @see views_autocomplete_filters_handler_filter_string()
 * @see views_autocomplete_filters_handler_filter_combine()
 */
function views_autocomplete_filters_filter_hander_validate(&$errors, $filter_handler) {

  // Only check if this filter instance is exposed and has the autocomplete box
  // checked.
  if (!empty($filter_handler->options['exposed']) && !empty($filter_handler->options['expose']['autocomplete_filter'])) {

    // Look through the view and find the display that this filter instance is
    // part of.
    foreach ($filter_handler->view->display as $display_id => $display) {
      $display_filters = $display->handler
        ->get_handlers('filter');
      foreach ($display_filters as $filter_id => $filter) {
        if ($filter === $filter_handler) {

          // At this point we know we are looking at the correct display,
          // and we can check the fields.
          // Get the fields from the correct display.
          $display_fields = $display->handler
            ->get_handlers('field');
          $missing_autocomplete_fields = FALSE;

          // Distinct validation per handler type.
          switch ($filter_handler->definition['handler']) {
            case 'views_autocomplete_filters_handler_filter_combine':
            case 'views_autocomplete_filters_handler_filter_search_api_fulltext':
              $field_name = $filter_handler->options['fields'];
              if (empty($field_name)) {
                $missing_autocomplete_fields = TRUE;
              }
              break;
            default:
              $field_name = !empty($filter_handler->options['expose']['autocomplete_field']) ? $filter_handler->options['expose']['autocomplete_field'] : $filter_handler->options['id'];
              if (empty($field_name) || empty($display_fields[$field_name])) {
                $missing_autocomplete_fields = TRUE;
              }
              break;
          }
          if ($missing_autocomplete_fields) {
            $errors[] = t('Field with autocomplete results is not selected for %label filter in %display display.', array(
              '%label' => $filter_handler
                ->ui_name(TRUE),
              '%display' => $display->display_title . ' (' . $display->id . ')',
            ));
          }
        }
      }
    }
  }
}

Functions

Namesort descending Description
views_autocomplete_filters_filter_hander_expose_form Helper function for expose_form method for autocomplete filter handlers. Needed to avoid code duplicates.
views_autocomplete_filters_filter_hander_option_definition Helper function for option_definition method for autocomplete filter handlers. Needed to avoid code duplicates.
views_autocomplete_filters_filter_hander_validate Helper function for validate method for autocomplete filter handlers. Needed to avoid code duplicates.
views_autocomplete_filters_filter_hander_value_form Helper function for value_form method for autocomplete filter handlers. Needed to avoid code duplicates.
views_autocomplete_filters_menu Implements hook_menu().
views_autocomplete_filters_views_api Implements hook_views_api().
_views_autocomplete_filters_access_callback Access callback of autocomplete menu item.