'Autocomplete Widgets', 'page callback' => 'autocomplete_widgets_json', 'access callback' => 'autocomplete_widgets_access', 'access arguments' => array(1, 2), 'type' => MENU_CALLBACK, ); return $items; } /** * Implementation of hook_theme(). */ function autocomplete_widgets_theme() { return array( 'autocomplete_widgets' => array('arguments' => 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_form_alter(). * * Because we need to alter the field settings form, this module needs * to be loaded after CCK Text/Number field modules. * See autocomplete_widgets_install(). */ function autocomplete_widgets_form_alter(&$form, $form_state, $form_id) { // Provide additional help for the field settings form. if ($form_id == 'content_field_edit_form' && isset($form['widget'])) { module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.admin'); _autocomplete_widgets_content_field_edit_form_alter($form, $form_state); } } /** * Implementation of hook_widget_info(). */ function autocomplete_widgets_widget_info() { return array( 'autocomplete_widgets_allowvals' => array( 'label' => t('Autocomplete for allowed values list'), 'field types' => array('text', 'number_integer', 'number_decimal', 'number_float'), ), 'autocomplete_widgets_flddata' => array( 'label' => t('Autocomplete for existing field data'), 'field types' => array('text'), ), ); } /** * Implementation of hook_elements(). * * Autocomplete_path is not used by text_widget but other widgets can use it * (see nodereference and userreference). */ function autocomplete_widgets_elements() { return array( 'autocomplete_widgets' => array( '#input' => TRUE, '#columns' => array('value'), '#delta' => 0, '#process' => array('autocomplete_widgets_process'), '#autocomplete_path' => FALSE, ), ); } /** * Implementation of hook_widget_settings(). */ function autocomplete_widgets_widget_settings($op, $widget) { module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.admin'); return _autocomplete_widgets_widget_settings($op, $widget); } /** * Implementation of hook_widget(). */ function autocomplete_widgets_widget(&$form, &$form_state, $field, $items, $delta = 0) { return array( '#type' => 'autocomplete_widgets', '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL, ); } /** * Process an individual textfield autocomplete element. */ function autocomplete_widgets_process($element, $edit, $form_state, $form) { $field = $form['#field_info'][$element['#field_name']]; $field_key = $element['#columns'][0]; $value = NULL; if ($field['widget']['type'] == 'autocomplete_widgets_allowvals') { if (isset($element['#value'][$field_key])) { $keys = array($element['#value'][$field_key]); module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common'); $options = _autocomplete_widgets_get_options($field, '', '', $keys, 1); if (!empty($options)) { $value = current($options); } } } else if ($field['widget']['type'] == 'autocomplete_widgets_flddata') { if (isset($element['#value'][$field_key])) { $value = $element['#value'][$field_key]; } } $element[$field_key] = array( '#type' => 'textfield', '#default_value' => $value, '#autocomplete_path' => 'autocomplete_widgets/'. $element['#type_name'] .'/'. $element['#field_name'], '#size' => !empty($field['widget']['size']) ? $field['widget']['size'] : 60, '#attributes' => array('class' => 'text'), // The following values were set by the content module and need // to be passed down to the nested element. '#title' => $element['#title'], '#description' => $element['#description'], '#required' => $element['#required'], '#field_name' => $element['#field_name'], '#type_name' => $element['#type_name'], '#delta' => $element['#delta'], '#columns' => $element['#columns'], ); $element[$field_key]['#maxlength'] = !empty($field['max_length']) ? $field['max_length'] : NULL; if (empty($element[$field_key]['#element_validate'])) { $element[$field_key]['#element_validate'] = array(); } array_unshift($element[$field_key]['#element_validate'], 'autocomplete_widgets_validate'); $element['_error_element'] = array( '#type' => 'value', '#value' => implode('][', array_merge($element['#parents'], array($field_key))), ); return $element; } /** * Validate a textfield autocomplete element. */ function autocomplete_widgets_validate($element, &$form_state) { $field_name = $element['#field_name']; $type_name = $element['#type_name']; $delta = $element['#delta']; $field = content_fields($field_name, $type_name); $field_key = $element['#columns'][0]; $value = trim($element['#value']); if ($field['widget']['type'] == 'autocomplete_widgets_allowvals') { if ($value !== '') { module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common'); $options = _autocomplete_widgets_get_options($field, $value, 'equals', NULL, 1); if (empty($options)) { form_error($element, t('%name: found no valid option.', array('%name' => $field['widget']['label']))); } else { $value = key($options); } } } // Remove the wrapper layer and set the right element's value. // This will move the nested value at 'field-name-0-value-value' // back to its original location, 'field-name-0-value'. form_set_value($element, $value, $form_state); } /** * Check access to the menu callback of the autocomplete widget. */ function autocomplete_widgets_access($type_name, $field_name) { return user_access('access content') && ($field = content_fields($field_name, $type_name)) && content_access('view', $field) && content_access('edit', $field); } /** * Menu callback; Retrieve a pipe delimited string of autocomplete suggestions. */ function autocomplete_widgets_json($type_name, $field_name, $string = '') { module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common'); $field = content_fields($field_name, $type_name); $match = isset($field['widget']['autocomplete_match']) ? $field['widget']['autocomplete_match'] : 'contains'; $matches = array(); $options = _autocomplete_widgets_get_options($field, $string, $match, NULL, 10); foreach ($options as $key => $value) { // Add a class wrapper for a few required CSS overrides. $matches[$value] = '
'. check_plain($value) .'
'; } drupal_json($matches); } /** * Theme an individual textfield autocomplete element. */ function theme_autocomplete_widgets($element) { return $element['#children']; }