diff --git a/autocomplete_widgets.admin.inc b/autocomplete_widgets.admin.inc index 23af9ce..a5488d9 100755 --- a/autocomplete_widgets.admin.inc +++ b/autocomplete_widgets.admin.inc @@ -90,7 +90,7 @@ function _autocomplete_widgets_field_widget_settings_form($field, $instance) { $settings['suggested_values'] = !isset($settings['suggested_values']) ? '' : $settings['suggested_values']; $form['suggested_values'] = array( '#type' => 'textarea', - '#title' => t('Suggeset values list'), + '#title' => t('Suggested values list'), '#default_value' => $settings['suggested_values'], '#rows' => 10, '#description' => t('Autocomplete requests will only respond with suggestions from this list. If a user enters a value not on this list, it will not be added to the autocomplete options in the future. Enter one suggestion per line.'), @@ -113,6 +113,18 @@ function _autocomplete_widgets_field_widget_settings_form($field, $instance) { ); } - return $form; + $settings['order'] = !isset($settings['order']) ? 'ASC' : $settings['order']; + $form['order'] = array( + '#type' => 'select', + '#title' => t('Order'), + '#options' => array( + 'ASC' => t('A to Z'), + 'DESC' => t('Z to A'), + ), + '#empty_option' => t('Don\'t Sort'), + '#default_value' => $settings['order'], + '#description' => t('Choose in which order should autocomplete suggestions be displayed.'), + ); + return $form; } diff --git a/autocomplete_widgets.common.inc b/autocomplete_widgets.common.inc index ebe246d..0008ace 100755 --- a/autocomplete_widgets.common.inc +++ b/autocomplete_widgets.common.inc @@ -8,12 +8,12 @@ /** * Fetch an array of options for the given widget. * - * @param $field - * The field description. + * @param $instance + * A structured array describing the field instance. * @param $string * Optional string to filter values on (used by autocomplete). * @param $match - * Operator to match filtered name against, can be any of: + * Operator to match filtered name against. Can be any of: * 'contains', 'equals', 'starts_with' * @param $keys * Optional keys to lookup (the $string and $match arguments will be @@ -28,30 +28,31 @@ * ... * ) */ -function _autocomplete_widgets_get_options($field, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { +function _autocomplete_widgets_get_options($instance, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { static $results = array(); // Create unique id for static cache. if (!isset($keys) || !is_array($keys)) { $keys = array(); } - $cid = $field['field_name'] .':'. $match .':'. ($string !== '' ? $string : implode('-', $keys)) .':'. $limit; + $cid = $instance['field_name'] .':'. $match .':'. ($string !== '' ? $string : implode('-', $keys)) . ':' . $limit; if (!isset($results[$cid])) { - if ($field['widget']['type'] == 'autocomplete_widgets_allowvals') { - $results[$cid] = _autocomplete_widgets_get_options_allowvals($field, $string, $match, $keys, $limit); - } - else if ($field['widget']['type'] == 'autocomplete_widgets_flddata') { - $results[$cid] = _autocomplete_widgets_get_options_flddata($field, $string, $match, $keys, $limit); - } - else if ($field['widget']['type'] == 'autocomplete_widgets_suggested') { - $results[$cid] = _autocomplete_widgets_get_options_suggested($field, $string, $match, $keys, $limit); - } - else if ($field['widget']['type'] == 'autocomplete_widgets_node_reference') { - $results[$cid] = _autocomplete_widgets_get_options_node_reference($field, $string, $match, $keys, $limit); - } - else { - $results[$cid] = array(); + switch ($instance['widget']['type']) { + case 'autocomplete_widgets_allowvals': + $results[$cid] = _autocomplete_widgets_get_options_allowvals($instance, $string, $match, $keys, $limit); + break; + case 'autocomplete_widgets_flddata': + $results[$cid] = _autocomplete_widgets_get_options_flddata($instance, $string, $match, $keys, $limit); + break; + case 'autocomplete_widgets_suggested': + $results[$cid] = _autocomplete_widgets_get_options_suggested($instance, $string, $match, $keys, $limit); + break; + case 'autocomplete_widgets_node_reference': + $results[$cid] = _autocomplete_widgets_get_options_node_reference($instance, $string, $match, $keys, $limit); + break; + default: + $results[$cid] = array(); } } @@ -63,15 +64,13 @@ function _autocomplete_widgets_get_options($field, $string = '', $match = 'conta * * Options are retrieved from the allowed values defined for the field. */ -function _autocomplete_widgets_get_options_allowvals($field, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { - - $field_name = $field['field_name']; - $allowed_values = list_allowed_values(field_info_field($field_name)); +function _autocomplete_widgets_get_options_allowvals($instance, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { + $allowed_values = list_allowed_values(field_info_field($instance['field_name'])); $limit = (!isset($limit) || !is_numeric($limit)) ? count($allowed_values) : $limit; - $case_sensitive = $field['widget']['settings']['autocomplete_case']; - $filter_xss = !empty($field['widget']['settings']['autocomplete_xss']); + $case_sensitive = $instance['widget']['settings']['autocomplete_case']; + $filter_xss = !empty($instance['widget']['settings']['autocomplete_xss']); $options = array(); - $count = 0; + $count = 0; //@todo: cant the count var be replaced with a call to count()? foreach ($allowed_values as $key => $value) { if ($filter_xss) { @@ -107,6 +106,9 @@ function _autocomplete_widgets_get_options_allowvals($field, $string = '', $matc break; } } + + _autocomplete_widgets_sort_options($options, $instance); + return $options; } @@ -115,22 +117,24 @@ function _autocomplete_widgets_get_options_allowvals($field, $string = '', $matc * * Options are retrieved from existing values for the field. */ -function _autocomplete_widgets_get_options_flddata($field, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { - $field_name = $field['field_name']; - $table = 'field_data_' . $field_name; - $column = $field_name . '_value'; +function _autocomplete_widgets_get_options_flddata($instance, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { + $table = 'field_data_' . $instance['field_name']; + $column = $instance['field_name'] . '_value'; + $order = isset($instance['widget']['settings']['order']) ? $instance['widget']['settings']['order'] : ''; $select = db_select($table, 'fd'); $select->addField('fd', $column); - if (!empty($field['widget']['i18n_flddata'])) { + if (!empty($instance['widget']['i18n_flddata'])) { // Adding a join with the node table allows the i18n rewrite the query // to filter values from node for the proper language. $select->join('node', 'n', 'vid = n.vid'); } if ($string !== '') { - $case_sensitive = empty($field['widget']['autocomplete_case']); + //@todo: there is no need to check case sensitivty of $column. + $case_sensitive = empty($instance['widget']['autocomplete_case']); + $col = $case_sensitive ? $column : strtolower($column); $val = $case_sensitive ? $string : strtolower($string); @@ -153,6 +157,9 @@ function _autocomplete_widgets_get_options_flddata($field, $string = '', $match if (!empty($limit)) { $select->range(0, $limit); } + if (!empty($order)) { + $select->orderBy($order); + } $select->distinct(); $rows = $select->execute()->fetchAll(PDO::FETCH_ASSOC); @@ -168,10 +175,10 @@ function _autocomplete_widgets_get_options_flddata($field, $string = '', $match * * Options are retrieved from the suggested values defined for the field. */ -function _autocomplete_widgets_get_options_suggested($field, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { - $case_sensitive = empty($field['widget']['autocomplete_case']); +function _autocomplete_widgets_get_options_suggested($instance, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { + $case_sensitive = empty($instance['widget']['autocomplete_case']); - $options = explode("\n", $field['widget']['settings']['suggested_values']); + $options = explode("\n", $instance['widget']['settings']['suggested_values']); $options = array_map('trim', $options); $options = array_filter($options, 'strlen'); @@ -200,9 +207,10 @@ function _autocomplete_widgets_get_options_suggested($field, $string = '', $matc $options = array($string); } break; - } + _autocomplete_widgets_sort_options($options, $instance); + return $options; } @@ -211,20 +219,25 @@ function _autocomplete_widgets_get_options_suggested($field, $string = '', $matc * * Options are retrieved from the titles of the allowed node types. */ -function _autocomplete_widgets_get_options_node_reference($field, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { - $field_name = $field['field_name']; - $table = 'field_data_' . $field_name; - $column = $field_name . '_value'; +function _autocomplete_widgets_get_options_node_reference($instance, $string = '', $match = 'contains', $keys = NULL, $limit = NULL) { + $table = 'field_data_' . $instance['field_name']; + $column = $instance['field_name'] . '_value'; $options = array(); + $order = isset($instance['widget']['settings']['order']) ? $instance['widget']['settings']['order'] : ''; $field_query = db_select($table, 'fd') ->fields('fd', array($column)); $node_title_query = db_select('node', 'n') ->fields('n', array('title')) - ->condition('n.type', $field['widget']['settings']['allowed_node_types'], 'IN') + ->condition('n.type', $instance['widget']['settings']['allowed_node_types'], 'IN') ->addTag('node_access'); + if (!empty($order)) { + $field_query->orderBy($order); + $node_title_query->orderBy($order); + } + if ($string !== '') { switch ($match) { case 'starts_with': @@ -237,6 +250,7 @@ function _autocomplete_widgets_get_options_node_reference($field, $string = '', $node_title_query->condition('n.title', '%' . $string . '%', 'LIKE'); break; } + //@todo: can these fetch all's be replaced with fetchAssoc? $rows = $node_title_query->execute()->fetchAll(PDO::FETCH_ASSOC); foreach($rows as $row) { $options[$row['title']] = $row['title']; @@ -246,6 +260,39 @@ function _autocomplete_widgets_get_options_node_reference($field, $string = '', $options[$row[$column]] = $row[$column]; } } - sort($options); + return $options; } + +/** + * Validate a list autocomplete element. + */ +function _autocomplete_widgets_validate_allowvals($element, &$form_state) { + $instance = field_widget_instance($element, $form_state); + if ($instance['widget']['type'] == 'autocomplete_widgets_allowvals') { + $label = $element['#value']; + if ($label !== '') { + module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common'); + $options = _autocomplete_widgets_get_options($instance, $label, 'equals', NULL, 1); + if (empty($options)) { + form_error($element, t('%name: %label is not a valid option for this field.', array('%name' => $instance['label'], '%label' => $label))); + } + } + } +} + +/** + * Sort an array of options fo the given field instance. + */ +function _autocomplete_widgets_sort_options(&$options, $instance) { + if (isset($instance['widget']['settings']['order'])) { + switch ($instance['widget']['settings']['order']) { + case 'ASC': + sort($options); + break; + case 'DESC': + rsort($options); + break; + } + } +} diff --git a/autocomplete_widgets.module b/autocomplete_widgets.module index 5ffdad9..0b4c6b9 100755 --- a/autocomplete_widgets.module +++ b/autocomplete_widgets.module @@ -28,17 +28,51 @@ function autocomplete_widgets_menu() { ); } +// /** +// * 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_views_api(). + * Implementation of hook_element_info(). + * + * Autocomplete_path is not used by text_widget but other widgets can use it. */ -function autocomplete_widgets_views_api() { +function autocomplete_widgets_element_info() { return array( - 'api' => 3.0, - 'path' => drupal_get_path('module', 'autocomplete_widgets') . '/views', + 'autocomplete_widgets' => array( + '#input' => TRUE, + '#columns' => array('value'), '#delta' => 0, + '#process' => array('autocomplete_widgets_element_process'), + '#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() { @@ -83,31 +117,6 @@ function autocomplete_widgets_field_widget_info() { } /** - * Implementation of hook_element_info(). - * - * Autocomplete_path is not used by text_widget but other widgets can use it - * (see nodereference and userreference). - */ -function autocomplete_widgets_element_info() { - return array( - 'autocomplete_widgets' => array( - '#input' => TRUE, - '#columns' => array('value'), '#delta' => 0, - '#process' => array('autocomplete_widgets_process_element'), - '#autocomplete_path' => FALSE, - ), - ); -} - -/** - * 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); -} - -/** * Implementation of hook_field_widget_form(). */ function autocomplete_widgets_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) { @@ -134,17 +143,17 @@ function autocomplete_widgets_field_widget_form(&$form, &$form_state, $field, $i 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'], + '#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 + // 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_process_element'), + '#process' => array('autocomplete_widgets_element_process'), '#title' => $element['#title'], '#field_name' => $element['#field_name'], '#field_parents' => $element['#field_parents'], @@ -156,69 +165,21 @@ function autocomplete_widgets_field_widget_form(&$form, &$form_state, $field, $i '#required' => $element['#required'], '#weight' => isset($element['#weight']) ? $element['#weight'] : 0, '#delta' => $delta, - '#element_validate' => array('autocomplete_widgets_validate'), + '#file' => drupal_get_path('module', 'autocomplete_widgets') . '/autocomplete_widgets.common.inc', + '#element_validate' => array('_autocomplete_widgets_validate_allowvals'), )); + break; } return $element; } /** - * Process an individual textfield autocomplete element. - */ -function autocomplete_widgets_process_element($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; -} - -/** - * Validate a list autocomplete element. - */ -function autocomplete_widgets_validate($element, &$form_state) { - $instance = field_widget_instance($element, $form_state); - if ($instance['widget']['type'] == 'autocomplete_widgets_allowvals') { - $label = $element['#value']; - if ($label !== '') { - module_load_include('inc', 'autocomplete_widgets', 'autocomplete_widgets.common'); - $options = _autocomplete_widgets_get_options($instance, $label, 'equals', NULL, 1); - if (empty($options)) { - form_error($element, t('%name: %label is not a valid option for this field.', array('%name' => $instance['label'], '%label' => $label))); - } - } - } -} - -/** - * 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'); - $field = field_info_instance($entity_type, $field_name, $bundle_name); - $match = isset($field['widget']['settings']['autocomplete_match']) ? $field['widget']['settings']['autocomplete_match'] : 'contains'; - $matches = array(); - $options = _autocomplete_widgets_get_options($field, $string, $match, NULL, 10); - foreach ($options as $key => $label) { - // Add a class wrapper for a few required CSS overrides. - $matches[$label] = '
'. check_plain($label) .'
'; - } - drupal_json_output($matches); -} - -/** - * Theme an individual textfield autocomplete element. + * Implementation of hook_field_widget_settings_form(). */ -function theme_autocomplete_widgets($element) { - return $element['#children']; +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); } /** @@ -281,3 +242,29 @@ function autocomplete_widgets_field_formatter_view($entity_type, $entity, $field } 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($field['widget']['settings']['autocomplete_match']) ? $field['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] = '
'. check_plain($label) .'
'; + } + drupal_json_output($matches); +} + +/** + * Theme an individual textfield autocomplete element. + */ +function theme_autocomplete_widgets($element) { + return $element['#children']; +} +