You are here

autocomplete_widgets.module in Autocomplete Widgets for Text and Number Fields 7

Same filename and directory in other branches
  1. 6 autocomplete_widgets.module

Provides autocomplete widgets for Text and Number fields.

File

autocomplete_widgets.module
View source
<?php

/**
 * @file
 * Provides autocomplete widgets for  Text and Number fields.
 */

/**
 * Implementation of hook_menu().
 */
function autocomplete_widgets_menu() {
  $items = array();
  $items['autocomplete_widgets'] = array(
    'title' => 'Autocomplete Widgets',
    'page callback' => 'autocomplete_widgets_json',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_theme().
 */
function autocomplete_widgets_theme() {
  return array(
    'autocomplete_widgets' => array(
      'variables' => array(
        'element' => NULL,
      ),
    ),
  );
}

// /**
//  * Implementation of hook_views_api().
//  */
// function autocomplete_widgets_views_api() {
//   return array(
//     'api' => 3.0,
//     'path' => drupal_get_path('module', 'autocomplete_widgets') . '/views',
//   );
// }

/**
 * Implementation of hook_element_info().
 *
 * Autocomplete_path is not used by text_widget but other widgets can use it.
 */
function autocomplete_widgets_element_info() {
  return array(
    'autocomplete_widgets' => array(
      '#input' => TRUE,
      '#columns' => array(
        'value',
      ),
      '#delta' => 0,
      '#process' => array(
        'autocomplete_widgets_element_process',
        'form_process_autocomplete',
      ),
      '#autocomplete_path' => FALSE,
    ),
  );
}

/**
 * Process an individual textfield autocomplete element.
 */
function autocomplete_widgets_element_process($element, &$form_state, $form) {
  $instance = field_widget_instance($element, $form_state);
  if ($instance['widget']['type'] == 'autocomplete_widgets_allowvals') {
    module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common');
    $label = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $exists);
    $options = _autocomplete_widgets_get_options($instance, $label, 'equals', NULL, 1);
    if ($options) {
      drupal_array_set_nested_value($form_state['values'], $element['#parents'], key($options));
    }
  }
  return $element;
}

/**
 * Implementation of hook_field_widget_info().
 */
function autocomplete_widgets_field_widget_info() {
  return array(
    'autocomplete_widgets_allowvals' => array(
      'label' => t('Autocomplete for allowed values list'),
      'field types' => array(
        'list_text',
        'list_integer',
        'list_decimal',
        'list_float',
      ),
      'settings' => array(
        'size' => 60,
        'autocomplete_match' => 'contains',
        'autocomplete_case' => 1,
      ),
    ),
    'autocomplete_widgets_flddata' => array(
      'label' => t('Autocomplete for existing field data'),
      'field types' => array(
        'text',
      ),
      'settings' => array(
        'size' => 60,
        'autocomplete_match' => 'contains',
        'autocomplete_case' => 1,
      ),
    ),
    'autocomplete_widgets_suggested' => array(
      'label' => t('Autocomplete for predefined suggestions'),
      'field types' => array(
        'text',
      ),
      'settings' => array(
        'size' => 60,
        'autocomplete_match' => 'contains',
        'autocomplete_case' => 1,
      ),
    ),
    'autocomplete_widgets_node_reference' => array(
      'label' => t('Autocomplete for existing field data and some node titles'),
      'field types' => array(
        'text',
      ),
      'settings' => array(
        'size' => 60,
        'autocomplete_match' => 'contains',
        'autocomplete_case' => 1,
      ),
    ),
  );
}

/**
 * Implementation of hook_field_widget_form().
 */
function autocomplete_widgets_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $element['value'] = array(
    '#columns' => $element['#columns'],
    '#field_name' => $element['#field_name'],
    '#field_parents' => $element['#field_parents'],
    '#language' => $element['#language'],
    '#description' => $element['#description'],
    '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
    '#required' => $element['#required'],
    '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
    '#delta' => $delta,
    '#title' => $element['#title'],
    '#size' => $instance['widget']['settings']['size'],
  );
  if (isset($field['settings']['max_length'])) {
    $element['value']['#maxlength'] = $field['settings']['max_length'];
  }
  switch ($instance['widget']['type']) {
    case 'autocomplete_widgets_flddata':
    case 'autocomplete_widgets_suggested':
    case 'autocomplete_widgets_node_reference':
      $element['value'] = array_merge($element['value'], array(
        '#type' => 'textfield',
        '#autocomplete_path' => 'autocomplete_widgets/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $element['#field_name'],
      ));
      break;
    case 'autocomplete_widgets_allowvals':

      // Get the label for key in hidden text field.
      $keys = array(
        $element['value']['#default_value'],
      );
      module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common');
      $options = $keys[0] != '' ? _autocomplete_widgets_get_options($instance, '', '', $keys, 1) : NULL;
      $element['value'] = array_merge($element['value'], array(
        '#type' => 'textfield',
        '#process' => array(
          'autocomplete_widgets_element_process',
          'form_process_autocomplete',
        ),
        '#title' => $element['#title'],
        '#field_name' => $element['#field_name'],
        '#field_parents' => $element['#field_parents'],
        '#description' => $element['#description'],
        '#columns' => $element['#columns'],
        '#autocomplete_path' => 'autocomplete_widgets/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $element['#field_name'],
        '#language' => $element['#language'],
        '#default_value' => isset($options) ? current($options) : '',
        '#required' => $element['#required'],
        '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
        '#delta' => $delta,
        '#file' => drupal_get_path('module', 'autocomplete_widgets') . '/autocomplete_widgets.common.inc',
        '#element_validate' => array(
          '_autocomplete_widgets_validate_allowvals',
        ),
      ));
      break;
  }
  return $element;
}

/**
 * Implementation of hook_field_widget_settings_form().
 */
function autocomplete_widgets_field_widget_settings_form($field, $instance) {
  module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.admin');
  return _autocomplete_widgets_field_widget_settings_form($field, $instance);
}

/**
 * Implements hook_field_formatter_info().
 */
function autocomplete_widgets_field_formatter_info() {
  return array(
    'autocomplete_widgets_nr' => array(
      'label' => t('Autocomplete widget node reference'),
      'description' => t('Displays textfield as a link if there exists an allowed node with that title, otherwise as plain text.'),
      'field types' => array(
        'text',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_view().
 */
function autocomplete_widgets_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $result = array();
  switch ($display['type']) {
    case 'autocomplete_widgets_nr':
      switch ($field['type']) {
        case 'text':
          if (isset($items[0]['value']) && isset($instance['widget']['settings']['allowed_node_types'])) {

            // If there exists a node with that title, display it as a link.
            $query = new EntityFieldQuery();
            $nodes = $query
              ->entityCondition('entity_type', 'node')
              ->entityCondition('bundle', $instance['widget']['settings']['allowed_node_types'], 'IN')
              ->propertyCondition('title', $items[0]['value'])
              ->propertyCondition('status', 1);
            $nodes = $nodes
              ->execute();
            $nid = array();
            if (isset($nodes['node'])) {
              foreach ($nodes['node'] as $key => $obj) {
                $nid[] = $key;

                // If there are more than one nodes having this title we
                // only care about the first one.
                break;
              }
            }
            if (isset($nid[0])) {
              $node = node_load($nid[0]);
              return array(
                array(
                  '#markup' => l($node->title, 'node/' . $node->nid),
                ),
              );
            }

            // If no node found with this title, display name as plain text.
            return array(
              array(
                '#markup' => $items[0]['value'],
              ),
            );
          }
          break;
      }
      break;
  }
  return $result;
}

/**
 * Menu callback; Retrieve the autocomplete suggestions.
 */
function autocomplete_widgets_json($entity_type, $bundle_name, $field_name, $string = '') {
  module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common');
  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
  $match = isset($instance['widget']['settings']['autocomplete_match']) ? $instance['widget']['settings']['autocomplete_match'] : 'contains';
  $matches = array();
  $options = _autocomplete_widgets_get_options($instance, $string, $match, NULL, 10);
  foreach ($options as $key => $label) {

    // Add a class wrapper for a few required CSS overrides.
    $matches[$label] = '<div class="reference-autocomplete">' . check_plain($label) . '</div>';
  }
  drupal_json_output($matches);
}

/**
 * Theme an individual textfield autocomplete element.
 */
function theme_autocomplete_widgets($element) {
  return $element['#children'];
}

/**
* Implements hook_content_migrate_field_alter().
*/
function autocomplete_widgets_content_migrate_field_alter(&$field_value, $instance_value) {
  if ($field_value['type'] == 'text' && $instance_value['widget']['type'] == 'autocomplete_widgets_flddata' && empty($field_value['settings']['max_length'])) {
    $field_value['type'] = 'text';
    $field_value['settings']['max_length'] = 255;
    $field_value['messages'][] = t("Invalid field/widget combination: The field '@field' in the bundle '@bundle' is an unlimited length field using a '@widget' widget, not allowed in D7. The field length will be set to 255.", array(
      '@field' => $field_value['field_name'],
      '@bundle' => $instance_value['bundle'],
      '@widget' => $instance_value['widget']['type'],
    ));
  }
  elseif ($field_value['type'] == 'text' && $instance_value['widget']['type'] == 'autocomplete_widgets_allowvals' && empty($field_value['settings']['max_length'])) {
    $field_value['messages'][] = t("Changed field type: The '@field' field uses a '@widget' widget. The field type will be changed from '@type' to 'list_text'.", array(
      '@type' => $field_value['type'],
      '@field' => $field_value['field_name'],
      '@widget' => $instance_value['widget']['type'],
    ));
    $field_value['type'] = 'list_text';
    $field_value['module'] = 'list';

    // Lists don't have a max_length setting.
    if (isset($field_value['settings']['max_length'])) {
      unset($field_value['settings']['max_length']);
    }
    $allowed_values = array();
    if (!empty($field_value['settings']['allowed_values'])) {
      $allowed_values = content_migrate_extract_allowed_values($field_value['settings']['allowed_values'], $field_value['type']);
    }
    $field_value['settings']['allowed_values'] = $allowed_values;
  }
}