? cck-nodereference-views-autocomplete-506654.patch Index: includes/views/handlers/content_handler_filter_many_to_one.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/cck/includes/views/handlers/Attic/content_handler_filter_many_to_one.inc,v retrieving revision 1.1.2.5 diff -u -p -r1.1.2.5 content_handler_filter_many_to_one.inc --- includes/views/handlers/content_handler_filter_many_to_one.inc 14 Aug 2009 19:15:10 -0000 1.1.2.5 +++ includes/views/handlers/content_handler_filter_many_to_one.inc 12 Oct 2009 14:36:32 -0000 @@ -8,6 +8,7 @@ */ class content_handler_filter_many_to_one extends views_handler_filter_many_to_one { var $content_field; + var $can_autocomplete = FALSE; function construct() { parent::construct(); @@ -15,10 +16,16 @@ class content_handler_filter_many_to_one $this->additional_fields = $this->definition['additional fields']; $field = $this->content_field; $this->value_title = $field['widget']['label']; + $this->can_autocomplete = in_array($field['module'], array('nodereference', 'userreference')); } function get_value_options() { - $this->value_options = $this->allowed_values(); + if (empty($this->can_autocomplete) || $this->options['type'] == 'select') { + $this->value_options = $this->allowed_values(); + } + else { + /* don't overwrite the value options */ + } } // Get allowed values from hook_allowed_values(), if any, @@ -39,4 +46,129 @@ class content_handler_filter_many_to_one return (array) $options; } -} \ No newline at end of file + function has_extra_options() { return $this->can_autocomplete; } + + function option_definition() { + $options = parent::option_definition(); + + $options['type'] = array('default' => 'select'); + + return $options; + } + + function extra_options_form(&$form, &$form_state) { + $form['type'] = array( + '#type' => 'radios', + '#title' => t('Selection type'), + '#options' => array('select' => t('Dropdown'), 'textfield' => t('Autocomplete')), + '#default_value' => $this->options['type'], + ); + } + + function value_form(&$form, &$form_state) { + if ($this->options['type'] == 'textfield') { + $form['value'] = array( + '#tree' => TRUE, + '#title' => t('@widget-label', array('@widget-label' => $this->value_title)), + '#type' => 'nodereference_autocomplete', + '#views' => TRUE, + '#views_single' => $this->options['expose']['single'], + '#default_value' => $this->value ? array('name' => $this->value) : array(), + '#field_name' => $this->content_field['field_name'], + '#type_name' => $this->content_field['type_name'], + '#value_callback' => 'nodereference_autocomplete_value', + ); + + if (empty($form_state['exposed'])) { + // Retain the helper option + $this->helper->options_form($form, $form_state); + } + } + else { + parent::value_form($form, $form_state); + } + } + + function value_validate(&$form, &$form_state) { + // We only validate if they've chosen the text field style. + if ($this->options['type'] != 'textfield') { + return; + } + + $form_state['values']['options']['value'] = $form_state['values']['options']['value']['name']; + } + + function accept_exposed_input($input) { + if (empty($this->options['exposed'])) { + return TRUE; + } + + // If it's optional and there's no value don't bother filtering. + if ($this->options['expose']['optional'] && empty($this->validated_exposed_input)) { + return FALSE; + } + + $rc = parent::accept_exposed_input($input); + if ($rc) { + // If we have previously validated input, override. + if (isset($this->validated_exposed_input)) { + $this->value = $this->validated_exposed_input; + } + } + + return $rc; + } + + function exposed_validate(&$form, &$form_state) { + if (empty($this->options['exposed'])) { + return; + } + + $identifier = $this->options['expose']['identifier']; + + // We only validate if they've chosen the text field style. + if ($this->options['type'] != 'textfield') { + if ($form_state['values'][$identifier] != 'All') { + $this->validated_exposed_input = (array) $form_state['values'][$identifier]; + } + return; + } + + if (empty($this->options['expose']['identifier'])) { + return; + } + + $this->validated_exposed_input = $form_state['values'][$identifier]['name']; + } + + function value_submit($form, &$form_state) { + // prevent array_filter from messing up our arrays in parent submit. + } + + function expose_form_right(&$form, &$form_state) { + parent::expose_form_right($form, $form_state); + if ($this->options['type'] != 'select') { + unset($form['expose']['reduce']); + } + } + + function admin_summary() { + // set up $this->value_options for the parent summary + $this->value_options = array(); + + if ($this->value) { + if ($this->content_field['module'] == 'nodereference') { + $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n WHERE n.nid IN (' . implode(', ', $this->value) . ')')); + } + elseif ($this->content_field['module'] == 'userreference') { + $result = db_query('SELECT u.uid, u.name FROM {user} u WHERE u.uid IN (' . implode(', ', $this->value) . ')'); + } + + while ($node = db_fetch_object($result)) { + $this->value_options[$node->nid] = $node->title .'[nid:'. $node->nid .']'; + } + } + return parent::admin_summary(); + } + +} Index: modules/nodereference/nodereference.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/nodereference/Attic/nodereference.module,v retrieving revision 1.138.2.60 diff -u -p -r1.138.2.60 nodereference.module --- modules/nodereference/nodereference.module 26 Aug 2009 17:29:58 -0000 1.138.2.60 +++ modules/nodereference/nodereference.module 12 Oct 2009 14:36:35 -0000 @@ -519,10 +519,21 @@ function nodereference_widget(&$form, &$ function nodereference_autocomplete_value($element, $edit = FALSE) { $field_key = $element['#columns'][0]; if (!empty($element['#default_value'][$field_key])) { - $nid = $element['#default_value'][$field_key]; - $value = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $nid)); - $value .= ' [nid:'. $nid .']'; - return array($field_key => $value); + $nids = array(); + $values = array(); + if (!empty($element['#views'])) { + $nids = $element['#default_value'][$field_key]; + } + else { + $nids = array($element['#default_value'][$field_key]); + } + + $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n WHERE n.nid IN ('. db_placeholders($nids) .')'), $nids); + while ($data = db_fetch_object($result)) { + $values[] = $data->title .' [nid:'. $data->nid .']'; + } + + return array($field_key => implode(', ', $values)); } return array($field_key => NULL); } @@ -609,11 +620,15 @@ function nodereference_autocomplete_proc // path and some extra processing to it. // Add a validation step where the value can be unwrapped. $field_key = $element['#columns'][0]; + $field_name = $element['#field_name']; + if (!empty($element['#views']) && empty($element['#views_single'])) { + $field_name = 'views_'. $field_name; + } $element[$field_key] = array( '#type' => 'text_textfield', '#default_value' => isset($element['#value']) ? $element['#value'] : '', - '#autocomplete_path' => 'nodereference/autocomplete/'. $element['#field_name'], + '#autocomplete_path' => 'nodereference/autocomplete/'. $field_name, // The following values were set by the content module and need // to be passed down to the nested element. '#title' => $element['#title'], @@ -623,6 +638,7 @@ function nodereference_autocomplete_proc '#type_name' => $element['#type_name'], '#delta' => $element['#delta'], '#columns' => $element['#columns'], + '#views' => $element['#views'], ); if (empty($element[$field_key]['#element_validate'])) { $element[$field_key]['#element_validate'] = array(); @@ -682,31 +698,46 @@ function nodereference_autocomplete_vali $delta = $element['#delta']; $value = $element['#value'][$field_key]; $nid = NULL; + $nids = array(); + if (!empty($value)) { - preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches); - if (!empty($matches)) { - // Explicit [nid:n]. - list(, $title, $nid) = $matches; - if (!empty($title) && ($n = node_load($nid)) && trim($title) != trim($n->title)) { - form_error($element[$field_key], t('%name: title mismatch. Please check your selection.', array('%name' => t($field['widget']['label'])))); - } + if (!empty($element['#views'])) { + $value = drupal_explode_tags($value); } else { - // No explicit nid. - $reference = _nodereference_potential_references($field, $value, 'equals', NULL, 1); - if (empty($reference)) { - form_error($element[$field_key], t('%name: found no valid post with that title.', array('%name' => t($field['widget']['label'])))); + $value = array($value); + } + + foreach ($value as $v) { + $nid = NULL; + preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $v, $matches); + if (!empty($matches)) { + // Explicit [nid:n]. + list(, $title, $nid) = $matches; + if (!empty($title) && ($n = node_load($nid)) && trim($title) != trim($n->title)) { + form_error($element[$field_key], t('%name: title mismatch. Please check your selection.', array('%name' => t($field['widget']['label'])))); + } } else { - // TODO: - // the best thing would be to present the user with an additional form, - // allowing the user to choose between valid candidates with the same title - // ATM, we pick the first matching candidate... - $nid = key($reference); + // No explicit nid. + $reference = _nodereference_potential_references($field, $v, 'equals', NULL, 1); + if (empty($reference)) { + form_error($element[$field_key], t('%name: found no valid post with that title.', array('%name' => t($field['widget']['label'])))); + } + else { + // TODO: + // the best thing would be to present the user with an additional form, + // allowing the user to choose between valid candidates with the same title + // ATM, we pick the first matching candidate... + $nid = key($reference); + } + } + if (!empty($nid)) { + $nids[] = $nid; } } } - form_set_value($element, $nid, $form_state); + form_set_value($element, (empty($element['#views']) ? $nid : $nids), $form_state); } /** @@ -910,6 +941,16 @@ function _nodereference_potential_refere */ function nodereference_autocomplete($field_name, $string = '') { $fields = content_fields(); + $prefix = ''; + + // Check for a views field. + if (0 === substr_compare($field_name, 'views_', 0, 6)) { + $field_name = str_replace('views_', '', $field_name); + $array = drupal_explode_tags($string); + $string = trim(array_pop($array)); + $prefix = count($array) ? implode(', ', $array) .', ' : ''; + } + $field = $fields[$field_name]; $match = isset($field['widget']['autocomplete_match']) ? $field['widget']['autocomplete_match'] : 'contains'; $matches = array(); @@ -917,7 +958,7 @@ function nodereference_autocomplete($fie $references = _nodereference_potential_references($field, $string, $match, array(), 10); foreach ($references as $id => $row) { // Add a class wrapper for a few required CSS overrides. - $matches[$row['title'] ." [nid:$id]"] = '