Index: components/hidden.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/hidden.inc,v
retrieving revision 1.18
diff -u -r1.18 hidden.inc
--- components/hidden.inc	12 Jan 2010 22:28:48 -0000	1.18
+++ components/hidden.inc	14 Jan 2010 05:56:42 -0000
@@ -22,6 +22,17 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_hidden() {
+  return array(
+    'webform_display_hidden' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_hidden($component) {
@@ -47,7 +58,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_hidden($component, $value = NULL, $filter = TRUE) {
-  $form_item = array(
+  $element = array(
     '#type'          => 'hidden',
     '#title'         => $component['name'],
     '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'],
@@ -55,26 +66,33 @@
   );
 
   if (isset($value[0])) {
-    $form_item['#default_value'] = $value[0];
+    $element['#default_value'] = $value[0];
   }
 
-  return $form_item;
+  return $element;
 }
 
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_hidden($component, $value) {
-  $form_item = _webform_render_hidden($component, $value);
-  // Only allow administrators that can view or edit all submissions to view or edit hidden fields.
-  if (user_access('edit all webform submissions') || user_access('access all webform results')) {
-    unset($form_item['#value']);
-    $form_item['#default_value'] = $value[0];
-    $form_item['#type'] = 'textfield';
-    $form_item['#title'] = t('@name (hidden)', array('@name' => $component['name']));
-    $form_item['#disabled'] = TRUE;
-  }
-  return $form_item;
+function _webform_display_hidden($component, $value, $format = 'html') {
+  $element = array(
+    '#title' => t('!name (hidden)', array('!name' => $component['name'])),
+    '#value' => isset($value[0]) ? $value[0] : NULL,
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_hidden',
+    '#component' => $component,
+    '#format' => $format,
+    '#theme' => 'webform_display_hidden',
+    '#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#access' => user_access('edit all webform submissions') || user_access('access all webform results'),
+  );
+  return $element;
+}
+
+function theme_webform_display_hidden($element) {
+  return $element['#format'] == 'html' ? check_plain($element['#value']) : $element['#value'];
 }
 
 /**
Index: components/textarea.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/textarea.inc,v
retrieving revision 1.17
diff -u -r1.17 textarea.inc
--- components/textarea.inc	12 Jan 2010 22:28:48 -0000	1.17
+++ components/textarea.inc	14 Jan 2010 05:56:42 -0000
@@ -29,6 +29,18 @@
   );
 }
 
+
+/**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_textarea() {
+  return array(
+    'webform_display_textarea' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
 /**
  * Implementation of _webform_edit_component().
  */
@@ -81,7 +93,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_textarea($component, $value = NULL, $filter = TRUE) {
-  $form_item = array(
+  $element = array(
     '#type'          => 'textarea',
     '#title'         => $component['name'],
     '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'],
@@ -97,24 +109,41 @@
   );
 
   if ($component['extra']['disabled']) {
-    $form_item['#attributes']['readonly'] = 'readonly';
+    $element['#attributes']['readonly'] = 'readonly';
   }
 
   if (isset($value)) {
-    $form_item['#default_value'] = $value[0];
+    $element['#default_value'] = $value[0];
   }
 
-  return $form_item;
+  return $element;
 }
 
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_textarea($component, $value) {
-  $form_item = _webform_render_textarea($component, $value);
-  $form_item['#default_value'] = $value[0];
-  $form_item['#attributes']['readonly'] = 'readonly';
-  return $form_item;
+function _webform_display_textarea($component, $value, $format = 'html') {
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_textarea',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#component' => $component,
+    '#format' => $format,
+    '#value' => isset($value[0]) ? $value[0] : '',
+  );
+}
+
+/**
+ * Format the output of data for this component.
+ */
+function theme_webform_display_textarea($element) {
+  $output = $element['#format'] == 'html' ? str_replace("\n", '<br />', check_plain($element['#value'])) : $element['#value'];
+  if (strlen($output) > 80) {
+    $output = ($element['#format'] == 'html') ? '<div class="webform-long-answer">' . $output . '</div>' : $output;
+  }
+  return $output ? $output : ' ';
 }
 
 /**
Index: components/file.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/file.inc,v
retrieving revision 1.7
diff -u -r1.7 file.inc
--- components/file.inc	12 Jan 2010 22:28:49 -0000	1.7
+++ components/file.inc	14 Jan 2010 05:56:41 -0000
@@ -32,6 +32,20 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_file() {
+  return array(
+    'webform_edit_file' => array(
+      'arguments' => array('form' => NULL),
+    ),
+    'webform_display_file' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_file($component) {
@@ -266,7 +280,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_file($component, $value = NULL) {
-  $form_item[$component['form_key']] = array(
+  $element[$component['form_key']] = array(
     '#type'          => $component['type'],
     '#title'         => $component['name'],
     //'#required'      => $component['mandatory'], // Drupal core bug with required file uploads.
@@ -282,8 +296,8 @@
     ),
     '#webform_component' => $component,
   );
-  $form_item['#weight'] = $component['weight'];
-  $form_item['new'] = array(
+  $element['#weight'] = $component['weight'];
+  $element['new'] = array(
     '#type' => 'hidden',
     '#weight' => $component['weight'],
     '#value' => $component['form_key'],
@@ -293,9 +307,9 @@
   if (isset($value)) {
     $file_data = unserialize($value[0]);
     if (isset($file_data['filename'])) {
-      $form_item['#suffix'] = ' <a href="'. webform_file_url($file_data['filepath']) .'">Download '. $file_data['filename'] .'</a>'. $form_item['#suffix'];
-      $form_item['#description'] = t('Uploading a new file will replace the current file.');
-      $form_item['existing'] = array(
+      $element['#suffix'] = ' ' . l(t('Download !filename', array('!filename' => $file_data['filename'])), webform_file_url($file_data['filepath'])) . (isset($element['#suffix']) ? $element['#suffix'] : '');
+      $element['#description'] = t('Uploading a new file will replace the current file.');
+      $element['existing'] = array(
         '#type' => 'value',
         '#value' => $file_data,
       );
@@ -304,10 +318,10 @@
 
   // Change the 'width' option to the correct 'size' option.
   if ($component['extra']['width'] > 0) {
-    $form_item[$component['form_key']]['#size'] = $component['extra']['width'];
+    $element[$component['form_key']]['#size'] = $component['extra']['width'];
   }
 
-  return $form_item;
+  return $element;
 }
 
 /**
@@ -397,32 +411,29 @@
 }
 
 /**
- * Format the output of emailed data for this component
- *
- * @param $component
- *   A Webform component array.
- * @param $data
- *   A string or array of the submitted data.
- * @return
- *   Textual output to be included in the email.
- */
-function theme_webform_mail_file($component, $value) {
-  $file = is_string($value) ? unserialize($value) : $value;
-  $output = $component['name'] .': '. (!empty($file['filepath']) ? webform_file_url($file['filepath']) : '') ."\n";
-  return $output;
-}
-/**
  * Implementation of _webform_display_component().
  */
-function _webform_display_file($component, $value) {
-  $file_data = unserialize($value[0]);
-  $form_item = _webform_render_file($component, $value);
-  $form_item['#type'] = 'textfield';
-  $form_item['#tree'] = TRUE;
-  $form_item['#attributes']['readonly'] = 'readonly';
-  $form_item['#default_value'] = empty($file_data['filepath']) ? '' : $file_data['filepath'];
+function _webform_display_file($component, $value, $format = 'html') {
+  $file_data = isset($value[0]) ? unserialize($value[0]) : array();
+  return array(
+     '#title' => $component['name'],
+     '#value' => $file_data,
+     '#weight' => $component['weight'],
+     '#theme' => 'webform_display_file',
+     '#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
+     '#post_render' => array('webform_element_wrapper'),
+     '#component' => $component,
+     '#format' => $format,
+  );
+}
 
-  return $form_item;
+/**
+ * Format the output of text data for this component
+ */
+function theme_webform_display_file($element) {
+  $file = $element['#value'];
+  $url = !empty($file) ? webform_file_url($file['filepath']) : t('no upload');
+  return !empty($file) ? ($element['#format'] == 'plain' ? $url : l($file['filename'], $url)) : '';
 }
 
 /**
@@ -440,20 +451,6 @@
 }
 
 /**
- * Implementation of _webform_theme_component().
- */
-function _webform_theme_file() {
-  return array(
-    'webform_edit_file' => array(
-      'arguments' => array('form' => NULL),
-    ),
-    'webform_mail_file' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
-    ),
-  );
-}
-
-/**
  * Implementation of _webform_analysis_component().
  */
 function _webform_analysis_file($component, $sids = array()) {
Index: components/pagebreak.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/pagebreak.inc,v
retrieving revision 1.6
diff -u -r1.6 pagebreak.inc
--- components/pagebreak.inc	12 Jan 2010 22:28:49 -0000	1.6
+++ components/pagebreak.inc	14 Jan 2010 05:56:42 -0000
@@ -20,6 +20,17 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_pagebreak() {
+  return array(
+    'webform_display_pagebreak' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_pagebreak($component) {
@@ -48,38 +59,31 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_pagebreak($component, $value = NULL, $filter = TRUE) {
-  $form_item = array();
-  // Render page breaks as hidden elements so that they can be displayed in
-  // emails as separators.
-  $form_item = array(
+  $element = array(
     '#type' => 'hidden',
     '#value' => $component['name'],
     '#weight' => $component['weight'],
   );
-  return $form_item;
+  return $element;
 }
 
 /**
- * Implementation of _webform_theme_component().
+ * Implementation of _webform_render_component().
  */
-function _webform_theme_pagebreak() {
-  return array(
-    'webform_mail_pagebreak' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
-    ),
+function _webform_display_pagebreak($component, $value = NULL, $format = 'html') {
+  $element = array(
+    '#theme' => 'webform_display_pagebreak',
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#component' => $component,
+    '#format' => $format,
   );
+  return $element;
 }
 
 /**
- * Format the output of e-mailed data for this component.
- *
- * @param $component
- *   A Webform component array.
- * @param $value
- *   A string or array of the submitted data.
- * @return
- *   Textual output to be included in the email.
+ * Format the text output data for this component.
  */
-function theme_webform_mail_pagebreak($component, $value) {
-  return "\n-- ". $component['name'] ." --\n";
+function theme_webform_display_pagebreak($element) {
+  return $element['#format'] == 'html' ? '<h2 class="webform-page">' . check_plain($element['#title']) . '</h2>' : "--" . $element['#title'] . "--\n";
 }
Index: components/time.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/time.inc,v
retrieving revision 1.20
diff -u -r1.20 time.inc
--- components/time.inc	12 Jan 2010 22:28:49 -0000	1.20
+++ components/time.inc	14 Jan 2010 05:56:42 -0000
@@ -28,6 +28,20 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_time() {
+  return array(
+    'webform_time' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'webform_display_time' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_time($component) {
@@ -125,7 +139,7 @@
   for ($i = 0; $i <= 59; $i++) $minutes[$i < 10 ? "0$i" : $i] = $i < 10 ? "0$i" : $i;
   $am_pms = array('am' => t('am'), 'pm' => t('pm'));
 
-  $form_item = array(
+  $element = array(
     '#title' => $component['name'],
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
@@ -137,20 +151,20 @@
     '#webform_component' => $component,
   );
 
-  $form_item['hour'] = array(
+  $element['hour'] = array(
     '#prefix' => '',
     '#type' => 'select',
     '#default_value' => $hour,
     '#options' => $hours,
   );
-  $form_item['minute'] = array(
+  $element['minute'] = array(
     '#prefix' => ':',
     '#type' => 'select',
     '#default_value' => $minute,
     '#options' => $minutes,
   );
   if ($component['extra']['hourformat'] == '12-hour') {
-    $form_item['ampm'] = array(
+    $element['ampm'] = array(
       '#type' => 'radios',
       '#default_value' => $am_pm,
       '#options' => $am_pms,
@@ -158,39 +172,39 @@
   }
 
   if (isset($value)) {
-    $form_item['minute']['#default_value'] = $value[1];
+    $element['minute']['#default_value'] = $value[1];
   
     // Match the hourly data to the hour format.
     if ($value[1]) {
       $timestamp = strtotime($value[0] .':'. $value[1] . (isset($value[2]) ? $value[2] : ''));
       if ($component['extra']['hourformat'] == '24-hour') {
-        $form_item['hour']['#default_value'] = date('H', $timestamp);
+        $element['hour']['#default_value'] = date('H', $timestamp);
       }
       else {
-        $form_item['hour']['#default_value'] = date('g', $timestamp);
-        $form_item['ampm']['#default_value'] = $value[2];
+        $element['hour']['#default_value'] = date('g', $timestamp);
+        $element['ampm']['#default_value'] = $value[2];
       }
     }
   }
 
-  return $form_item;
+  return $element;
 }
 
-function webform_validate_time($form_item, $form_state) {
-  $form_key = $form_item['#webform_component']['form_key'];
-  $name = $form_item['#webform_component']['name'];
+function webform_validate_time($element, $form_state) {
+  $form_key = $element['#webform_component']['form_key'];
+  $name = $element['#webform_component']['name'];
 
   // Check if the user filled the required fields.
-  foreach ($form_item['#webform_component'] == '12-hour' ? array('hour', 'minute', 'ampm') : array('hour', 'minute') as $field_type) {
-    if (!is_numeric($form_item[$field_type]['#value']) && $form_item['#required']) {
+  foreach ($element['#webform_component'] == '12-hour' ? array('hour', 'minute', 'ampm') : array('hour', 'minute') as $field_type) {
+    if (!is_numeric($element[$field_type]['#value']) && $element['#required']) {
       form_set_error($form_key, t('%field field is required.', array('%field' => $name)));
       return;
     }
   }
 
   // Check for a valid time.
-  if ($form_item['hour']['#value'] !== '' || $form_item['minute']['#value'] !== '') {
-    if (!is_numeric($form_item['hour']['#value']) || !is_numeric($form_item['minute']['#value']) || (isset($form_item['ampm']) && $form_item['ampm']['#value'] === '')) {
+  if ($element['hour']['#value'] !== '' || $element['minute']['#value'] !== '') {
+    if (!is_numeric($element['hour']['#value']) || !is_numeric($element['minute']['#value']) || (isset($element['ampm']) && $element['ampm']['#value'] === '')) {
       form_error($form_key, t('Entered %name is not a valid time.', array('%name' => $name)));
       return;
     }
@@ -200,65 +214,43 @@
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_time($component, $value) {
-  $form_item = _webform_render_time($component, $value);
-  $form_item['minute']['#default_value'] = $value[1];
-  $form_item['minute']['#disabled'] = TRUE;
-  $form_item['hour']['#disabled'] = TRUE;
-  $form_item['ampm']['#disabled'] = TRUE;
-
-  // Match the hourly data to the hour format.
-  if ($value[1]) {
-    $timestamp = strtotime($value[0] .':'. $value[1] . (isset($value[2]) ? $value[2] : ''));
-    if ($component['extra']['hourformat'] == '24-hour') {
-      $form_item['hour']['#default_value'] = date('H', $timestamp);
-    }
-    else {
-      $form_item['hour']['#default_value'] = date('g', $timestamp);
-      $form_item['ampm']['#default_value'] = $value[2];
-    }
-  }
-  return $form_item;
+function _webform_display_time($component, $value, $format = 'html') {
+  $value = array(
+    'hour' => isset($value[0]) ? $value[0] : NULL,
+    'minute' => isset($value[1]) ? $value[1] : NULL,
+    'ampm' => isset($value[2]) ? $value[2] : NULL,
+  );
+
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_time',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#component' => $component,
+    '#format' => $format,
+    '#hourformat' => $component['extra']['hourformat'],
+    '#value' => $value,
+  );
 }
 
 /**
- * Format the output of e-mailed data for this component
- *
- * @param $component
- *   A Webform component array.
- * @param $data
- *   A string or array of the submitted data
- * @return
- *   Textual output to be included in the email.
+ * Format the output of data for this component.
  */
-function theme_webform_mail_time($component, $value) {
-  $output = $component['name'] .':';
-  if ($value['hour'] && $value['minute']) {
-    if ($component['extra']['hourformat'] == '24-hour') {
-      $output .= ' '. $value['hour'] .':'. $value['minute'];
+function theme_webform_display_time($element) {
+  $output = ' ';
+  if ($element['#value']['hour'] && $element['#value']['minute']) {
+    if ($element['#hourformat'] == '24-hour') {
+      $output = $element['#value']['hour'] .':'. $element['#value']['minute'];
     }
     else {
-      $output .= ' '. $value['hour'] .':'. $value['minute'] .' '. $value['ampm'];
+      $output = $element['#value']['hour'] .':'. $element['#value']['minute'] .' '. $element['#value']['ampm'];
     }
   }
   return $output;
 }
 
 /**
- * Implementation of _webform_theme_component().
- */
-function _webform_theme_time() {
-  return array(
-    'webform_time' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'webform_mail_time' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
-    ),
-  );
-}
-
-/**
  * Implementation of _webform_analysis_component().
  */
 function _webform_analysis_time($component, $sids = array()) {
Index: components/fieldset.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/fieldset.inc,v
retrieving revision 1.8
diff -u -r1.8 fieldset.inc
--- components/fieldset.inc	12 Jan 2010 22:28:49 -0000	1.8
+++ components/fieldset.inc	14 Jan 2010 05:56:41 -0000
@@ -50,7 +50,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_fieldset($component, $value = NULL, $filter = TRUE) {
-  $form_item = array(
+  $element = array(
     '#type'          => $component['type'],
     '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
     '#weight'        => $component['weight'],
@@ -60,15 +60,28 @@
     '#attributes'    => array('class' => 'webform-component-'. $component['type'], 'id' => 'webform-component-'. $component['form_key']),
   );
 
-  return $form_item;
+  return $element;
 }
 
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_fieldset($component, $value) {
-  $form_item = _webform_render_fieldset($component, $value);
-  return $form_item;
+function _webform_display_fieldset($component, $value, $format = 'html') {
+  if ($format == 'text') {
+    $element = array(
+      '#title' => $component['name'],
+      '#post_render' => array('webform_element_wrapper'),
+      '#theme_wrappers' => array('webform_element_text'),
+    );
+  }
+  else {
+    $element = _webform_render_fieldset($component, $value);
+  }
+
+  $element['#component'] = $component;
+  $element['#format'] = $format;
+
+  return $element;
 }
 
 /**
Index: components/date.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/date.inc,v
retrieving revision 1.20
diff -u -r1.20 date.inc
--- components/date.inc	12 Jan 2010 22:28:49 -0000	1.20
+++ components/date.inc	14 Jan 2010 05:56:41 -0000
@@ -29,6 +29,20 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_date() {
+  return array(
+    'webform_date' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'webform_display_date' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_date($component) {
@@ -92,7 +106,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_date($component, $value = NULL) {
-  $form_item = array(
+  $element = array(
     '#title' => $component['name'],
     '#weight' => $component['weight'],
     '#type' => 'date',
@@ -106,12 +120,12 @@
   );
 
   if (isset($value)) {
-    $form_item['month']['#default_value'] = $value[0];
-    $form_item['day']['#default_value'] = $value[1];
-    $form_item['year']['#default_value'] = $value[2];
+    $element['month']['#default_value'] = $value[0];
+    $element['day']['#default_value'] = $value[1];
+    $element['year']['#default_value'] = $value[2];
   }
 
-  return $form_item;
+  return $element;
 }
 
 /**
@@ -211,28 +225,28 @@
 /**
  * Element validation for Webform date fields.
  */
-function webform_validate_date($form_item, $form_state) {
-  $component = $form_item['#webform_component'];
+function webform_validate_date($element, $form_state) {
+  $component = $element['#webform_component'];
   $form_key = $component['form_key'];
   $name = $component['name'];
 
   // Check if the user filled the required fields.
   foreach (array('day', 'month', 'year') as $field_type) {
-    if (!is_numeric($form_item[$field_type]['#value']) && $form_item['#required']) {
+    if (!is_numeric($element[$field_type]['#value']) && $element['#required']) {
       form_set_error($form_key, t('!name field is required.', array('!name' => $name)));
       return;
     }
   }
   // Check for a valid date.
-  if ($form_item['month']['#value'] !== '' || $form_item['day']['#value'] !== '' || $form_item['year']['#value'] !== '') {
-    if (!checkdate((int)$form_item['month']['#value'], (int)$form_item['day']['#value'], (int)$form_item['year']['#value'])) {
+  if ($element['month']['#value'] !== '' || $element['day']['#value'] !== '' || $element['year']['#value'] !== '') {
+    if (!checkdate((int)$element['month']['#value'], (int)$element['day']['#value'], (int)$element['year']['#value'])) {
       form_set_error($form_key, t('Entered !name is not a valid date.', array('!name' => $name)));
       return;
     }
   }
   // Check the date is between allowed years.
-  if ($form_item['year']['#value'] !== '' && is_numeric($component['extra']['year_start']) && is_numeric($component['extra']['year_end'])) {
-    if ($form_item['year']['#value'] < $component['extra']['year_start'] || $form_item['year']['#value'] > $component['extra']['year_end']) {
+  if ($element['year']['#value'] !== '' && is_numeric($component['extra']['year_start']) && is_numeric($component['extra']['year_end'])) {
+    if ($element['year']['#value'] < $component['extra']['year_start'] || $element['year']['#value'] > $component['extra']['year_end']) {
       form_set_error($form_key .'][year', t('The entered date needs to be between the years @start and @end.', array('@start' => $component['extra']['year_start'], '@end' => $component['extra']['year_end'])));
       return;
     }
@@ -251,44 +265,40 @@
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_date($component, $value) {
-  $form_item = _webform_render_date($component, $value);
-  $form_item['month']['#default_value'] = $value[0];
-  $form_item['day']['#default_value'] = $value[1];
-  $form_item['year']['#default_value'] = $value[2];
-  $form_item['#disabled'] = TRUE;
-  return $form_item;
+function _webform_display_date($component, $value, $format = 'html') {
+  $value = array(
+    'month' => isset($value[0]) ? $value[0] : NULL,
+    'day' => isset($value[1]) ? $value[1] : NULL,
+    'year' => isset($value[2]) ? $value[2] : NULL,
+  );
+
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_date',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#component' => $component,
+    '#format' => $format,
+    '#value' => $value,
+  );
 }
 
 /**
- * Format the output of e-mailed data for this component.
+ * Format the text output for this component.
  */
-function theme_webform_mail_date($component, $value) {
-  $output = $component['name'] .':';
-  if ($value[0] && $value[1]) {
-    $timestamp = strtotime($value[0] .'/'. $value[1] .'/'. $value[2]);
+function theme_webform_display_date($element) {
+  $output = ' ';
+  if ($element['#value']) {
+    $timestamp = strtotime($element['#value']['month'] .'/'. $element['#value']['day'] .'/'. $element['#value']['year']);
     $format = webform_date_format('medium');
-    $output .= ' '. format_date($timestamp, 'custom', $format);
+    $output = format_date($timestamp, 'custom', $format, 0);
   }
 
   return $output;
 }
 
 /**
- * Implementation of _webform_theme_component().
- */
-function _webform_theme_date() {
-  return array(
-    'webform_date' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'webform_mail_date' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
-    ),
-  );
-}
-
-/**
  * Implementation of _webform_analysis_component().
  */
 function _webform_analysis_date($component, $sids = array()) {
Index: components/markup.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/markup.inc,v
retrieving revision 1.9
diff -u -r1.9 markup.inc
--- components/markup.inc	12 Jan 2010 22:28:49 -0000	1.9
+++ components/markup.inc	14 Jan 2010 05:56:42 -0000
@@ -48,7 +48,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_markup($component, $value = NULL, $filter = TRUE) {
-  $form_item = array(
+  $element = array(
     '#type'   => 'markup',
     '#title'  => $component['name'],
     '#weight' => $component['weight'],
@@ -59,16 +59,16 @@
   );
 
   // TODO: Remove when #markup becomes available in D7.
-  $form_item['#value'] = $form_item['#markup'];
+  $element['#value'] = $element['#markup'];
 
-  return $form_item;
+  return $element;
 }
 
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_markup($component, $value) {
-  return _webform_render_markup($component, $value);
+function _webform_display_markup($component, $value, $format = 'html') {
+  return array();
 }
 
 /**
Index: components/grid.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/grid.inc,v
retrieving revision 1.7
diff -u -r1.7 grid.inc
--- components/grid.inc	12 Jan 2010 22:28:49 -0000	1.7
+++ components/grid.inc	14 Jan 2010 05:56:41 -0000
@@ -27,6 +27,21 @@
   );
 }
 
+
+/**
+ * Implementation of _webform_help_grid().
+ */
+function _webform_theme_grid() {
+  return array(
+    'webform_grid' => array(
+      'arguments' => array('grid_element' => NULL),
+    ),
+    'webform_display_grid' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
 /**
  * Implementation of _webform_edit_component().
  */
@@ -71,7 +86,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_grid($component, $value = NULL, $filter = TRUE) {
-  $form_item = array(
+  $element = array(
     '#title' => $component['name'],
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
@@ -107,7 +122,7 @@
   foreach ($questions as $question) {
     if ($question != '') {
       // Remove quotes from keys to prevent HTML breakage.
-      $form_item[str_replace(array('"', "'"), '', $question)] = array(
+      $element[str_replace(array('"', "'"), '', $question)] = array(
         '#title'         => $question,
         '#required'      => $component['mandatory'],
         '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
@@ -120,23 +135,86 @@
 
   if (isset($value)) {
     $cid = 0;
-    foreach (element_children($form_item) as $key) {
-      $form_item[$key]['#default_value'] = $value[$cid++];
+    foreach (element_children($element) as $key) {
+      $element[$key]['#default_value'] = $value[$cid++];
     }
   }
 
-  return $form_item;
+  return $element;
 }
 
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_grid($component, $value) {
-  $form_item = _webform_render_grid($component, $value);
-  foreach (element_children($form_item) as $key) {
-    $form_item[$key]['#disabled'] = TRUE;
+function _webform_display_grid($component, $value, $format = 'html') {
+  $questions = _webform_grid_options($component['extra']['questions']);
+  $options = _webform_grid_options($component['extra']['options']);
+
+  $element = array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#component' => $component,
+    '#format' => $format,
+    '#questions' => $questions,
+    '#options' => $options,
+    '#theme' => 'webform_display_grid',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+  );
+
+  $cid = 0;
+  foreach ($questions as $question) {
+    if ($question != '') {
+      // Remove quotes from keys to prevent HTML breakage.
+      $element[str_replace(array('"', "'"), '', $question)] = array(
+        '#title' => $question,
+        '#value' => isset($value[$cid]) ? $value[$cid] : NULL,
+      );
+    }
+    $cid++;
+  }
+
+  return $element;
+}
+
+/**
+ * Format the text output for this component.
+ */
+function theme_webform_display_grid($element) {
+  $component = $element['#component'];
+  $format = $element['#format'];
+
+  if ($format == 'html') {
+    $rows = array();
+    $header = array('');
+    foreach ($element['#options'] as $option) {
+      $header[] = array('data' => check_plain($option), 'class' => 'checkbox');
+    }
+    foreach (element_children($element) as $key) {
+      $row = array();
+      $row[] = check_plain($element[$key]['#title']);
+      foreach ($element['#options'] as $option_value => $option_label) {
+        if ($option_value == $element[$key]['#value']) {
+          $row[] = array('data' => '<strong>X</strong>', 'class' => 'checkbox');
+        }
+        else {
+          $row[] = '&nbsp';
+        }
+      }
+      $rows[] = $row;
+    }
+
+    $output = theme('table', $header, $rows, array('class' => 'webform-grid'));
   }
-  return $form_item;
+  else {
+    $items = array();
+    foreach (element_children($element) as $key) {
+      $items[] = ' - ' . $element[$key]['#title'] . ': ' . $element[$key]['#value'];
+    }
+    $output = implode("\n", $items);
+  }
+
+  return $output;
 }
 
 /**
@@ -175,38 +253,6 @@
 
   return $ordered_value;
 }
-/**
- * Format the output of e-mailed data for this component.
- *
- * @param $component
- *   A Webform component array.
- * @param $value
- *   A string or array of the submitted data.
- * @return
- *   Textual output to be included in the email.
- */
-function theme_webform_mail_grid($component, $value) {
-  $questions = _webform_grid_options($component['extra']['questions']);
-  $output = $component['name'] .":\n";
-  foreach ($questions as $key => $question) {
-    $output .= '  - '. $question .':'. ($value[$question] == '' ? '' : ' '. $value[$question]) ."\n";
-  }
-  return $output;
-}
-
-/**
- * Implementation of _webform_help_grid().
- */
-function _webform_theme_grid() {
-  return array(
-    'webform_grid' => array(
-      'arguments' => array('grid_element' => NULL),
-    ),
-    'webform_mail_grid' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
-    ),
-  );
-}
 
 /**
  * Implementation of _webform_analysis_component().
@@ -308,17 +354,17 @@
   return $return;
 }
 
-function theme_webform_grid($grid_element) {
+function theme_webform_grid($element) {
   $rows = array();
   $header = array('');
   $first = TRUE;
-  foreach (element_children($grid_element) as $key) {
-    $question_element = $grid_element[$key];
+  foreach (element_children($element) as $key) {
+    $question_element = $element[$key];
 
     // Set the header for the table.
     if ($first) {
       foreach ($question_element['#options'] as $option) {
-        $header[] = $option;
+        $header[] = array('data' => $option, 'class' => 'checkbox');
       }
       $first = FALSE;
     }
@@ -330,12 +376,12 @@
     $radios = expand_radios($question_element);
     foreach (element_children($radios) as $key) {
       unset($radios[$key]['#title']);
-      $row[] = drupal_render($radios[$key]);
+      $row[] = array('data' => drupal_render($radios[$key]), 'class' => 'checkbox');
     }
     $rows[] = $row;
   }
 
-  return theme('form_element', $grid_element, theme('table', $header, $rows, array('class' => 'webform-grid')));
+  return theme('form_element', $element, theme('table', $header, $rows, array('class' => 'webform-grid')));
 }
 
 /**
Index: components/select.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/select.inc,v
retrieving revision 1.28
diff -u -r1.28 select.inc
--- components/select.inc	12 Jan 2010 22:28:49 -0000	1.28
+++ components/select.inc	14 Jan 2010 05:56:42 -0000
@@ -28,6 +28,17 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_select() {
+  return array(
+    'webform_display_select' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_select($component) {
@@ -119,7 +130,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_select($component, $value = NULL, $filter = TRUE) {
-  $form_item = array(
+  $element = array(
     '#title'         => $component['name'],
     '#required'      => $component['mandatory'],
     '#weight'        => $component['weight'],
@@ -137,22 +148,22 @@
   }
 
   // Set the component options.
-  $form_item['#options'] = $options;
+  $element['#options'] = $options;
 
   // Set the default value.
   if (isset($value)) {
     if ($component['extra']['multiple'] === 'Y') {
       // Set the value as an array.
-      $form_item['#default_value'] = array();
+      $element['#default_value'] = array();
       foreach ((array) $value as $key => $option_value) {
-        $form_item['#default_value'][] = $option_value;
+        $element['#default_value'][] = $option_value;
       }
     }
     else {
       // Set the value as a single string.
-      $form_item['#default_value'] = '';
+      $element['#default_value'] = '';
       foreach ((array) $value as $option_value) {
-        $form_item['#default_value'] = $option_value;
+        $element['#default_value'] = $option_value;
       }
     }
   }
@@ -161,34 +172,34 @@
     if ($component['extra']['multiple'] === 'Y') {
       $varray = array_filter(explode(',', $default_value));
       foreach ($varray as $key => $v) {
-        $form_item['#default_value'][] = $v;
+        $element['#default_value'][] = $v;
       }
     }
     else {
-      $form_item['#default_value'] = $default_value;
+      $element['#default_value'] = $default_value;
     }
   }
 
   if ($component['extra']['aslist'] === 'Y') {
     // Set display as a select list:
-    $form_item['#type'] = 'select';
+    $element['#type'] = 'select';
     if ($component['extra']['multiple'] === 'Y') {
-      $form_item['#multiple'] = TRUE;
+      $element['#multiple'] = TRUE;
     }
   }
   else {
     if ($component['extra']['multiple'] === 'Y') {
       // Set display as a checkbox set.
-      $form_item['#type'] = 'checkboxes';
+      $element['#type'] = 'checkboxes';
       // Drupal 6 hack to properly render on multipage forms.
-      $form_item['#process'] = array('webform_expand_checkboxes');
+      $element['#process'] = array('webform_expand_checkboxes');
     }
     else {
       // Set display as a radio set.
-      $form_item['#type'] = 'radios';
+      $element['#type'] = 'radios';
     }
   }
-  return $form_item;
+  return $element;
 }
 
 /**
@@ -216,24 +227,17 @@
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_select($component, $value) {
-  $form_item = _webform_render_select($component, $value);
-  if ($component['extra']['multiple'] === 'Y') {
-    // Set the value as an array.
-    $form_item['#default_value'] = array();
-    foreach ((array) $value as $key => $value) {
-      $form_item['#default_value'][] = $value;
-    }
-  }
-  else {
-    // Set the value as a single string.
-    $form_item['#default_value'] = '';
-    foreach ((array) $value as $value) {
-      $form_item['#default_value'] = $value;
-    }
-  }
-  $form_item['#disabled'] = TRUE;
-  return $form_item;
+function _webform_display_select($component, $value, $format = 'html') {
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_select',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#component' => $component,
+    '#format' => $format,
+    '#value' => $value,
+  );
 }
 
 /**
@@ -362,48 +366,47 @@
 }
 
 /**
- * Format the output of e-mailed data for this component.
- *
- * @param $component
- *   A Webform component array.
- * @param $value
- *   A string or array of the submitted data.
- * @return
- *   Textual output to be included in the email.
+ * Format the text output for this component.
  */
-function theme_webform_mail_select($component, $value) {
+function theme_webform_display_select($element) {
+  $component = $element['#component'];
+
   // Convert submitted 'safe' values to un-edited, original form.
   $options = _webform_select_options($component['extra']['items'], TRUE);
 
-  // Generate the output.
-  $output = '';
+  $items = array();
   if ($component['extra']['multiple']) {
-    $output .= $component['name'] .":\n";
-    foreach ((array) $value as $option_value) {
-      if ($option_value) {
-        if ($options[$option_value]) {
-          $output .= '    - '. $options[$option_value] ."\n";
+    foreach ((array) $element['#value'] as $option_value) {
+      if ($option_value !== '') {
+        if (isset($options[$option_value])) {
+          $items[] = $options[$option_value];
         }
       }
     }
   }
   else {
-    if ($value !== '' && $options[$value]) {
-      $output .= $component['name'] .": ". $options[$value] ."\n";
+    if (isset($element['#value'][0]) && $element['#value'][0] !== '' && $options[$element['#value'][0]]) {
+      $items[] = $options[$element['#value'][0]];
     }
   }
-  return $output;
-}
 
-/**
- * Implementation of _webform_theme_component().
- */
-function _webform_theme_select() {
-  return array(
-    'webform_mail_select' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
-    ),
-  );
+  if ($element['#format'] == 'html') {
+    array_walk($items, 'check_plain');
+    $output = count($items) > 1 ? theme('item_list', $items) : (isset($items[0]) ? $items[0] : ' ');
+  }
+  else {
+    if (count($items) > 1) {
+      foreach ($items as $key => $item) {
+        $items[$key] = ' - ' . $item;
+      }
+      $output = implode("\n", $items);
+    }
+    else {
+      $output = isset($items[0]) ? $items[0] : ' ';
+    }
+  }
+
+  return $output;
 }
 
 /**
Index: components/textfield.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/textfield.inc,v
retrieving revision 1.17
diff -u -r1.17 textfield.inc
--- components/textfield.inc	12 Jan 2010 22:28:49 -0000	1.17
+++ components/textfield.inc	14 Jan 2010 05:56:42 -0000
@@ -31,6 +31,17 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_textfield() {
+  return array(
+    'webform_display_textfield' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_textfield($component) {
@@ -95,7 +106,7 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_textfield($component, $value = NULL, $filter = TRUE) {
-  $form_item = array(
+  $element = array(
     '#type'          => $component['type'],
     '#title'         => $component['name'],
     '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'],
@@ -110,32 +121,40 @@
   );
 
   if ($component['extra']['disabled']) {
-    $form_item['#attributes']['readonly'] = 'readonly';
+    $element['#attributes']['readonly'] = 'readonly';
   }
 
   // Change the 'width' option to the correct 'size' option.
   if ($component['extra']['width'] > 0) {
-    $form_item['#size'] = $component['extra']['width'];
+    $element['#size'] = $component['extra']['width'];
   }
   if ($component['extra']['maxlength'] > 0) {
-    $form_item['#maxlength'] = $component['extra']['maxlength'];
+    $element['#maxlength'] = $component['extra']['maxlength'];
   }
 
   if (isset($value)) {
-    $form_item['#default_value'] = $value[0];
+    $element['#default_value'] = $value[0];
   }
 
-  return $form_item;
+  return $element;
 }
 
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_textfield($component, $value) {
-  $form_item = _webform_render_textfield($component);
-  $form_item['#default_value'] = $value[0];
-  $form_item['#attributes']['readonly'] = 'readonly';
-  return $form_item;
+function _webform_display_textfield($component, $value, $format = 'html') {
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_textfield',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#field_prefix' => $component['extra']['field_prefix'],
+    '#field_suffix' => $component['extra']['field_suffix'],
+    '#component' => $component,
+    '#format' => $format,
+    '#value' => isset($value[0]) ? $value[0] : '',
+  );
 }
 
 /**
@@ -179,29 +198,13 @@
 }
 
 /**
- * Format the output of e-mailed data for this component
- *
- * @param $component
- *   A Webform component array.
- * @param $value
- *   A string or array of the submitted data
- * @return string
- *   Textual output to be included in the email.
- */
-function theme_webform_mail_textfield($component, $value) {
-  $value = $value == '' ? '' : ' '. $component['extra']['field_prefix'] . $value . $component['extra']['field_suffix'];
-  return $component['name'] .':'. $value;
-}
-
-/**
- * Implementation of _webform_theme_component().
+ * Format the output of data for this component.
  */
-function _webform_theme_textfield() {
-  return array(
-    'webform_mail_textfield' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
-    ),
-  );
+function theme_webform_display_textfield($element) {
+  $prefix = $element['#format'] == 'html' ? filter_xss($element['#field_prefix']) : $element['#field_prefix'];
+  $suffix = $element['#format'] == 'html' ? filter_xss($element['#field_suffix']) : $element['#field_suffix'];
+  $value = $element['#format'] == 'html' ? check_plain($element['#value']) : $element['#value'];
+  return $value ? ($prefix . $value . $suffix) : ' ';
 }
 
 /**
Index: components/email.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/email.inc,v
retrieving revision 1.24
diff -u -r1.24 email.inc
--- components/email.inc	12 Jan 2010 22:28:49 -0000	1.24
+++ components/email.inc	14 Jan 2010 05:56:41 -0000
@@ -28,6 +28,17 @@
 }
 
 /**
+ * Implementation of _webform_theme_component().
+ */
+function _webform_theme_email() {
+  return array(
+    'webform_display_email' => array(
+      'arguments' => array('component' => NULL, 'value' => NULL, 'format' => 'plain'),
+    ),
+  );
+}
+
+/**
  * Implementation of _webform_edit_component().
  */
 function _webform_edit_email($component) {
@@ -84,7 +95,7 @@
  */
 function _webform_render_email($component, $value = NULL) {
   global $user;
-  $form_item = array(
+  $element = array(
     '#type'          => 'textfield',
     '#title'         => $component['name'],
     '#default_value' => _webform_filter_values($component['value']),
@@ -100,19 +111,19 @@
   );
 
   if (isset($value)) {
-    $form_item['#default_value'] = $value[0];
+    $element['#default_value'] = $value[0];
   }
 
   if ($component['extra']['disabled']) {
-    $form_item['#attributes']['readonly'] = 'readonly';
+    $element['#attributes']['readonly'] = 'readonly';
   }
 
   // Change the 'width' option to the correct 'size' option.
   if ($component['extra']['width'] > 0) {
-    $form_item['#size'] = $component['extra']['width'];
+    $element['#size'] = $component['extra']['width'];
   }
 
-  return $form_item;
+  return $element;
 }
 
 /**
@@ -136,11 +147,25 @@
 /**
  * Implementation of _webform_display_component().
  */
-function _webform_display_email($component, $value) {
-  $form_item = _webform_render_email($component, $value);
-  $form_item['#default_value'] = $value[0];
-  $form_item['#attributes']['readonly'] = 'readonly';
-  return $form_item;
+function _webform_display_email($component, $value, $format = 'html') {
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_email',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#component' => $component,
+    '#format' => $format,
+    '#value' => isset($value[0]) ? $value[0] : '',
+  );
+}
+
+/**
+ * Format the text output for this component.
+ */
+function theme_webform_display_email($element) {
+  $element['#value'] = empty($element['#value']) ? ' ' : $element['#value'];
+  return $element['#format'] == 'html' ? check_plain($element['#value']) : $element['#value'];
 }
 
 /**
Index: webform.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.module,v
retrieving revision 1.152
diff -u -r1.152 webform.module
--- webform.module	12 Jan 2010 22:28:49 -0000	1.152
+++ webform.module	14 Jan 2010 05:56:41 -0000
@@ -248,30 +248,35 @@
   $items['node/%webform_menu/submission/%webform_menu_submission'] = array(
     'title' => 'Webform submission',
     'load arguments' => array(1),
-    'page callback' => 'webform_client_form_load',
-    'page arguments' => array(1, 3, FALSE, FALSE),
+    'page callback' => 'webform_submission_page',
+    'page arguments' => array(1, 3, 'html'),
+    'title callback' => 'webform_submission_title',
+    'title arguments' => array(1, 3),
     'access callback' => 'webform_submission_access',
     'access arguments' => array(1, 3, 'view'),
+    'file' => 'includes/webform.submissions.inc',
     'type' => MENU_CALLBACK,
   );
   $items['node/%webform_menu/submission/%webform_menu_submission/view'] = array(
     'title' => 'View',
     'load arguments' => array(1),
-    'page callback' => 'webform_client_form_load',
-    'page arguments' => array(1, 3, FALSE, FALSE),
+    'page callback' => 'webform_submission_page',
+    'page arguments' => array(1, 3, 'html'),
     'access callback' => 'webform_submission_access',
     'access arguments' => array(1, 3, 'view'),
     'weight' => 0,
+    'file' => 'includes/webform.submissions.inc',
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
   $items['node/%webform_menu/submission/%webform_menu_submission/edit'] = array(
     'title' => 'Edit',
     'load arguments' => array(1),
-    'page callback' => 'webform_client_form_load',
-    'page arguments' => array(1, 3, TRUE, FALSE),
+    'page callback' => 'webform_submission_page',
+    'page arguments' => array(1, 3, 'form'),
     'access callback' => 'webform_submission_access',
     'access arguments' => array(1, 3, 'edit'),
     'weight' => 1,
+    'file' => 'includes/webform.submissions.inc',
     'type' => MENU_LOCAL_TASK,
   );
   $items['node/%webform_menu/submission/%webform_menu_submission/delete'] = array(
@@ -282,6 +287,7 @@
     'access callback' => 'webform_submission_access',
     'access arguments' => array(1, 3, 'delete'),
     'weight' => 2,
+    'file' => 'includes/webform.submissions.inc',
     'type' => MENU_LOCAL_TASK,
   );
 
@@ -447,16 +453,19 @@
       'template' => 'templates/webform-confirmation',
       'pattern' => 'webform_confirmation_[0-9]+',
     ),
+    'webform_element' => array(
+      'arguments' => array('element' => NULL, 'value' => NULL),
+    ),
+    'webform_element_text' => array(
+      'arguments' => array('element' => NULL, 'value' => NULL),
+    ),
     'webform_mail_message' => array(
-      'arguments' => array('form_values' => NULL, 'node' => NULL, 'sid' => NULL, 'cid' => NULL),
+      'arguments' => array('node' => NULL, 'submission' => NULL, 'cid' => NULL),
       'template' => 'templates/webform-mail',
       'pattern' => 'webform_mail(_[0-9]+)?',
     ),
-    'webform_mail_fields' => array(
-      'arguments' => array('cid' => NULL, 'value' => NULL, 'node' => NULL, 'indent' => NULL),
-    ),
     'webform_mail_headers' => array(
-      'arguments' => array('form_values' => NULL, 'node' => NULL, 'sid' => NULL, 'cid' => NULL),
+      'arguments' => array('node' => NULL, 'submission' => NULL, 'cid' => NULL),
       'pattern' => 'webform_mail_headers_[0-9]+',
     ),
     'webform_token_help' => array(
@@ -507,6 +516,21 @@
     'webform_results_table' => array(
       'arguments' => array('node' => NULL, 'components' => NULL, 'submissions' => NULL, 'node' => NULL, 'total_count' => NULL, 'pager_count' => NULL),
     ),
+    // webform_submissions.inc
+    'webform_submission_page' => array(
+      'arguments' => array('submission' => NULL, 'submission_navigation' => NULL, 'submission_information' => NULL),
+      'template' => 'templates/webform-submission-page',
+    ),
+    'webform_submission_information' => array(
+      'arguments' => array('node' => NULL, 'submission' => NULL),
+      'template' => 'templates/webform-submission-information',
+      'file' => 'includes/webform.submissions.inc',
+    ),
+    'webform_submission_navigation' => array(
+      'arguments' => array('node' => NULL, 'submission' => NULL, 'mode' => NULL),
+      'template' => 'templates/webform-submission-navigation',
+      'file' => 'includes/webform.submissions.inc',
+    ),
   );
 
   // Theme functions in all components.
@@ -930,7 +954,7 @@
   }
 
   // Render the form and generate the output.
-  $form = drupal_get_form('webform_client_form_'. $node->nid, $node, $submission, $enabled, $is_draft);
+  $form = drupal_get_form('webform_client_form_'. $node->nid, $node, $submission, $is_draft);
   $output = theme('webform_view', $node, $teaser, $page, $form, $enabled);
 
   // Remove the surrounding <form> tag if this is a preview.
@@ -1044,14 +1068,7 @@
 function webform_mail($key, &$message, $params) {
   $message['headers'] = array_merge($message['headers'], $params['headers']);
   $message['subject'] = $params['subject'];
-  $message['body'][] = $params['message'];
-}
-
-/**
- * Menu callback to load the appropriate node form.
- */
-function webform_client_form_load($node, $submission, $enabled) {
-  return drupal_get_form('webform_client_form_'. $node->nid, $node, $submission, $enabled);
+  $message['body'][] = drupal_wrap_mail($params['message']);
 }
 
 /**
@@ -1066,9 +1083,6 @@
  * @param $submission
  *   An object containing information about the form submission if we're
  *   displaying a result.
- * @param $enabled
- *   If displaying a result, specify if form elements are enabled for
- *   editing.
  * @param $is_draft
  *   Optional. Set to TRUE if displaying a draft.
  * @param $filter
@@ -1076,62 +1090,9 @@
  *   building the form. Values need to be unfiltered to be editable by
  *   Form Builder.
  */
-function webform_client_form(&$form_state, $node, $submission, $enabled = FALSE, $is_draft = FALSE, $filter = TRUE) {
+function webform_client_form(&$form_state, $node, $submission, $is_draft = FALSE, $filter = TRUE) {
   global $user;
 
-  module_load_include('inc', 'webform', 'includes/webform.components');
-
-  if (isset($submission->sid) && !$is_draft) {
-    drupal_set_title(t('Submission #@sid', array('@sid' => $submission->sid)));
-    webform_set_breadcrumb($node, $submission);
-  }
-
-  // Set a header for navigating results.
-  if ($submission && !$is_draft && (user_access('access all webform results') || (user_access('access own webform results') && $user->uid == $node->uid))) {
-    // Add CSS to display submission info. Don't preprocess because this CSS file is used rarely.
-    drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'module', 'all', FALSE);
-
-    $previous = db_result(db_query('SELECT MAX(sid) FROM {webform_submissions} WHERE nid = %d AND sid < %d', array($node->nid, $submission->sid)));
-    $next = db_result(db_query('SELECT MIN(sid) FROM {webform_submissions} WHERE nid = %d AND sid > %d', array($node->nid, $submission->sid)));
-
-    $form['submission'] = array(
-      '#type' => 'value',
-      '#value' => $submission,
-    );
-    $form['navigation'] = array(
-      '#prefix' => '<div class="webform-submission-navigation">',
-      '#suffix' => '</div>',
-    );
-    $form['navigation']['previous'] = array(
-      '#value' => $previous ? l(t('Previous submission'), 'node/'. $node->nid .'/submission/'. $previous . ($enabled ? '/edit' : '') , array('attributes' => array('class' => 'webform-submission-previous'), 'query' => ($enabled ? 'destination=node/'. $node->nid .'/submission/'. $previous .'/edit' : NULL))) : '<span class="webform-submission-previous">'. t('Previous submission') .'</span>',
-    );
-    $form['navigation']['next'] = array(
-      '#value' => $next ? l(t('Next submission'), 'node/'. $node->nid .'/submission/'. $next . ($enabled ? '/edit' : ''), array('attributes' => array('class' => 'webform-submission-next'), 'query' => ($enabled ? 'destination=node/'. $node->nid .'/submission/'. $next .'/edit' : NULL))) : '<span class="webform-submission-next">'. t('Next submission') .'</span>',
-    );
-
-    $form['submission_info'] = array(
-      '#title' => t('Submission Information'),
-      '#type' => 'fieldset',
-      '#collapsible' => FALSE,
-    );
-    $account = user_load(array('uid' => $submission->uid));
-    $form['submission_info']['user_picture'] = array(
-      '#value' => theme('user_picture', $account),
-    );
-    $form['submission_info']['form'] = array(
-      '#value' => '<div>'. t('Form: !form', array('!form' => l($node->title, 'node/'. $node->nid))) .'</div>',
-    );
-    $form['submission_info']['submitted'] = array(
-      '#value' => '<div>'. t('Submitted by !name', array('!name' => theme('username', $account))) .'</div>',
-    );
-    $form['submission_info']['time'] = array(
-      '#value' => '<div>'. format_date($submission->submitted, 'large') .'</div>',
-    );
-    $form['submission_info']['ip_address'] = array(
-      '#value' => '<div>'. $submission->remote_addr .'</div>',
-    );
-  }
-
   // Add a theme function for this form.
   $form['#theme'] = array('webform_form_'. $node->nid, 'webform_form');
 
@@ -1172,7 +1133,30 @@
     $page_count = $form_state['storage']['page_count'];
     $page_num = $form_state['storage']['page_num'];
 
-    if ((!isset($node->build_mode) || $node->build_mode != NODE_BUILD_PREVIEW) && $enabled) {
+    if ((!isset($node->build_mode) || $node->build_mode != NODE_BUILD_PREVIEW)) {
+      // Recursively add components to the form.
+      foreach ($component_tree['children'] as $cid => $component) {
+        $component_value = isset($form_state['values']['submitted'][$component['form_key']]) ? $form_state['values']['submitted'][$component['form_key']] : NULL;
+        if (_webform_client_form_rule_check($form_state, $component, $page_num)) {
+          _webform_client_form_add_component($component, $component_value, $form['submitted'], $form, $submission, 'form', $page_num, $filter);
+        }
+      }
+
+      // These form details help managing data upon submission.
+      $form['details']['nid'] = array(
+        '#type' => 'value',
+        '#value' => $node->nid,
+      );
+      $form['details']['sid'] = array(
+        '#type' => 'hidden',
+        '#value' => isset($submission->sid) ? $submission->sid : '',
+      );
+      $form['details']['finished'] = array(
+        '#type' => 'hidden',
+        '#value' => isset($submission->draft) ? !$submission->draft : 0,
+      );
+
+      // Add buttons for pages, drafts, and submissions.
       if ($page_count > 1) {
         $next_page = t('Next Page >');
         $prev_page = t('< Previous Page');
@@ -1218,27 +1202,6 @@
         );
       }
     }
-
-    // Recursively add components to the form.
-    foreach ($component_tree['children'] as $cid => $component) {
-      $component_value = isset($form_state['values']['submitted'][$component['form_key']]) ? $form_state['values']['submitted'][$component['form_key']] : NULL;
-      if (_webform_client_form_rule_check($form_state, $component, $page_num)) {
-        _webform_client_form_add_component($component, $component_value, $form['submitted'], $form, $form_state, $submission, $enabled, $filter);
-      }
-    }
-
-    $form['details']['nid'] = array(
-      '#type' => 'value',
-      '#value' => $node->nid,
-    );
-    $form['details']['sid'] = array(
-      '#type' => 'hidden',
-      '#value' => isset($submission->sid) ? $submission->sid : '',
-    );
-    $form['details']['finished'] = array(
-      '#type' => 'hidden',
-      '#value' => isset($submission->draft) ? !$submission->draft : 0,
-    );
   }
 
   return $form;
@@ -1261,18 +1224,43 @@
 }
 
 /**
- * Add a component to the form. Called recursively for fieldsets.
+ * Add a component to a renderable array. Called recursively for fieldsets.
+ *
+ * This function assists in the building of the client form, as well as the
+ * display of results, and the text of e-mails.
+ *
+ * @param $component
+ *   The component to be added to the form.
+ * @param $component_value
+ *   The components current value if known.
+ * @param $parent_fieldset
+ *   The fieldset to which this element will be added.
+ * @param $form
+ *   The entire form array.
+ * @param $form_state
+ *   The form state.
+ * @param $submission
+ *   The Webform submission as retrieved from the database.
+ * @param $format
+ *   The format the form should be displayed as. May be one of the following:
+ *   - form: Show as an editable form.
+ *   - html: Show as HTML results.
+ *   - text: Show as plain text.
+ * @param $filter
+ *   Whether the form element properties should be filtered. Only set to FALSE
+ *   if needing the raw properties for editing.
+ *
+ * @see webform_client_form
+ * @see webform_submission_render
  */
-function _webform_client_form_add_component($component, $component_value, &$parent_fieldset, &$form, &$form_state, $submission, $enabled = FALSE, $filter = TRUE) {
-  $page_num = $form_state['storage']['page_num'];
+function _webform_client_form_add_component($component, $component_value, &$parent_fieldset, &$form, $submission, $format = 'form', $page_num = 0, $filter = TRUE) {
   $cid = $component['cid'];
 
   // Load with submission information if necessary.
-  if (!$enabled) {
+  if ($format != 'form') {
     // This component is display only.
-    $display_function = '_webform_display_'. $component['type'];
     $data = empty($submission->data[$cid]['value']) ? NULL : $submission->data[$cid]['value'];
-    if ($output = webform_component_invoke($component['type'], 'display', $component, $data)) {
+    if ($output = webform_component_invoke($component['type'], 'display', $component, $data, $format)) {
       $parent_fieldset[$component['form_key']] = $output;
     }
   }
@@ -1306,7 +1294,7 @@
   if (isset($component['children']) && is_array($component['children'])) {
     foreach ($component['children'] as $scid => $subcomponent) {
       $subcomponent_value = isset($component_value[$subcomponent['form_key']]) ? $component_value[$subcomponent['form_key']] : NULL;
-      _webform_client_form_add_component($subcomponent, $subcomponent_value, $parent_fieldset[$component['form_key']], $form, $form_state, $submission, $enabled, $filter);
+      _webform_client_form_add_component($subcomponent, $subcomponent_value, $parent_fieldset[$component['form_key']], $form, $submission, $format, $page_num, $filter);
     }
   }
 }
@@ -1494,6 +1482,7 @@
 
   // Perform post processing by components.
   _webform_client_form_submit_process($node, $form_state['values']['submitted']);
+
   // Flatten trees within the submission.
   $form_state['values']['submitted_tree'] = $form_state['values']['submitted'];
   $form_state['values']['submitted'] = _webform_client_form_submit_flatten($node, $form_state['values']['submitted']);
@@ -1533,23 +1522,25 @@
 
   // Check if this form is sending an email.
   if (!$is_draft && !$form_state['values']['details']['finished']) {
+    $submission = webform_get_submission($node->nid, $sid, TRUE);
+
     // Create a themed message for mailing.
     foreach ($node->webform['emails'] as $eid => $email) {
       $cid = is_numeric($email['email']) && isset($node->webform['components'][$email['email']]) ? $email['email'] : 'custom';
 
       // Pass through the theme layer if using the default template.
       if ($email['template'] == 'default') {
-        $email['message'] = theme(array('webform_mail_'. $node->nid, 'webform_mail', 'webform_mail_message'), $form_state['values'], $node, $sid, $cid);
+        $email['message'] = theme(array('webform_mail_'. $node->nid, 'webform_mail', 'webform_mail_message'), $node, $submission, $cid);
       }
       else {
         $email['message'] = $email['template'];
       }
 
       // Replace tokens in the message.
-      $email['message'] = _webform_filter_values($email['message'], $node, $form_state['values'], FALSE, TRUE);
+      $email['message'] = _webform_filter_values($email['message'], $node, $submission, FALSE, TRUE);
 
       // Build the e-mail headers.
-      $email['headers'] = theme(array('webform_mail_headers_'. $node->nid, 'webform_mail_headers'), $form_state['values'], $node, $sid, $cid);
+      $email['headers'] = theme(array('webform_mail_headers_'. $node->nid, 'webform_mail_headers'), $node, $submission, $cid);
 
       // Assemble the FROM string.
       if (isset($email['headers']['From'])) {
@@ -1558,7 +1549,7 @@
         unset($email['headers']['From']);
       }
       else {
-        $email['from'] = webform_format_email_address($email['from_address'], $email['from_name'], $node, $form_state['values']);
+        $email['from'] = webform_format_email_address($email['from_address'], $email['from_name'], $node, $submission);
       }
 
       // Update the subject if set in the themed headers.
@@ -1567,7 +1558,7 @@
         unset($email['headers']['Subject']);
       }
       else {
-        $email['subject'] = webform_format_email_subject($email['subject'], $node, $form_state['values']);
+        $email['subject'] = webform_format_email_subject($email['subject'], $node, $submission);
       }
 
       // Update the to e-mail if set in the themed headers.
@@ -1584,7 +1575,7 @@
 
         // After filtering e-mail addresses with component values, a single value
         // might contain multiple addresses (such as from checkboxes or selects).
-        $address = webform_format_email_address($address, NULL, $node, $form_state['values'], TRUE, FALSE, 'short');
+        $address = webform_format_email_address($address, NULL, $node, $submission, TRUE, FALSE, 'short');
 
         if (is_array($address)) {
           foreach ($address as $new_address) {
@@ -1759,94 +1750,113 @@
 }
 
 /**
- * Check if current user has a draft of this webform, and return the sid.
+ * A Form API #post_render function. Wraps displayed elements in their label.
+ *
+ * Note: this entire function may be removed in Drupal 7, which supports
+ * #theme_wrappers natively.
  */
-function _webform_fetch_draft_sid($nid, $uid) {
-  $result = db_query("SELECT * FROM {webform_submissions} WHERE nid = %d AND uid = %d AND is_draft = 1 ORDER BY submitted DESC", $nid, $uid);
-  $row = db_fetch_array($result);
-  if (isset($row['sid'])) {
-    return (int) $row['sid'];
+function webform_element_wrapper($content, $elements) {
+  if (isset($elements['#theme_wrappers'])) {
+    foreach ($elements['#theme_wrappers'] as $theme_wrapper) {
+      $content = theme($theme_wrapper, $elements, $content);
+    }
   }
-  return FALSE;
+  return $content;
 }
 
 /**
- * Prepare to theme the fields portion of the e-mails sent by webform.
- *
- * This function calls itself recursively to maintain the tree structure of
- * components in the webform. It is called intially by
- * theme_webform_create_mailmessage().
- *
- * @param $cid
- *   The parent component ID we're currently printing.
- * @param $value
- *   The value of the component to be printed. May be an array of other components.
- * @param $node
- *   The full node object.
- * @param $indent
- *   The current amount of indentation being applied to printed components.
- */
-function theme_webform_mail_fields($cid, $value, $node, $indent = "") {
-  $component = $cid ? $node->webform['components'][$cid] : null;
-
-  // Check if this component needs to be included in the email at all.
-  if ($cid && !$component['email'] && !in_array($component['type'], array('markup', 'fieldset', 'pagebreak'))) {
-    return '';
-  }
-
-  // First check for component-level themes.
-  $themed_output = theme('webform_mail_'. $component['type'], $component, $value);
-
-  $message = '';
-  if ($themed_output) {
-    // Indent the output and add to message.
-    $message .= $indent;
-    $themed_output = rtrim($themed_output, "\n");
-    $message .= str_replace("\n", "\n". $indent, $themed_output);
-    $message .= "\n";
-  }
-  // Generic output for single values.
-  elseif (!is_array($value)) {
-    // Note that newlines cannot be preceeded by spaces to display properly in some clients.
-    if ($component['name']) {
-      // If text is more than 60 characters, put it on a new line with space after.
-      $long = (drupal_strlen($indent . $component['name'] . $value)) > 60;
-      $message .= $indent . $component['name'] .':'. (empty($value) ? "\n" : ($long ? "\n$value\n\n" : " $value\n"));
+ * Replacement for theme_form_element().
+ */
+function theme_webform_element($element, $value) {
+  $wrapper_classes = array(
+   'form-item',
+   $element['#format'] == 'html' ? 'webform-display-item' : 'webform-item',
+  );
+  $output = "<div class=\"" . implode(' ', $wrapper_classes) . "\">\n";
+  $required = !empty($element['#required']) ? '<span class="form-required" title="'. t('This field is required.') .'">*</span>' : '';
+
+  if (!empty($element['#title'])) {
+    $title = $element['#title'];
+    if (!empty($element['#id'])) {
+      $output .= ' <label for="'. $element['#id'] .'">'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
+    }
+    else {
+      $output .= ' <label>'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
     }
   }
-  // Else use a generic output for arrays.
-  else {
-    if ($cid != 0) {
-      $message .= $indent . $component['name'] .":\n";
+
+  $output .= " $value\n";
+
+  if (!empty($element['#description'])) {
+    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
+  }
+
+  $output .= "</div>\n";
+
+  return $output;
+}
+
+/**
+ * Output a form element in plain text format.
+ */
+function theme_webform_element_text($element, $value) {
+  $output = '';
+
+  // Output the element title.
+  if (isset($element['#title'])) {
+    if ($element['#component']['type'] == 'fieldset') {
+      $output .= '--' . $element['#title'] . '--';
     }
-    foreach ($value as $k => $v) {
-      foreach ($node->webform['components'] as $local_key => $local_value) {
-        if ($local_value['form_key'] == $k && $local_value['pid'] == $cid) {
-          $form_key = $local_key;
-          break;
-        }
+    elseif (!in_array(substr(0, -1, $element['#title']), array('?', ':', '!', '%', ';', '@'))) {
+      $output .= $element['#title'] . ':';
+    }
+    else {
+      $output .= $element['#title'];
+    }
+  }
+
+  // Wrap long values at 65 characters, allowing for a few fieldset indents.
+  // It's common courtesy to wrap at 75 characters in e-mails.
+  if ($element['#component']['type'] != 'fieldset' && strlen($value) > 65) {
+    $value = wordwrap($value, 65, "\n");
+    $lines = explode("\n", $value);
+    foreach ($lines as $key => $line) {
+      $lines[$key] = '  ' . $line;
+    }
+    $value = implode("\n", $lines);
+  }
+
+  // Add the value to the output.
+  if ($value) {
+    $output .= (strpos($value, "\n") === FALSE ? ' ' : "\n") . $value;
+  }
+
+  // Indent fieldsets.
+  if ($element['#component']['type'] == 'fieldset') {
+    $lines = explode("\n", $output);
+    foreach ($lines as $number => $line) {
+      if (strlen($line)) {
+        $lines[$number] = '  ' . $line;
       }
-      $message .= theme('webform_mail_fields', $form_key, $v, $node, $indent .'  ');
     }
+    $output = implode("\n", $lines);
+    $output .= "\n";
   }
 
-  return ($message);
+  if ($output) {
+    $output .= "\n";
+  }
+
+  return $output;
 }
 
 /**
  * Theme the headers when sending an email from webform.
  *
- * @param $form_values
- *   An array of all form values submitted by the user. The array contains three
- *   keys containing the following:
- *   - submitted: All the submitted values in a single array keyed by webform
- *     component IDs. Useful for simply looping over the values.
- *   - submitted_tree: All the submitted values in a tree-structure array, keyed
- *     by the Form Key values defined by the user.
  * @param $node
  *   The complete node object for the webform.
- * @param $sid
- *   The submission ID of the new submission.
+ * @param $submission
+ *   The webform submission of the user.
  * @param $cid
  *   If you desire to make different e-mail headers depending on the recipient,
  *   you can check this component ID to output different content. This will be
@@ -1857,7 +1867,7 @@
  *   for "From", "To", or "Subject" are set, they will take precedence over
  *   the values set in the webform configuration.
  */
-function theme_webform_mail_headers($form_values, $node, $sid, $cid) {
+function theme_webform_mail_headers($node, $submission, $cid) {
   $headers = array(
     'X-Mailer' => 'Drupal Webform (PHP/'. phpversion() .')',
   );
@@ -1865,6 +1875,18 @@
 }
 
 /**
+ * Check if current user has a draft of this webform, and return the sid.
+ */
+function _webform_fetch_draft_sid($nid, $uid) {
+  $result = db_query("SELECT * FROM {webform_submissions} WHERE nid = %d AND uid = %d AND is_draft = 1 ORDER BY submitted DESC", $nid, $uid);
+  $row = db_fetch_array($result);
+  if (isset($row['sid'])) {
+    return (int) $row['sid'];
+  }
+  return FALSE;
+}
+
+/**
  * Filters all special tokens provided by webform, such as %post and %profile.
  *
  * @param $string
@@ -1908,21 +1930,28 @@
 
   // Submission replacements.
   if (isset($submission) && !array_key_exists('%email_values', $replacements)) {
-    foreach ($submission['submitted'] as $cid => $value) {
+    foreach ($submission->data as $cid => $value) {
+      $component = $node->webform['components'][$cid];
+
       // Find by CID.
-      $replacements['unsafe']['%cid[' . $cid . ']'] = $value;
+      $replacements['unsafe']['%cid[' . $cid . ']'] = drupal_render(webform_component_invoke($component['type'], 'display', $component, $value['value'], 'text'));
 
       // Find by form key.
-      $form_key = $node->webform['components'][$cid]['form_key'];
-      $replacements['unsafe']['%value[' . $form_key . ']'] = $value;
-      $replacements['unsafe']['%label[' . $form_key . ']'] = $node->webform['components'][$cid]['name'];
+      $parents = array($component['form_key']);
+      $pid = $component['pid'];
+      while ($pid) {
+        $parents[] = $node->webform['components'][$pid]['form_key'];
+        $pid = $node->webform['components'][$pid]['pid'];
+      }
+      $form_key = implode('][', array_reverse($parents));
+      $replacements['unsafe']['%email[' . $form_key . ']'] = $replacements['unsafe']['%cid[' . $cid . ']'];
     }
 
     // The entire form tree:
-    $replacements['unsafe']['%email_values'] = theme('webform_mail_fields', 0, $submission['submitted_tree'], $node);
+    $replacements['unsafe']['%email_values'] = webform_submission_render($node, $submission, 'text');
 
     // Submission edit URL.
-    $replacements['unsafe']['%submission_url'] = url('node/'. $node->nid .'/submission/'. $submission['details']['sid'], array('absolute' => TRUE));
+    $replacements['unsafe']['%submission_url'] = url('node/'. $node->nid .'/submission/'. $submission->sid, array('absolute' => TRUE));
   }
 
   // Provide a list of candidates for token replacement.
@@ -2075,10 +2104,9 @@
     }
     if (!empty($submission_keys)) {
       $submission_tokens = array(
-        '%email_values',
         '%submission_url',
-        '%label[key]',
-        '%value[key]',
+        '%email_values',
+        '%email[key]',
         t('Where the key may be any of the following components (do not include quotes):') . theme('item_list', $submission_keys),
       );
     }
Index: webform_hooks.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform_hooks.php,v
retrieving revision 1.2
diff -u -r1.2 webform_hooks.php
--- webform_hooks.php	12 Jan 2010 22:28:49 -0000	1.2
+++ webform_hooks.php	14 Jan 2010 05:56:41 -0000
@@ -238,17 +238,34 @@
  * @param $value
  *   An array of information containing the submission result, directly
  *   correlating to the webform_submitted_data database table schema.
+ * @param $format
+ *   Either 'html' or 'text'. Defines the format that the content should be
+ *   returned as. Make sure that returned content is run through check_plain()
+ *   or other filtering functions when returning HTML.
  * @return
- *   Textual output formatted for human reading.
+ *   A renderable element containing at the very least these properties:
+ *    - #title
+ *    - #weight
+ *    - #component
+ *    - #format
+ *    - #value
+ *   Webform also uses #theme_wrappers to output the end result to the user,
+ *   which will properly format the label and content for use within an e-mail
+ *   (such as wrapping the text) or as HTML (ensuring consistent output).
  */
-function _webform_display_component($component, $value, $enabled = FALSE) {
-  $form_item = _webform_render_component($component, FALSE);
-  $cid = 0;
-  foreach (element_children($form_item) as $key) {
-    $form_item[$key]['#default_value'] = $value[$cid++];
-    $form_item[$key]['#disabled'] = !$enabled;
-  }
-  return $form_item;
+function _webform_display_component($component, $value, $format = 'html') {
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_textfield',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#post_render' => array('webform_element_wrapper'),
+    '#field_prefix' => $component['extra']['field_prefix'],
+    '#field_suffix' => $component['extra']['field_suffix'],
+    '#component' => $component,
+    '#format' => $format,
+    '#value' => isset($value[0]) ? $value[0] : '',
+  );
 }
 
 /**
Index: webform.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.css,v
retrieving revision 1.5
diff -u -r1.5 webform.css
--- webform.css	7 May 2009 22:38:13 -0000	1.5
+++ webform.css	14 Jan 2010 05:56:39 -0000
@@ -1,5 +1,12 @@
 /* $Id: webform.css,v 1.5 2009/05/07 22:38:13 quicksketch Exp $ */
 
+.webform-display-item {
+  margin-top: 0.5em;
+  margin-bottom: 0.5em;
+}
+.webform-display-item label {
+  display: inline;
+}
 .webform-submission-navigation {
   text-align: right;
 }
Index: templates/webform-mail.tpl.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/templates/webform-mail.tpl.php,v
retrieving revision 1.2
diff -u -r1.2 webform-mail.tpl.php
--- templates/webform-mail.tpl.php	17 Jun 2009 23:01:32 -0000	1.2
+++ templates/webform-mail.tpl.php	14 Jan 2010 05:56:43 -0000
@@ -10,8 +10,8 @@
  * "webform-mail.tpl.php" to affect all webform e-mails on your site.
  *
  * Available variables:
- * - $form_values: The values submitted by the user.
  * - $node: The node object for this webform.
+ * - $submission: The webform submission.
  * - $user: The current user submitting the form.
  * - $ip_address: The IP address of the user submitting the form.
  * - $sid: The unique submission ID of this submission.
Index: includes/webform.submissions.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.submissions.inc,v
retrieving revision 1.5
diff -u -r1.5 webform.submissions.inc
--- includes/webform.submissions.inc	12 Jan 2010 22:28:49 -0000	1.5
+++ includes/webform.submissions.inc	14 Jan 2010 05:56:43 -0000
@@ -99,7 +99,6 @@
  *   The submission to be deleted (from webform_submitted_data).
  */
 function webform_submission_delete_form($form_state, $node, $submission) {
-  drupal_set_title(t('Delete Form Submission'));
   webform_set_breadcrumb($node, $submission);
 
   $form = array();
@@ -107,7 +106,7 @@
   $form['submission'] = array('#type' => 'value', '#value' => $submission);
   $question = t('Are you sure you want to delete this submission?');
 
-  return confirm_form($form, $question, isset($_GET['destination']) ? $_GET['destination'] : 'node/'. $node->nid .'/webform-results', NULL, t('Delete'), t('Cancel'));
+  return confirm_form($form, NULL, isset($_GET['destination']) ? $_GET['destination'] : 'node/'. $node->nid .'/webform-results', $question, t('Delete'), t('Cancel'));
 }
 
 function webform_submission_delete_form_submit($form, &$form_state) {
@@ -118,6 +117,56 @@
 }
 
 /**
+ * Menu title callback; Return the submission number as a title.
+ */
+function webform_submission_title($node, $submission) {
+  return t('Submission #@sid', array('@sid' => $submission->sid));
+}
+
+/**
+ * Menu callback; Present a Webform submission page for display or editing.
+ */
+function webform_submission_page($node, $submission, $format) {
+  webform_set_breadcrumb($node, $submission);
+
+  if ($format == 'form') {
+    $output = drupal_get_form('webform_client_form_'. $node->nid, $node, $submission);
+  }
+  else {
+    $output = webform_submission_render($node, $submission, $format);
+  }
+
+  if (user_access('access all webform results') || (user_access('access own webform results') && $user->uid == $node->uid)) {
+    $navigation = theme('webform_submission_navigation', $node, $submission, $format != 'form' ? 'display' : 'form');
+    $information = theme('webform_submission_information', $node, $submission);
+  }
+  else {
+    $navigation = NULL;
+    $information = NULL;
+  }
+
+  return theme('webform_submission_page', $output, $navigation, $information);
+}
+
+/**
+ * Print a Webform submission for display on a page or in an e-mail.
+ */
+function webform_submission_render($node, $submission, $format) {
+  $component_tree = array();
+  $renderable = array();
+  $page_count = 1;
+
+  _webform_components_tree_build($node->webform['components'], $component_tree, 0, $page_count);
+
+  // Recursively add components to the form.
+  foreach ($component_tree['children'] as $cid => $component) {
+    _webform_client_form_add_component($component, NULL, $renderable, $renderable, $submission, $format);
+  }
+
+  return drupal_render($renderable);
+}
+
+/**
  * Return all the submissions for a particular node.
  *
  * @param $nid
@@ -244,7 +293,6 @@
   return $submissions[$nid][$sid];
 }
 
-
 function _webform_submission_spam_check($to, $subject, $from, $headers = array()) {
   $headers = implode('\n', (array)$headers);
   // Check if they are attempting to spam using a bcc or content type hack.
@@ -307,3 +355,20 @@
   // Limit not exceeded.
   return FALSE;
 }
+
+/**
+ * Preprocess function for webform-submission-navigation.tpl.php
+ */
+function template_preprocess_webform_submission_navigation(&$vars) {
+  $vars['previous'] = db_result(db_query('SELECT MAX(sid) FROM {webform_submissions} WHERE nid = %d AND sid < %d', array($vars['node']->nid, $vars['submission']->sid)));
+  $vars['next'] = db_result(db_query('SELECT MIN(sid) FROM {webform_submissions} WHERE nid = %d AND sid > %d', array($vars['node']->nid, $vars['submission']->sid)));
+  $vars['previous_url'] = 'node/' . $vars['node']->nid . '/submission/' . $vars['previous'] . ($vars['mode'] == 'form' ? '/edit' : '');
+  $vars['next_url'] = 'node/' . $vars['node']->nid . '/submission/' . $vars['next'] . ($vars['mode'] == 'form' ? '/edit' : '');
+}
+
+/**
+ * Preprocess function for webform-submission-navigation.tpl.php
+ */
+function template_preprocess_webform_submission_information(&$vars) {
+  $vars['account'] = user_load(array('uid' => $vars['submission']->uid));
+}
Index: includes/webform.components.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.components.inc,v
retrieving revision 1.10
diff -u -r1.10 webform.components.inc
--- includes/webform.components.inc	12 Jan 2010 22:28:49 -0000	1.10
+++ includes/webform.components.inc	14 Jan 2010 05:56:42 -0000
@@ -38,7 +38,7 @@
   $output = '';
 
   // Add CSS and JS. Don't preprocess because these files are used rarely.
-  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'module', 'all', FALSE);
+  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'theme', 'all', FALSE);
   drupal_add_js(drupal_get_path('module', 'webform') .'/webform.js', 'module', 'header', FALSE, TRUE, FALSE);
 
   if (module_exists('form_builder')) {
@@ -165,7 +165,7 @@
  */
 function theme_webform_components_form($form) {
   // Add CSS to display submission info. Don't preprocess because this CSS file is used rarely.
-  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'module', 'all', FALSE);
+  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'theme', 'all', FALSE);
   drupal_add_js(drupal_get_path('module', 'webform') .'/webform.js', 'module', 'header', FALSE, TRUE, FALSE);
 
   drupal_add_tabledrag('webform-components', 'order', 'sibling', 'webform-weight');
Index: includes/webform.emails.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.emails.inc,v
retrieving revision 1.2
diff -u -r1.2 webform.emails.inc
--- includes/webform.emails.inc	12 Jan 2010 07:14:52 -0000	1.2
+++ includes/webform.emails.inc	14 Jan 2010 05:56:43 -0000
@@ -85,7 +85,7 @@
  */
 function theme_webform_emails_form($form) {
   // Add CSS to display submission info. Don't preprocess because this CSS file is used rarely.
-  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'module', 'all', FALSE);
+  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'theme', 'all', FALSE);
   drupal_add_js(drupal_get_path('module', 'webform') .'/webform.js', 'module', 'header', FALSE, TRUE, FALSE);
 
   $node = $form['#node'];
Index: includes/webform.report.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.report.inc,v
retrieving revision 1.7
diff -u -r1.7 webform.report.inc
--- includes/webform.report.inc	12 Jan 2010 22:28:49 -0000	1.7
+++ includes/webform.report.inc	14 Jan 2010 05:56:43 -0000
@@ -119,7 +119,7 @@
 function theme_webform_results_submissions($node, $submissions, $total_count = 0, $pager_count = 0) {
   global $user;
 
-  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css');
+  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'theme', 'all', FALSE);
 
   // This header has to be generated separately so we can add the SQL necessary
   // to sort the results.
@@ -206,7 +206,7 @@
  *   The number of results to be shown per page.
  */
 function theme_webform_results_table($node, $components, $submissions, $total_count, $pager_count) {
-  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css');
+  drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'theme', 'all', FALSE);
 
   $header = array();
   $rows = array();
Index: templates/webform-submission-navigation.tpl.php
===================================================================
RCS file: templates/webform-submission-navigation.tpl.php
diff -N templates/webform-submission-navigation.tpl.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ templates/webform-submission-navigation.tpl.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,30 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Customize the navigation shown when editing or viewing submissions.
+ *
+ * Available variables:
+ * - $node: The node object for this webform.
+ * - $submission: The contents of the webform submission.
+ * - $previous: The previous submission ID.
+ * - $next: The next submission ID.
+ * - $previous_url: The URL of the previous submission.
+ * - $next_url: The URL of the next submission.
+ * - $mode: Either "form" or "display". As the navigation is shown in both uses.
+ */
+?>
+<div class="webform-submission-navigation">
+  <?php if ($previous): ?>
+    <?php print l(t('Previous submission'), $previous_url, array('attributes' => array('class' => 'webform-submission-previous'), 'query' => ($mode == 'form' ? 'destination=' . $previous_url : NULL))); ?>
+  <?php else: ?>
+    <span class="webform-submission-previous"><?php print t('Previous submission'); ?></span>
+  <?php endif; ?>
+
+  <?php if ($next): ?>
+    <?php print l(t('Next submission'), $next_url, array('attributes' => array('class' => 'webform-submission-next'), 'query' => ($mode == 'form' ? 'destination=' . $next_url : NULL))); ?>
+  <?php else: ?>
+    <span class="webform-submission-next"><?php print t('Next submission'); ?></span>
+  <?php endif; ?>
+</div>
Index: templates/webform-submission-information.tpl.php
===================================================================
RCS file: templates/webform-submission-information.tpl.php
diff -N templates/webform-submission-information.tpl.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ templates/webform-submission-information.tpl.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,21 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Customize the header information shown when editing or viewing submissions.
+ *
+ * Available variables:
+ * - $node: The node object for this webform.
+ * - $submission: The contents of the webform submission.
+ * - $account: The user that submitted the form.
+ */
+?>
+<fieldset>
+  <legend><?php print t('Submission information'); ?></legend>
+  <?php print theme('user_picture', $account); ?>
+  <div><?php print t('Form: !form', array('!form' => l($node->title, 'node/' . $node->nid))); ?></div>
+  <div><?php print t('Submitted by !name', array('!name' => theme('username', $account))); ?></div>
+  <div><?php print format_date($submission->submitted, 'large'); ?></div>
+  <div><?php print $submission->remote_addr; ?></div>
+</fieldset>
Index: templates/webform-submission-page.tpl.php
===================================================================
RCS file: templates/webform-submission-page.tpl.php
diff -N templates/webform-submission-page.tpl.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ templates/webform-submission-page.tpl.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,26 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Customize the navigation shown when editing or viewing submissions.
+ *
+ * Available variables:
+ * - $node: The node object for this webform.
+ * - $submission: The contents of the webform submission.
+ * - $previous: The previous submission ID.
+ * - $next: The next submission ID.
+ * - $previous_url: The URL of the previous submission.
+ * - $next_url: The URL of the next submission.
+ * - $mode: Either "form" or "display". As the navigation is shown in both uses.
+ */
+
+drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'theme', 'all', FALSE);
+?>
+
+<?php print $submission_navigation; ?>
+<?php print $submission_information; ?>
+
+<?php print $submission; ?>
+
+<?php print $submission_navigation; ?>
