? API.txt
Index: admin.js
===================================================================
RCS file: /cvs/drupal/contributions/modules/user_titles/admin.js,v
retrieving revision 1.9
diff -u -r1.9 admin.js
--- admin.js	26 Jul 2007 23:25:11 -0000	1.9
+++ admin.js	6 Dec 2007 00:06:17 -0000
@@ -11,6 +11,7 @@
   // Bind our buttons.
   $("input#edit-add-submit").click(Drupal.UserTitles.addTitle);
   $("table#user-titles-settings img.title-delete").click(Drupal.UserTitles.removeTitle);
+  $("input.user-titles-hook-module").click(Drupal.UserTitles.toggleTypeCheckboxes);
 }
 
 Drupal.UserTitles.addTitle = function() {
@@ -78,6 +79,13 @@
       .addClass('even');
 }
 
+// toggles type checkboxes disabled status by checking userpoints field
+Drupal.UserTitles.toggleTypeCheckboxes = function() {
+  var disableType = ! $("input.user-titles-hook-module").eq(0).attr('checked');
+  $('.user-titles-types').attr('disabled', disableType ? 'disabled' : '');
+  $('input#edit-types-disabled').val(disableType ? '1' : '0');
+}
+
 // We are ignoring the global Drupal killswitch, because this module doesn't
 // currently degrade gracefully. It can, but the code has not yet been written.
 
Index: user_titles.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/user_titles/user_titles.module,v
retrieving revision 1.13
diff -u -r1.13 user_titles.module
--- user_titles.module	19 Nov 2007 00:46:36 -0000	1.13
+++ user_titles.module	6 Dec 2007 00:24:44 -0000
@@ -41,6 +41,12 @@
   }
 }
 
+function user_titles_hook_module() {
+  $module = variable_get('user_titles_hook_module', '');
+  if ($module != '' && module_exists($module)) return $module;
+  return '';
+}
+
 /**
  * Form to determine titles and levels.
  */
@@ -51,12 +57,54 @@
     $nodes[$type] = $info->name;
   }
 
+  $hook_module  = variable_get('user_titles_hook_module', '');
+  $hook_modules = module_invoke_all('user_titles', 'register');
+  if (!module_exists($hook_module)) $hook_module = '';
+  
+  $form['hook-module'] = array(
+    '#type' => 'radios',
+    '#title' => 'Point scheme',
+    '#default_value' => $hook_module,
+    '#options' => array(),
+    '#attributes' => array('class' => 'user-titles-hook-module'),
+  );
+  
+  $form['hook-module']['#options'][''] = array(
+    'name' => t('Node count'),
+    'description' => t('Built-in, see below'),
+  );
+  foreach ($hook_modules as $module) {
+    $form['hook-module']['#options'][$module] = array(
+      'name'        => module_invoke($module, 'user_titles', 'name'),
+      'description' => module_invoke($module, 'user_titles', 'description'),
+      'url'         => module_invoke($module, 'user_titles', 'url'),
+    );
+  }
+  
+  // Properly format hook-module, this probably shouldn't be here
+  foreach ($form['hook-module']['#options'] as $module => $info) {
+    $link_start = $link_end = '';
+    if ($info['url']) {
+      $link_start = '<a href="'. $info['url'] .'">';
+      $link_end   = '</a>';
+    }
+    $form['hook-module']['#options'][$module] =
+      '<strong>'. $link_start . $info['name'] . $link_end
+      .'</strong><div class="description">'. $info['description'] .'</div>';
+  }
+  
   $form['types'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Counted node types'),
     '#description' => t('Only the checked node types will be counted'),
     '#options' => $nodes,
     '#default_value' => $types,
+    '#disabled' => !empty($hook_module),
+    '#attributes' => array('class' => 'user-titles-types'),
+  );
+  $form['types-disabled'] = array(
+    '#type' => 'text',
+    '#default_value' => $use_userpoints,
   );
 
   $titles = user_titles_get_titles();
@@ -128,8 +176,12 @@
   drupal_add_js(array('userTitles' => array('imageURL' => base_path() ."misc/watchdog-error.png")), 'setting');
   drupal_add_js("$path/admin.js");
   drupal_add_css("$path/admin.css");
+  $countable = t('Posts');
+  if (user_titles_hook_module()) {
+    $countable = t('!Points', userpoints_translation());
+  }
   $header = array(
-    array('data' => t('Posts'), 'class' => 'num-posts'),
+    array('data' => $countable, 'class' => 'num-posts'),
     array('data' => t('Title'), 'class' => 'user-title'),
     '',
   );
@@ -159,6 +211,7 @@
   $output .= '</div>';
 
   $output .= '<div class="right">';
+  $output .= drupal_render($form['hook-module']);
   $output .= drupal_render($form['types']);
   $output .= '</div>';
 
@@ -208,7 +261,10 @@
     db_query("TRUNCATE {user_titles_posts}");
   }
 
-  user_titles_set_allowed_types(array_keys(array_filter($form_values['types'])));
+  if (!$form_values['types-disabled']) {
+    user_titles_set_allowed_types(array_keys(array_filter($form_values['types'])));
+  }
+  variable_set('user_titles_hook_module', $form_values['hook-module']);
   drupal_set_message(t('The configuration has been updated.'));
 }
 
@@ -247,7 +303,13 @@
 function user_titles_get_posts($uid) {
   static $cache = array();
   if (!array_key_exists($uid, $cache)) {
-    $cache[$uid] = db_result(db_query("SELECT posts FROM {user_titles_posts} WHERE uid = %d", $uid));
+    $cache[$uid] = FALSE;
+    if ($module = user_titles_hook_module()) {
+      $cache[$uid] = module_invoke($module, 'user_titles', 'get', $uid);
+    }
+    else {
+      $cache[$uid] = db_result(db_query("SELECT posts FROM {user_titles_posts} WHERE uid = %d", $uid));
+    }
     if ($cache[$uid] === FALSE) {
       $cache[$uid] = user_titles_update_post_count($uid);
     }
@@ -352,8 +414,8 @@
  */
 function user_titles_get_titles() {
   $query = db_query("SELECT title, value, tid FROM {user_titles} ORDER BY value DESC");
-  if(db_num_rows($query)) {
-    while($r = db_fetch_array($query)) {
+  if (db_num_rows($query)) {
+    while ($r = db_fetch_array($query)) {
       $result[] = $r;
     }
   }
@@ -368,8 +430,8 @@
  */
 function user_titles_set_titles($titles) {
   db_query("TRUNCATE {user_titles}");
-  foreach($titles as $title) {
-    if($title['tid'] == 'new') {
+  foreach ($titles as $title) {
+    if ($title['tid'] == 'new') {
       $title['tid'] = db_next_id("{user_titles}_tid");
     }
     db_query("INSERT INTO {user_titles} (title, value, tid) VALUES ('%s', %d, %d)", $title['title'], $title['value'], $title['tid']);
@@ -400,7 +462,7 @@
     }
 
     $form['user_titles']['current_title'] = array(
-      '#value' => '<div><strong>' . t('Current user title:') . ' </strong> ' . filter_xss_admin($title) . '</div>',
+      '#value' => '<div><strong>'. t('Current user title:') .' </strong> '. filter_xss_admin($title) .'</div>',
     );
 
     if (isset($title_info['title']) && empty($title_info['tid'])) {
@@ -412,7 +474,7 @@
         $default_title = $default_title_info['title'];
       }
       $form['user_titles']['default_title'] = array(
-        '#value' => '<div><strong>' . t('Default user title:') . ' </strong> ' . filter_xss_admin($default_title) . '</div>',
+        '#value' => '<div><strong>'. t('Default user title:') .' </strong> '. filter_xss_admin($default_title) .'</div>',
       );
     }
 
@@ -435,3 +497,22 @@
     }
   }
 }
+
+/**
+ * Sample hook implementation for userpoints; should be placed in userpoints
+ */
+function userpoints_user_titles($op, $uid = null) {
+  if (!module_exists('userpoints')) return;
+  switch ($op) {
+    case 'register':
+      return 'userpoints';
+    case 'name':
+      return 'User points';
+    case 'description':
+      return 'Different points values are assigned to user actions';
+    case 'url':
+      return url('admin/help/userpoints');
+    case 'get':
+      return userpoints_get_current_points($uid);
+  }
+}
