Index: components/date.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/date.inc,v
retrieving revision 1.47
diff -u -r1.47 date.inc
--- components/date.inc	6 Jan 2011 18:34:54 -0000	1.47
+++ components/date.inc	7 Feb 2011 03:49:36 -0000
@@ -156,6 +156,11 @@
 function webform_expand_date($element) {
   $component = $element['#webform_component'];
 
+  // Accept a string or array value for #default_value.
+  if (isset($element['#default_value']) && is_string($element['#default_value'])) {
+    $element['#default_value'] = webform_date_array($element['#default_value'], 'date');
+  }
+
   // Set defaults according to existing #default_value (set by Form API)
   if (isset($element['#default_value']['month']) || isset($element['#default_value']['day']) || isset($element['#default_value']['year'])) {
     $default_values = array(
Index: components/file.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/file.inc,v
retrieving revision 1.30
diff -u -r1.30 file.inc
--- components/file.inc	12 Jan 2011 06:55:50 -0000	1.30
+++ components/file.inc	7 Feb 2011 03:49:36 -0000
@@ -344,11 +344,15 @@
   $element = $variables['element'];
 
   // Add information about the existing file, if any.
+  if (isset($element['#default_value'])) {
+    $element['_fid']['#value'] = $element['#default_value'];
+  }
   $value = $element['_fid']['#value'] ? $element['_fid']['#value'] : $element['_old']['#value'];
+
   if ($value && ($file = webform_get_file($value))) {
     $firstchild = array_shift(array_keys($element));
-    $element[$firstchild]['#suffix'] = ' ' . l(t('Download !filename', array('!filename' => webform_file_name($file->filepath))), webform_file_url($file->filepath)) . (isset($element['#suffix']) ? $element['#suffix'] : '');
-    $element[$firstchild]['#description'] = ' <div class="webform-newfile-message">'. t('Uploading a new file will replace the current file.') .'</div>'. $element[$firstchild]['#description'];
+    $element[$firstchild]['#suffix'] = ' ' . l(t('Download !filename', array('!filename' => webform_file_name($file->uri))), webform_file_url($file->uri)) . (isset($element['#suffix']) ? $element['#suffix'] : '');
+    $element[$firstchild]['#description'] = '<div class="webform-newfile-message">'. t('Uploading a new file will replace the current file.') . '</div>' . (isset($element[$firstchild]['#description']) ? $element[$firstchild]['#description'] : '');
   }
 
   // Add the required asterisk.
Index: components/select.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/select.inc,v
retrieving revision 1.66
diff -u -r1.66 select.inc
--- components/select.inc	12 Jan 2011 22:07:34 -0000	1.66
+++ components/select.inc	7 Feb 2011 03:49:36 -0000
@@ -459,7 +459,7 @@
           unset($value[$key]);
         }
         else {
-          $return[] = $key;
+          $return[] = $option_value;
         }
       }
       // Handle options that are added through the "other" field.
Index: components/time.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/time.inc,v
retrieving revision 1.38
diff -u -r1.38 time.inc
--- components/time.inc	18 Oct 2010 07:21:10 -0000	1.38
+++ components/time.inc	7 Feb 2011 03:49:37 -0000
@@ -82,6 +82,20 @@
  * Implementation of _webform_render_component().
  */
 function _webform_render_time($component, $value = NULL, $filter = TRUE) {
+  $element = array(
+    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
+    '#required' => $component['mandatory'],
+    '#weight' => $component['weight'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#element_validate' => array('webform_validate_time'),
+    '#hourformat' => $component['extra']['hourformat'],
+    '#after_build' => array('webform_expand_time'),
+    '#theme' => 'webform_time',
+    '#theme_wrappers' => array('webform_element'),
+    '#webform_component' => $component,
+  );
+
   if (drupal_strlen($component['value']) > 0) {
     // Adjust the time based on the user or site timezone.
     if (variable_get('configurable_timezones', 1) && $component['extra']['timezone'] == 'user') {
@@ -103,6 +117,10 @@
     );
   }
 
+  if (!empty($value[0])) {
+    $default_values = webform_date_array($value[0], 'time');
+  }
+
   $first_hour = 0;
   $last_hour = 23;
   if ($component['extra']['hourformat'] == '12-hour') {
@@ -119,19 +137,6 @@
   for ($i = 0; $i <= 59; $i++) $minutes[$i] = $i < 10 ? "0$i" : $i;
   $ampms = array('am' => t('am'), 'pm' => t('pm'));
 
-  $element = array(
-    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
-    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
-    '#required' => $component['mandatory'],
-    '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
-    '#element_validate' => array('webform_validate_time'),
-    '#hourformat' => $component['extra']['hourformat'],
-    '#theme' => 'webform_time',
-    '#theme_wrappers' => array('webform_element'),
-    '#webform_component' => $component,
-  );
-
   $element['hour'] = array(
     '#prefix' => '',
     '#type' => 'select',
@@ -152,16 +157,27 @@
     );
   }
 
-  if (isset($value[0]) && $value[0] !== '') {
-    $value = webform_date_array($value[0], 'time');
-    if ($component['extra']['hourformat'] == '12-hour') {
-      $value = webform_time_convert($value, '12-hour');
-    }
+  // Set the overall default value.
+  if ($default_values['hour'] !== '') {
+    $element['#default_value'] = webform_date_string($default_values);
+  }
+
+  return $element;
+}
+
+/**
+ * Form API #after_build function for Webform time fields.
+ *
+ * Note that a #process function will not work on time fields, since they are
+ * not actual FAPI elements. We use this function to set the proper default
+ * values for the time fields.
+ */
+function webform_expand_time($element) {
+  if (array_key_exists('#default_value', $element)) {
+    $time_value = webform_date_array($element['#default_value'], 'time');
 
-    $element['hour']['#default_value'] = $value['hour'];
-    $element['minute']['#default_value'] = $value['minute'];
-    if (isset($value['ampm'])) {
-      $element['ampm']['#default_value'] = $value['ampm'];
+    foreach ($time_value as $key => $value) {
+      $element[$key]['#value'] = $value;
     }
   }
 
Index: includes/webform.pages.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.pages.inc,v
retrieving revision 1.19
diff -u -r1.19 webform.pages.inc
--- includes/webform.pages.inc	6 Jan 2011 18:34:55 -0000	1.19
+++ includes/webform.pages.inc	7 Feb 2011 03:49:37 -0000
@@ -174,9 +174,15 @@
   );
   $form['advanced']['allow_draft'] = array(
     '#type' => 'checkbox',
-    '#title' => t('Allow users to save a draft'),
+    '#title' => t('Show "Save draft" button'),
     '#default_value' => $node->webform['allow_draft'],
-    '#description' => t('Allow your users to save and finish the form later.'),
+    '#description' => t('Allow your users to save and finish the form later. This option is available only for authenticated users.'),
+  );
+  $form['advanced']['auto_save'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Automatically save as draft between pages'),
+    '#default_value' => $node->webform['auto_save'],
+    '#description' => t('Automatically save partial submissions when users click the "Next" or "Previous" buttons in a multipage form.'),
   );
   $form['advanced']['submit_notice'] = array(
     '#type' => 'checkbox',
@@ -265,6 +271,9 @@
   // Set the draft option.
   $node->webform['allow_draft'] = $form_state['values']['allow_draft'];
 
+  // Set the auto-save draft option.
+  $node->webform['auto_save'] = $form_state['values']['auto_save'];
+
   // Set the submit limit to -1 if set to unlimited.
   if ($form_state['values']['enforce_limit'] == 'no') {
     $node->webform['submit_limit'] = -1;
Index: includes/webform.submissions.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.submissions.inc,v
retrieving revision 1.33
diff -u -r1.33 webform.submissions.inc
--- includes/webform.submissions.inc	5 Jan 2011 23:46:01 -0000	1.33
+++ includes/webform.submissions.inc	7 Feb 2011 03:49:37 -0000
@@ -404,7 +404,8 @@
 
   if (!isset($counts[$nid][$uid]) || $reset) {
     $query = db_select('webform_submissions')
-      ->condition('nid', $nid);
+      ->condition('nid', $nid)
+      ->condition('is_draft', 0);
     $arguments = array($nid);
     if ($uid !== NULL) {
       $query->condition('uid', $uid);
Index: webform.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.install,v
retrieving revision 1.63
diff -u -r1.63 webform.install
--- webform.install	6 Feb 2011 07:02:16 -0000	1.63
+++ webform.install	7 Feb 2011 03:49:34 -0000
@@ -66,6 +66,13 @@
          'not null' => TRUE,
          'default' => 0,
       ),
+      'auto_save' => array(
+         'description' => 'Boolean value for whether submissions to this form should be auto-saved between pages.',
+         'type' => 'int',
+         'size' => 'tiny',
+         'not null' => TRUE,
+         'default' => 0,
+      ),
       'submit_notice' => array(
         'description' => 'Boolean value for whether to show or hide the previous submissions notification.',
         'type' => 'int',
@@ -510,3 +517,12 @@
     'not null' => FALSE,
   ));
 }
+
+/**
+ * Add the ability to auto-save as draft between pages.
+ */
+function webform_update_7309() {
+  if (!db_field_exists('webform', 'auto_save')) {
+    db_add_field('webform', 'auto_save', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0));
+  }
+}
Index: webform.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.module,v
retrieving revision 1.280
diff -u -r1.280 webform.module
--- webform.module	6 Feb 2011 07:02:16 -0000	1.280
+++ webform.module	7 Feb 2011 03:49:36 -0000
@@ -1017,6 +1017,7 @@
     'teaser' => 0,
     'block' => 0,
     'allow_draft' => 0,
+    'auto_save' => 0,
     'submit_notice' => 1,
     'submit_text' => '',
     'submit_limit' => -1,
@@ -1254,7 +1255,7 @@
 
   // Check if this user has a draft for this webform.
   $is_draft = FALSE;
-  if ($node->webform['allow_draft'] && $user->uid != 0) {
+  if (($node->webform['allow_draft'] || $node->webform['auto_save']) && $user->uid != 0) {
     // Draft found - display form with draft data for further editing.
     if ($draft_sid = _webform_fetch_draft_sid($node->nid, $user->uid)) {
       module_load_include('inc', 'webform', 'includes/webform.submissions');
@@ -1558,6 +1559,14 @@
     'js' => array(drupal_get_path('module', 'webform') . '/js/webform.js'),
   );
   module_load_include('inc', 'webform', 'includes/webform.components');
+  module_load_include('inc', 'webform', 'includes/webform.submissions');
+
+  // If in a multi-step form, a submission ID may be specified in form state.
+  // Load this submission. This allows anonymous users to use auto-save.
+  if (empty($submission) && !empty($form_state['values']['details']['sid'])) {
+    $submission = webform_get_submission($node->nid, $form_state['values']['details']['sid']);
+    $is_draft = $submission->is_draft;
+  }
 
   // Bind arguments to $form to make them available in theming and form_alter.
   $form['#node'] = $node;
@@ -1612,7 +1621,7 @@
 
     // 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;
+      $component_value = isset($form_state['values']['submitted'][$cid]) ? $form_state['values']['submitted'][$cid] : NULL;
       if (_webform_client_form_rule_check($node, $component, $page_num, $form_state)) {
         _webform_client_form_add_component($node, $component, $component_value, $form['submitted'], $form, $form_state, $submission, 'form', $page_num, $filter);
       }
@@ -1650,19 +1659,21 @@
       '#weight' => 1000,
     );
 
+    // Add the draft button.
+    if ($node->webform['allow_draft'] && (empty($submission) || $submission->is_draft) && $user->uid != 0) {
+      $form['actions']['draft'] = array(
+        '#type' => 'submit',
+        '#value' => t('Save Draft'),
+        '#weight' => -2,
+        '#validate' => array(),
+      );
+    }
+
     if ($page_count > 1) {
       $next_page = t('Next Page >');
       $prev_page = t('< Previous Page');
 
       // Add the submit button(s).
-     if ($node->webform['allow_draft'] && (empty($submission) || $submission->is_draft) && $user->uid != 0) {
-        $form['actions']['draft'] = array(
-          '#type' => 'submit',
-          '#value' => t('Save Draft'),
-          '#weight' => -2,
-          '#validate' => array(),
-        );
-      }
       if ($page_num > 1) {
         $form['actions']['previous'] = array(
           '#type' => 'submit',
@@ -1850,7 +1861,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;
+      $subcomponent_value = isset($form_state['values']['submitted'][$scid]) ? $form_state['values']['submitted'][$scid] : NULL;
       if (_webform_client_form_rule_check($node, $subcomponent, $page_num, $form_state, $submission)) {
         _webform_client_form_add_component($node, $subcomponent, $subcomponent_value, $parent_fieldset[$component['form_key']], $form, $form_state, $submission, $format, $page_num, $filter);
       }
@@ -1963,9 +1974,12 @@
     $form_state['storage']['page_num'] = $form_state['webform']['page_num'];
   }
 
+  // Assume the form is completed unless the page logic says otherwise.
+  $form_state['webform_completed'] = TRUE;
+
   // Check for a multi-page form that is not yet complete.
-  $submit_op = empty($node->webform['submit_text']) ? t('Submit') : t($node->webform['submit_text']);
-  $draft_op = t('Save Draft');
+  $submit_op = !empty($form['actions']['submit']['#value']) ? $form['actions']['submit']['#value'] : t('Submit');
+  $draft_op = !empty($form['actions']['draft']['#value']) ? $form['actions']['draft']['#value'] : t('Save Draft');
   if (!in_array($form_state['values']['op'], array($submit_op, $draft_op))) {
     // Checkboxes need post-processing to maintain their values.
     _webform_client_form_submit_process($node, $form_state['values']['submitted'], array('select', 'grid'));
@@ -2022,15 +2036,12 @@
       }
     }
 
-    // Rebuild the form and display the next page.
-    if ($form_state['storage']['page_num'] <= $form_state['storage']['page_count']) {
-      $form_state['rebuild'] = TRUE;
-      return;
-    }
+    // The form is done if the page number is greater than the page count.
+    $form_state['webform_completed'] = $form_state['storage']['page_num'] > $form_state['storage']['page_count'];
   }
 
+  // Merge any stored submission data for multistep forms.
   if (isset($form_state['storage']['submitted'])) {
-    // Merge any stored submission data for multistep forms.
     $original_values = is_array($form_state['values']['submitted']) ? $form_state['values']['submitted'] : array();
     unset($form_state['values']['submitted']);
 
@@ -2045,10 +2056,6 @@
     unset($original_values);
   }
 
-  // Remove the form state storage now that we're done with the pages.
-  unset($form_state['rebuild']);
-  unset($form_state['storage']);
-
   // Perform post processing by components.
   _webform_client_form_submit_process($node, $form_state['values']['submitted']);
 
@@ -2056,8 +2063,21 @@
   $form_state['values']['submitted_tree'] = $form_state['values']['submitted'];
   $form_state['values']['submitted'] = _webform_client_form_submit_flatten($node, $form_state['values']['submitted']);
 
-  // Set a flag indicating processing should continue and be saved.
-  $form_state['webform_completed'] = TRUE;
+  // Inform the submit handlers that a draft will be saved.
+  if ($form_state['values']['op'] == $draft_op || ($node->webform['auto_save'] && !$form_state['webform_completed'])) {
+    $form_state['save_draft'] = TRUE;
+  }
+
+  // Determine what we need to do on the next page.
+  if (!empty($form_state['save_draft']) || !$form_state['webform_completed']) {
+    // Rebuild the form and display the current (on drafts) or next page.
+    $form_state['rebuild'] = TRUE;
+  }
+  else {
+    // Remove the form state storage now that we're done with the pages.
+    unset($form_state['rebuild']);
+    unset($form_state['storage']);
+  }
 }
 
 /**
@@ -2068,14 +2088,14 @@
   module_load_include('inc', 'webform', 'includes/webform.components');
   global $user;
 
-  if (empty($form_state['webform_completed'])) {
+  if (empty($form_state['save_draft']) && empty($form_state['webform_completed'])) {
     return;
   }
 
   $node = $form['#node'];
 
   // Check if user is submitting as a draft.
-  $is_draft = $form_state['values']['op'] == t('Save Draft');
+  $is_draft = !empty($form_state['save_draft']);
 
   // Create a submission object.
   $submission = (object) array(
@@ -2244,8 +2264,11 @@
   $message = NULL;
   $redirect = NULL;
   $external_url = FALSE;
-  if ($is_draft) {
-    $message = t('Draft saved');
+  if (isset($form['actions']['draft']['#value']) && $form_state['values']['op'] == $form['actions']['draft']['#value']) {
+    $message = t('Submission saved. You may return to this form later and it will restore the current values.');
+  }
+  elseif ($is_draft) {
+    $redirect = NULL;
   }
   elseif (!empty($form_state['values']['details']['finished'])) {
     $message = t('Submission updated.');
@@ -2302,11 +2325,8 @@
       if (isset($node->webform['components'][$cid])) {
         // Call the component process submission function.
         $component = $node->webform['components'][$cid];
-        if ((!isset($types) || in_array($component['type'], $types))) {
-          $new_value = webform_component_invoke($component['type'], 'submit', $component, $form_values[$component['form_key']]);
-          if ($new_value !== NULL) {
-            $form_values[$component['form_key']] = $new_value;
-          }
+        if ((!isset($types) || in_array($component['type'], $types)) && webform_component_implements($component['type'], 'submit')) {
+          $form_values[$component['form_key']] = webform_component_invoke($component['type'], 'submit', $component, $form_values[$component['form_key']]);
         }
       }
     }
@@ -3144,6 +3164,20 @@
 }
 
 /**
+ * Check if a component implements a particular hook.
+ *
+ * @param $type
+ *   The component type as a string.
+ * @param $callback
+ *   The callback to check.
+ */
+function webform_component_implements($type, $callback) {
+  $function = '_webform_' . $callback . '_' . $type;
+  webform_component_include($type);
+  return function_exists($function);
+}
+
+/**
  * Disable the Drupal page cache.
  */
 function webform_disable_page_cache() {
