Index: signup.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/signup/signup.module,v
retrieving revision 1.151
diff -u -p -r1.151 signup.module
--- signup.module	8 Oct 2008 07:15:40 -0000	1.151
+++ signup.module	10 Oct 2008 06:25:18 -0000
@@ -860,7 +860,9 @@ function _signup_print_current_signup($n
   $header = array(array('data' => t('Your signup information'), 'colspan' => 2));
   $rows = array();
   if (is_array($form_data)) {
-    $rows += signup_build_signup_data($form_data, 'table');
+    // Include the default copy of theme_signup_custom_data().
+    include_once(SIGNUP_PATH .'/signup.theme');
+    $rows += theme('signup_custom_data', $form_data, 'table');
   }
   $output = '';
   if (!empty($rows)) {
@@ -1499,6 +1501,9 @@ function signup_sign_up_user($signup_for
 function signup_node_admin_page($node) {
   drupal_set_title(check_plain($node->title));
 
+  // Include the default copy of any theme functions used in here.
+  include_once(SIGNUP_PATH .'/signup.theme');
+
   // Prepare a table header that allows sorting on name and signup time.
   $header = array(
     array('data' => t('Name'), 'field' => 'u.name', 'sort' => 'asc'),
@@ -1521,7 +1526,7 @@ function signup_node_admin_page($node) {
     $form_data = unserialize($signed_up_user->form_data);
 
     // Compose the user data.
-    $signup_form_data = signup_build_signup_data($form_data);
+    $signup_form_data = theme('signup_custom_data', $form_data);
 
     // The username and the unique form identifier are different for
     // anon signups and registered user signups.  For registered users,
@@ -1908,57 +1913,14 @@ function _signup_admin_form($node = NULL
 }
 
 /**
- * Builds serialized user signup data into user-readable format.
+ * Deprecated function to render signup data in a human-readable form.
  *
- * @param $data The serialized user signup data.
- * @param $type The type of formatting -- defaults to 'output'.
- *
- * @return For table formatting, an array of table rows, for output formatting, raw user data in divs.
+ * @see theme_signup_custom_data()
  */
 function signup_build_signup_data($data, $type = 'output') {
-
-  switch ($type) {
-    case 'table':
-      static $rows = array();
-      // Loop through each first level element.
-      foreach ($data as $key => $value) {
-        // Element is nested, render it recursively.
-        if (is_array($value)) {
-          $rows[] = array('<div id="'. $key .'"></div>');
-          signup_build_signup_data($value, 'table');
-        }
-        else {
-          $rows[] = array($key .':', check_plain($value));
-        }
-      }
-      return $rows;
-    case 'output':
-      $output = '';
-      // Loop through each first level element.
-      foreach ($data as $key => $value) {
-        // Element is nested, render it recursively.
-        if (is_array($value)) {
-          $output .= '<div id="'. $key .'">'. signup_build_signup_data($value) .'</div>';
-        }
-        else {
-          $output .= '<div>'. $key .': '. check_plain($value) .'</div>';
-        }
-      }
-      return $output;
-    case 'email':
-      $output = '';
-      // Loop through each first level element.
-      foreach ($data as $key => $value) {
-        // Element is nested, render it recursively.
-        if (is_array($value)) {
-          $output .= "\n\r". signup_build_signup_data($value, 'email') ."\n\r";
-        }
-        else {
-          $output .= $value ."\n\r";
-        }
-      }
-      return $output;
-  }
+  // Include the default copy of theme_signup_custom_data().
+  include_once(SIGNUP_PATH .'/signup.theme');
+  return theme('signup_custom_data', $data, $type);
 }
 
 /**
@@ -2253,13 +2215,12 @@ function _signup_get_email_tokens($node,
 
   // Get the array of custom signup data (if any).
   if (is_array($signup->form_data)) {
-    $signup_data_array = $signup->form_data;
+    $signup_data = $signup->form_data;
   }
   else {
-    $signup_data_array = unserialize($signup->form_data);
+    $signup_data = unserialize($signup->form_data);
   }
-  if (!empty($signup_data_array)) {
-    $signup_data = signup_build_signup_data($signup_data_array, 'email');
+  if (!empty($signup_data)) {
     $tokens['%info'] = theme('signup_email_token_custom_data', $signup_data);
   }
   // Determine if this is an anon signup or not, and get the right info.
@@ -2273,3 +2234,21 @@ function _signup_get_email_tokens($node,
   }
   return $tokens;
 }
+
+/**
+ * Converts an arbitrary string into something safe to use for a CSS id.
+ *
+ * Stolen wholesale from the Zen theme. ;)
+ * @see zen_id_safe()
+ */
+function signup_id_safe($string) {
+  // Replace with dashes anything that isn't a-zA-Z, numbers, dashes, or
+  // underscores.
+  $string = strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $string));
+  // If the first character is not a-z, add 'id' in front.
+  // Don't use ctype_alpha since it's locale aware.
+  if (!ctype_lower($string{0})) { 
+    $string = 'id' . $string;
+  }
+  return $string;
+}
Index: signup.theme
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/signup/signup.theme,v
retrieving revision 1.14
diff -u -p -r1.14 signup.theme
--- signup.theme	30 Sep 2008 21:10:43 -0000	1.14
+++ signup.theme	10 Oct 2008 06:25:18 -0000
@@ -104,7 +104,81 @@ function theme_signup_email_token_anonym
 
 /**
  * Returns the value to use for the %info email token for custom signup data.
+ *
+ * @param $signup_data
+ *   Array of custom data for a particular signup.
+ *
+ * @see theme_signup_user_form()
  */
 function theme_signup_email_token_custom_data($signup_data) {
-  return t('SIGNUP INFORMATION') . "\n\r" . $signup_data;
+  return t('SIGNUP INFORMATION') . "\n\r" . theme('signup_custom_data', $signup_data, 'email');
+}
+
+/**
+ * Renders custom signup user data into a human-readable format.
+ *
+ * @param $data
+ *    Array of custom user signup data.
+ * @param $type
+ *    The type of formatting to render. Supported values are 'table' to
+ *    return an array of rows for a table, 'output' for output in HTML
+ *    div tags, or 'email' for unfiltered output for use in email bodies.
+ *
+ * @return
+ *    'table' formatting:  an array of table rows
+ *    'output' formatting: user data directly formatted in divs
+ *    'email' formatting:  plain text output with newlines
+ *
+ * @see theme_signup_user_form()
+ */
+function theme_signup_custom_data($data, $type = 'output') {
+  switch ($type) {
+    case 'table':
+      static $rows = array();
+      // Loop through each first level element.
+      foreach ($data as $key => $value) {
+        if (is_array($value)) {
+          // Element is nested, render it recursively.
+          // Instead of the overhead of theme(), just call ourself directly.
+          call_user_func(__FUNCTION__, $value, 'table');
+        }
+        else {
+          $rows[] = array($key . ':', check_plain($value));
+        }
+      }
+      return $rows;
+
+    case 'output':
+      $output = '';
+      // Loop through each first level element.
+      foreach ($data as $key => $value) {
+        $output .= '<div id="' . signup_id_safe($key) . '">';
+        if (is_array($value)) {
+          // Element is nested, render it recursively.
+          // Instead of the overhead of theme(), just call ourself directly.
+          $output .= call_user_func(__FUNCTION__, $value);
+        }
+        else {
+          $output .= $key . ': ' . check_plain($value);
+        }
+        $output .= "</div>\n";
+      }
+      return $output;
+
+    case 'email':
+      $output = '';
+      // Loop through each first level element.
+      foreach ($data as $key => $value) {
+        if (is_array($value)) {
+          // Element is nested, render it recursively.
+          // Instead of the overhead of theme(), just call ourself directly.
+          $output .= "\n\r" . call_user_func(__FUNCTION__, $value, 'email') . "\n\r";
+        }
+        else {
+          $output .= $key . ': ' . $value . "\n\r";
+        }
+      }
+      return $output;
+
+  }
 }
