Index: nodereference.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/nodereference.module,v
retrieving revision 1.27
diff -u -r1.27 nodereference.module
--- nodereference.module	5 May 2006 14:10:44 -0000	1.27
+++ nodereference.module	9 May 2006 20:50:56 -0000
@@ -46,23 +46,57 @@
   switch ($op) {
     case 'form':
       $form = array();
-      $form['referenceable_types'] = array(
-        '#type' => 'checkboxes',
-        '#title' => t('Content types that can be referenced'),
+      $form['types'] = array(
+        '#type' => 'fieldset', 
+        '#title' => t('Referenceable types'),
+        '#description' => t('Select all content types that can be referenced. Values from all these content types will be made available in lists.'),
+        );
+      $form['types']['referenceable_types'] = array(
+        '#type' => 'select',
         '#multiple' => TRUE,
         '#default_value' => isset($field['referenceable_types']) ? $field['referenceable_types'] : array(),
-        '#options' => node_get_types(),
+        '#options' => _nodereference_add_none(node_get_types()),
       );
+      $form['types2'] = array(
+        '#type' => 'fieldset', 
+        '#title' => t('Reverse links'),
+        '#description' => t('Select the content types that should display a reverse link back to the referencing node.'),
+        );
+      $form['types2']['linkable_types'] = array(
+        '#type' => 'select',
+        '#multiple' => TRUE,
+        '#default_value' => isset($field['linkable_types']) ? $field['linkable_types'] : array(),
+        '#options' => _nodereference_add_none(node_get_types()),
+        );
+      $form['types3'] = array(
+        '#type' => 'fieldset', 
+        '#title' => t('Prepend to title'),
+        '#description' => t('Prepend additional information about the node to the title. Use if the title alone will not be descriptive enough to identify the field. List all fields to be prepended to the title in selection lists.'),
+        );
+      $form['types3']['title_prepend'] = array(
+        '#type' => 'select',
+        '#multiple' => TRUE,
+        '#default_value' => isset($field['title_prepend']) ? $field['title_prepend'] : 0,
+        '#options' => _nodereference_add_none(_nodereference_prepend_fields()),
+        );
       return $form;
 
     case 'save':
-      return array('referenceable_types');
+      return array('referenceable_types', 'linkable_types', 'title_prepend');
 
     case 'database columns':
       $columns = array(
         'nid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'),
       );
       return $columns;
+
+    case 'filter operators':
+      return array(
+        '=' => t('is equal to'),
+        '!=' => t('is not equal to'),
+        'LIKE' => t('matches the pattern'),
+      );
+    break;
   }
 }
 
@@ -123,13 +157,30 @@
       case 'form':
         $form = array();
 
+        // check whether the option to prepend extra fields to the title was chosen, and add that info in if required
+        if ($field['title_prepend']) {
+           $e_options = _nodereference_potential_references($field, TRUE);
+           $prepend_fields = _nodereference_prepend_fields();
+           foreach ($e_options as $nid => $value) {
+             unset($prepend);
+             foreach ($field['title_prepend'] as $option) {
+               $prepend[$prepend_fields[$option]] = ($prepend_fields[$option] == 'created' || $prepend_fields[$option] == 'changed') ? format_date($value->$prepend_fields[$option]) : $value->$prepend_fields[$option];
+             }
+             $options[$nid] = '('. implode(':', $prepend) .') '. $value->title;
+           }
+        } else {
+           $options = _nodereference_potential_references($field);
+        }
+
+        if (!$field['required']) $options = _nodereference_add_none($options);
+
         $form[$field['field_name']] = array('#tree' => TRUE);
         $form[$field['field_name']]['nids'] = array(
           '#type' => 'select',
           '#title' => t($field['widget']['label']),
           '#default_value' => $node_field['default nids'],
           '#multiple' => $field['multiple'],
-          '#options' => _nodereference_potential_references($field),
+          '#options' => $options,
           '#required' => $field['required'],
           '#description' => $field['widget']['description'],
         );
@@ -226,10 +277,11 @@
 /**
  * Fetch an array of all candidate referenced nodes, for use in presenting the selection form to the user.
  */
-function _nodereference_potential_references($field, $return_full_nodes = FALSE) {
+function _nodereference_potential_references($field, $return_full_nodes = FALSE, $limit = array()) {
   $related_types = array();
 
-  foreach ($field['referenceable_types'] as $related_type) {
+  $referenceable_types = $limit ? $limit : $field['referenceable_types'];
+  foreach ($referenceable_types as $related_type) {
     if ($related_type) {
       $related_types[] = " type = '". $related_type ."'";
     }
@@ -241,7 +293,7 @@
     return array();
   }
 
-  $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, n.type FROM {node} n WHERE ". $related_clause ." ORDER BY n.title, n.type"));
+  $result = db_query(db_rewrite_sql("SELECT n.* FROM {node} n WHERE ". $related_clause ." ORDER BY n.title, n.type"));
 
   if (db_num_rows($result) == 0) {
     return array();
@@ -261,21 +313,27 @@
   return $rows;
 }
 
-function nodereference_referenced_by_list($nid, $content_type = '') {
-  if ($content_type) {
-    $result = db_query("SELECT n.* FROM {node_field_nodereference_data} node_ref INNER JOIN {node} n ON n.vid = node_ref.vid AND n.type = '%s' WHERE node_ref.field_nid = %d ORDER BY delta", $nid, $content_type);
-  }
-  else {
-    $result = db_query("SELECT n.* FROM {node_field_nodereference_data} node_ref INNER JOIN {node} n ON n.vid = node_ref.vid WHERE node_ref.field_nid = %d ORDER BY delta", $nid);
-  }
-
-  $values = array();
-
-  while ($value = db_fetch_object($result)) {
-    $values[] = $value;
+function nodereference_referenced_by_list($nid, $content_type = '', $linkable = '') {
+  
+  // find cck nodereference field tables and search through them for matching node ids
+  $links = array();
+  if ($content_type) $where = " AND ni.type_name = '$content_type' ";
+  
+  $result = db_query("SELECT * FROM {node_field} nf  INNER JOIN {node_field_instance} ni ON nf.field_name = ni.field_name WHERE nf.type='nodereference' $where");
+  while ($field = db_fetch_array($result)) {
+    $db_info   = content_database_info($field);
+    $all_types = _nodereference_add_none(node_get_types());
+    $settings  = unserialize($field['global_settings']);
+    foreach ((array)$settings['linkable_types'] as $type) {
+      $limit[] = $all_types[$type];
+    }
+    if ($linkable) $where = " AND n.type IN ('','". implode("','", (array) $types) ."')";
+    $ids = db_query("SELECT nref.vid, n.* FROM {". $db_info['table'] ."} nref INNER JOIN {node} n ON nref.vid = n.nid WHERE ". $db_info['columns']['nid']['column'] ."=". $nid . $where);
+    while ($data = db_fetch_object($ids)) {
+      $links[$data->vid] = $data;
+    }
   }
-
-  return $values;
+  return $links;
 }
 
 /**
@@ -285,13 +343,80 @@
   $fields = _content_fields();
   $field = $fields[$field_name];
   $matches = array();
-
+  
   foreach (_nodereference_potential_references($field, TRUE) as $key => $value) {
     if (stristr($value->title, $string)) {
-      $matches[$value->title] = check_plain('('. str_replace('content-', '', $value->type) .') '. $value->title);
+      
+      $prepend = array();
+      $prepend_fields = _nodereference_prepend_fields();
+        
+      foreach ($field['title_prepend'] as $option) {
+        $prepend[$prepend_fields[$option]] = ($prepend_fields[$option] == 'created' || $prepend_fields[$option] == 'changed') ? format_date($value->$prepend_fields[$option]) : $value->$prepend_fields[$option];
+      }
+      $matches[$value->title] = check_plain('('. str_replace('content-', '', $value->type) .' '. implode(':', $prepend) .') '. $value->title);
     }
   }
 
   print drupal_to_js($matches);
   exit();
-}
\ No newline at end of file
+}
+
+/**
+ * A list of possible fields to prepend to the node title to help clarify which node is which
+ */
+function _nodereference_prepend_fields() {
+  return array(1 => t('nid'), 2 => t('uid'), 3 => t('created'), 4 => t('changed'), 5 => t('status'));
+}
+
+/**
+ * Add a blank value to not-required select lists
+ */
+function _nodereference_add_none($array) {
+  return array(0 => '') + $array;
+}
+
+/**
+ * Implementation of hook_nodeapi().
+ */
+function nodereference_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
+  
+  switch ($op) {
+  
+  case("view"):
+    
+    $list = nodereference_referenced_by_list($node->nid, $node->type, 'linkable');
+    foreach ($list as $nid => $item ) {
+      $links[] = array('title' => $node_types[$node->type]->label, 'value' => l($item->title, 'node/'. $nid));
+    }
+    $output = array();
+    $output['']  = t('Related Content');
+    foreach ((array) $links as $link) {
+      if ($link['title']) $output[$link['title']][] = $link['value'];
+    }
+    ksort($output);
+    if (sizeof($output) > 1) $node->body .= theme('nodereference_related_nodes', $output, $node);
+    break;
+  }
+}
+
+/**
+ * A theme for the reverse link display
+ */
+function theme_nodereference_related_nodes($input, $node) {
+
+   $output  = '<h3>'. array_shift($input) .'</h3>';
+   $output .= '<dl>';
+   $prev_label = '';
+   foreach ($input as $label => $items) {
+     foreach ($items as $item) {
+       if ($label != $prev_label) {
+         $output .= '<dt>'. $label .'</dt>';
+         $prev_label = $label;
+       }
+       $output .= '<dd>'. $item .'</dd>';
+     }
+   }
+   $output .= '</dl>';
+   return $output;
+}
+
