diff --git a/includes/webform.conditionals.inc b/includes/webform.conditionals.inc
index 8c17e10..5ec718f 100644
--- a/includes/webform.conditionals.inc
+++ b/includes/webform.conditionals.inc
@@ -31,6 +31,14 @@ function webform_conditionals_form($form, &$form_state, $node) {
     }
   }
 
+  // Check the current topological sort order for the conditionals and report any errors,
+  // but only for actual form submissions and not for ajax-related form builds, such as
+  // adding or removing a condtion or conditional group.
+  if (empty($form_state['triggering_element']['#ajax'])) {
+    $node->webform['conditionals'] = $conditionals;
+    $node->webform['conditional_sorter']->reportErrors($conditionals);
+  }
+
   $form['#tree'] = TRUE;
   $form['#node'] = $node;
 
@@ -194,11 +202,6 @@ function webform_conditionals_form_submit($form, &$form_state) {
       $conditional['rules'][$rid]['source_type'] = 'component';
     }
     $conditionals[$rgid] = $conditional;
-    // Warn if there are multiple conditionals targetting the same component.
-    if (isset($targets[$conditional['target']])) {
-      drupal_set_message(t('More than one conditional hides or shows component "@name". Only the most-recently evaluated conditional will determine whether "@name" is displayed.',
-                           array('@name' => $node->webform['components'][$conditional['target']]['name'])), 'warning', FALSE);
-    }
     $targets[$conditional['target']] = TRUE;
   }
 
@@ -889,29 +892,44 @@ function webform_conditional_delete($node, $conditional) {
  * settings. We remove unnecessary data structures and provide a "source map"
  * so that JavaScript can quickly determine if it needs to check rules when a
  * field on the page has been modified.
+ *
+ * @param object $node
+ *   The loaded node object, containing the webform.
+ * @param array $submission_data
+ *   The cid-indexed array of existing submission values to be included for
+ *   sources outside of the current page.
+ * @param integer $page_num
+ *   The number of the page for which javascript settings should be generated.
+ * @return array
+ *   Array of settings to be send to the browser as javascript settings.
  */
-function webform_conditional_prepare_javascript($node, $submission_data) {
+function webform_conditional_prepare_javascript($node, $submission_data, $page_num) {
   $settings = array(
     'ruleGroups' => array(),
     'sourceMap' => array(),
     'values' => array(),
   );
   $operators = webform_conditional_operators();
-  foreach ($node->webform['conditionals'] as $conditional) {
+  $conditionals = $node->webform['conditionals'];
+  $components = $node->webform['components'];
+  $topological_order = $node->webform['conditional_sorter']->getOrder();
+  foreach ($topological_order[$page_num] as $conditional_spec) {
+    $conditional = $conditionals[$conditional_spec['rgid']];
     $rgid_key = 'rgid_' . $conditional['rgid'];
     // Assemble the main conditional group settings.
     if ($conditional['target_type'] == 'component') {
-      $target_component = $node->webform['components'][$conditional['target']];
+      $target_component = $components[$conditional['target']];
       $target_parents = webform_component_parent_keys($node, $target_component);
-      $target_id = 'webform-component--' . str_replace('_', '-', implode('--', $target_parents));
-      $settings['ruleGroups'][$rgid_key]['target'] = $target_id;
-      $settings['ruleGroups'][$rgid_key]['andor'] = $conditional['andor'];
-      $settings['ruleGroups'][$rgid_key]['action'] = $conditional['action'];
+      $settings['ruleGroups'][$rgid_key] = array(
+        'target' => 'webform-component--' . str_replace('_', '-', implode('--', $target_parents)),
+        'andor' => $conditional['andor'],
+        'action' => $conditional['action'],
+      );
     }
     // Add on the list of rules to the conditional group.
     foreach ($conditional['rules'] as $rule) {
       if ($rule['source_type'] == 'component') {
-        $source_component = $node->webform['components'][$rule['source']];
+        $source_component = $components[$rule['source']];
         $source_parents = webform_component_parent_keys($node, $source_component);
         $source_id = 'webform-component--' . str_replace('_', '-', implode('--', $source_parents));
         $rid_key = 'rid_' . $rule['rid'];
@@ -924,10 +942,11 @@ function webform_conditional_prepare_javascript($node, $submission_data) {
 
         $conditional_type = webform_component_property($source_component['type'], 'conditional_type');
         $operator_info = $operators[$conditional_type][$rule['operator']];
-        $rule_settings = array();
-        $rule_settings['source'] = $source_id;
-        $rule_settings['value'] = $rule['value'];
-        $rule_settings['callback'] = $operator_info['js comparison callback'];
+        $rule_settings = array(
+          'source' => $source_id,
+          'value' => $rule['value'],
+          'callback' => $operator_info['js comparison callback'],
+        );
         if (isset($operator_info['comparison prepare js'])) {
           $callback = $operator_info['comparison prepare js'];
           $rule_settings['value'] = $callback($rule['value']);
diff --git a/includes/webform.webformconditionals.inc b/includes/webform.webformconditionals.inc
new file mode 100644
index 0000000..7460c3d
--- /dev/null
+++ b/includes/webform.webformconditionals.inc
@@ -0,0 +1,338 @@
+<?php
+
+/**
+ * @file
+ * Conditional engine to process dependencies within the webform's conditionals.
+ */
+
+/**
+ * Performs analysis and topological sorting on the conditionals.
+ */
+class WebformConditionals {
+  protected static $conditionals = array();
+
+  protected $node;
+  protected $topologicalOrder;
+  protected $pageMap;
+  protected $childrenMap;
+
+  public $errors;
+
+  /**
+   * Creates and caches a WebformConditional for a given node.
+   */
+  static function factory($node) {
+    if (!isset(self::$conditionals[$node->nid])) {
+      self::$conditionals[$node->nid] = new WebformConditionals($node);
+    }
+    return self::$conditionals[$node->nid];
+  }
+
+  /**
+   * Constructs a WebformConditional.
+   */
+  function __construct($node) {
+    $this->node = $node;
+  }
+
+  /**
+   * Sorts the conditionals into topological order.
+   *
+   * The "nodes" of the list are the conditionals, not the components that
+   * they operate upon.
+   *
+   * The webform components must already be sorted into component tree order
+   * before calling this method.
+   *
+   * See http://en.wikipedia.org/wiki/Topological_sorting
+   */
+  function topologicalSort() {
+    $components = $this->node->webform['components'];
+    $conditionals = $this->node->webform['conditionals'];
+    $errors = array();
+
+    // Generate a component to condional map for conditional targets.
+    $cid_to_target_rgid = array();
+    foreach ($conditionals as $rgid => $conditional) {
+      $target_id = $conditional['target'];
+      $cid_to_target_rgid[$target_id][$rgid] = $rgid;
+      if (count($cid_to_target_rgid[$target_id]) == 2) {
+        $component = $components[$target_id];
+        $errors[$component['page_num']][] = t('More than one conditional hides or shows component "@name".',
+                                              array('@name' => $component['name']));
+      }
+    }
+
+    // Generate T-Orders for each page
+    $new_entry = array('in' => array(), 'out' => array(), 'rgid' => -1);
+    $page_num = 0;
+    $sorted = array();
+    $pageMap = array();
+    $component = reset($components);
+    while ($component) {
+      $cid = $component['cid'];
+      // Start a new page, if needed
+      if ($component['page_num'] > $page_num ) {
+        $page_num = $component['page_num'];
+        $sorted[$page_num] = array();
+        $nodes = array();
+      }
+
+      // Create the pageMap as a side benefit of generating the t-sort.
+      $pageMap[$page_num][$cid] = $cid;
+
+      // Process component by adding it's conditional data to a component-tree-traversal order an index of:
+      // - incoming dependencies = the source components for the conditions for this target component and
+      // - outgoing dependencies = components which depend upon the target component
+      // Note: Surprisingly, 0 is a valid rgid, as well as a valid rid. Use -1 as a semaphore.
+      if (isset($cid_to_target_rgid[$cid])) {
+        // The component is the target of conditional(s)
+        foreach ($cid_to_target_rgid[$cid] as $rgid) {
+          $conditional = $conditionals[$rgid];
+          if (!isset($nodes[$cid])) {
+            $nodes[$cid] = $new_entry;
+          }
+          $nodes[$cid]['rgid'] = $rgid;
+          foreach ($conditional['rules'] as $rule) {
+            if ($rule['source_type'] == 'component') {
+              $source_id = $rule['source'];
+              if (!isset($nodes[$source_id])) {
+                $nodes[$source_id] = $new_entry;
+              }
+              $nodes[$cid]['in'][$source_id] = $source_id;
+              $nodes[$source_id]['out'][$cid] = $cid;
+              $source_component = $components[$source_id];
+              $source_pid = $source_component['pid'];
+              if ($source_pid) {
+                if (!isset($nodes[$source_pid])) {
+                  $nodes[$source_pid] = $new_entry;
+                }
+                // The rule source is within a parent fieldset
+                $nodes[$source_pid]['out'][$source_id] = $source_id;
+                $nodes[$source_id]['in'][$source_pid] = $source_pid;
+              }
+              if ($source_component['page_num'] > $page_num) {
+                $errors[$page_num][] = t('A forward reference from page @from, %from to %to was found.',
+                                         array(
+                                            '%from' => $source_component['name'],
+                                            '@from' => $source_component['page_num'],
+                                            '%to' => $component['name'],
+                                         ));
+              }
+            }
+          }
+        }
+      }
+
+      // Fetch the next component, if any.
+      $component = next($components);
+
+      // Finish any previous page already processed.
+      if (!$component || $component['page_num'] > $page_num) {
+
+        // Create a set of all components which have are not dependent upon anything.
+        // This list is known as S in the literature.
+        $start_nodes = array();
+        foreach ($nodes as $id => $n) {
+          if (!$n['in']) {
+            $start_nodes[] = $id;
+          }
+        }
+
+        // Create an empty list that will contain the sorted elements.
+        // This list is known as L in the literature.
+        while ($start_nodes) {
+          $id = array_shift($start_nodes);
+          if ($nodes[$id]['rgid'] >= 0) {
+            $sorted[$page_num][] = array(
+              'cid' => $id,
+              'rgid' => $nodes[$id]['rgid'],
+              'name' => $components[$id]['name'],
+            );
+          }
+          foreach ($nodes[$id]['out'] as $out_id) {
+            unset($nodes[$out_id]['in'][$id]);
+            if (!$nodes[$out_id]['in']) {
+              $start_nodes[] = $out_id;
+            }
+          }
+          $nodes[$id]['out'] = array();
+        }
+
+        // Check for a cyclic graph (circular dependency)
+        foreach ($nodes as $id => $n) {
+          if ($n['in'] || $n['out']) {
+            $errors[$page_num][] = t('A circular reference involving %name was found.',
+                                     array('%name' => $components[$id]['name']));
+          }
+        }
+
+      } // End finshing previous page
+
+    } // End component loop
+
+    // Create an empty page map for the preview page.
+    $pageMap[$page_num + 1] = array();
+
+    $this->topologicalOrder = $sorted;
+    $this->errors = $errors;
+    $this->pageMap = $pageMap;
+  }
+
+  /**
+   * Returns the (possibly cached) topological sort order.
+   */
+  function getOrder() {
+    if (!$this->topologicalOrder) {
+      $this->topologicalSort();
+    }
+    return $this->topologicalOrder;
+  }
+
+  /**
+   * Returns an index of components by page number.
+   */
+  function getPageMap() {
+    if (!$this->pageMap) {
+      $this->topologicalSort();
+    }
+    return $this->pageMap;
+  }
+  
+  /**
+   * Displays and error messages from the previously-generated sort order.
+   *
+   * User's who can't fix the webform are shown a single, simplified message.
+   */
+  function reportErrors() {
+    $this->getOrder();
+    if ($this->errors) {
+      if (webform_node_update_access($this->node)) {
+        foreach ($this->errors as $page_num => $page_errors) {
+          drupal_set_message(format_plural(count($page_errors),
+                                           'Conditional error on page @num:',
+                                           'Conditional errors on page @num:',
+                                           array('@num' => $page_num)) .
+                             '<br /><ul><li>' . implode('</li><li>', $page_errors) . '</li></ul>', 'warning');
+        }
+      }
+      else {
+         drupal_set_message(t('This form is improperly configured. Contact the administrator.'), 'warning');
+      }
+    }
+  }
+
+  /**
+   * Creates and caches a map of the children of a each component.
+   *
+   * Called after the component tree has been made and then flattened again.
+   * Alas, the children data is removed when the tree is flattened. The
+   * components are indexecd by cid but in tree order. Because cid's are
+   * numeric, they may not appear in IDE's or debuggers in their actual order.
+   */
+  function getChildrenMap() {
+    if (!$this->childrenMap) {
+      $map = array();
+      foreach ($this->node->webform['components'] as $cid => $component) {
+        $pid = $component['pid'];
+        if ($pid) {
+          $map[$pid][] = $cid;
+        }
+      }
+
+      $this->childrenMap = $map;
+    }
+    return $this->childrenMap;
+  }
+
+  /**
+   * Deletes the value of the given component, plus any descendents.
+   */
+  protected function deleteFamily(&$input_values, $parent_id) {
+    if (isset($input_values[$parent_id])) {
+      $input_values[$parent_id] = NULL;
+    }
+    if (isset($this->childrenMap[$parent_id])) {
+      foreach ($this->childrenMap[$parent_id] as $child_id) {
+        $this->deleteFamily($input_values, $child_id);
+      }
+    }
+  }
+
+  /**
+   * Executes the conditionals on a submission, removing any data which should
+   * be hidden.
+   */
+  function execute($input_values, $page_num = 0) {
+    $this->getOrder();
+    $this->getChildrenMap();
+
+    module_load_include('inc', 'webform', 'includes/webform.conditionals');
+    
+    $components = $this->node->webform['components'];
+    $conditionals = array_values($this->node->webform['conditionals']);
+    $operators = webform_conditional_operators();
+
+
+    $first_page = $page_num ? $page_num : 1;
+    $last_page = $page_num ? $page_num : count($this->topologicalOrder);
+    for ($page = $first_page; $page <= $last_page; $page++) {
+      foreach ($this->topologicalOrder[$page] as $conditional_spec) {
+        
+        $conditional = $conditionals[$conditional_spec['rgid']];
+        $conditional_result = TRUE;
+
+        // Execute each comparison callback.
+        $conditional_results = array();
+        foreach ($conditional['rules'] as $rule) {
+          // TODO: Support other source types besides components?
+          if ($rule['source_type'] !== 'component') {
+            continue;
+          }
+          $source_component = $components[$rule['source']];
+          $source_cid = $source_component['cid'];
+
+          $source_values = array();
+          if (isset($input_values[$source_cid])) {
+            $component_value = $input_values[$source_cid];
+            // For select_or_other components, use only the select values because $source_values must not be a nested array.
+            // During preview, the array is already flattened.
+            if ($source_component['type'] === 'select' &&
+                !empty($source_component['extra']['other_option']) &&
+                isset($component_value['select'])) {
+              $component_value = $component_value['select'];
+            }
+            $source_values = is_array($component_value) ? $component_value : array($component_value);
+          }
+
+          // Determine the operator and callback.
+          $conditional_type = webform_component_property($source_component['type'], 'conditional_type');
+          $operator_info = $operators[$conditional_type];
+
+          // Perform the comparison callback and build the results for this group.
+          $comparison_callback = $operator_info[$rule['operator']]['comparison callback'];
+          $conditional_results[] = $comparison_callback($source_values, $rule['value']);
+        }
+
+        // Calculate the and/or result.
+        $filtered_results = array_filter($conditional_results);
+        $conditional_result = $conditional['andor'] === 'or'
+                                  ? count($filtered_results) > 0
+                                  : count($filtered_results) === count($conditional_results);
+
+        // Flip the result of the action is to hide.
+        if ($conditional['action'] == 'hide') {
+          $conditional_result = !$conditional_result;
+        }
+
+        if (!$conditional_result) {
+          $this->deleteFamily($input_values, $conditional['target']);
+        }
+
+      } // End conditinal loop
+    } // End page loop
+
+    return $input_values;
+  }
+
+ }
diff --git a/js/webform.js b/js/webform.js
index e56f668..44f2f4e 100644
--- a/js/webform.js
+++ b/js/webform.js
@@ -98,8 +98,8 @@ Drupal.webform.conditional = function(context) {
       $currentForm.bind('change', { 'settings': settings }, Drupal.webform.conditionalCheck);
 
       // Trigger all the elements that cause conditionals on this form.
-      $.each(Drupal.settings.webform.conditionals[formKey]['sourceMap'], function(elementKey) {
-        $currentForm.find('.' + elementKey).find('input,select,textarea').filter(':first').trigger('change');
+      $.each(Drupal.settings.webform.conditionals[formKey]['ruleGroups'], function(rgid_key, rule_group) {
+        Drupal.webform.doCondition($form, settings, rgid_key);
       });
     })
   });
@@ -115,76 +115,69 @@ Drupal.webform.conditionalCheck = function(e) {
   var $form = $triggerElement.closest('form');
   var triggerElementKey = $triggerElement.attr('class').match(/webform-component--[^ ]+/)[0];
   var settings = e.data.settings;
-
-
   if (settings.sourceMap[triggerElementKey]) {
-    $.each(settings.sourceMap[triggerElementKey], function(n, rgid_key) {
-      var ruleGroup = settings.ruleGroups[rgid_key];
-
-      // Perform the comparison callback and build the results for this group.
-      var conditionalResult = true;
-      var conditionalResults = [];
-      $.each(ruleGroup['rules'], function(m, rule) {
-        var elementKey = rule['source'];
-        var element = $form.find('.' + elementKey)[0];
-        var existingValue = settings.values[elementKey] ? settings.values[elementKey] : null;
-        conditionalResults.push(window['Drupal']['webform'][rule.callback](element, existingValue, rule['value'] ));
-      });
-
-      // Filter out false values.
-      var filteredResults = [];
-      for (var i = 0; i < conditionalResults.length; i++) {
-        if (conditionalResults[i]) {
-          filteredResults.push(conditionalResults[i]);
-        }
-      }
+    $.each(settings.ruleGroups, function(rgid_key, rule_group) {
+      Drupal.webform.doCondition($form, settings, rgid_key);
+    });
+  }
+};
 
-      // Calculate the and/or result.
-      if (ruleGroup['andor'] === 'or') {
-        conditionalResult = filteredResults.length > 0;
-      }
-      else {
-        conditionalResult = filteredResults.length === conditionalResults.length;
-      }
+/**
+ * Processes one condition.
+ */
+Drupal.webform.doCondition = function($form, settings, rgid_key) {
+  var ruleGroup = settings.ruleGroups[rgid_key];
+
+  // Perform the comparison callback and build the results for this group.
+  var conditionalResult = true;
+  var conditionalResults = [];
+  $.each(ruleGroup['rules'], function(m, rule) {
+    var elementKey = rule['source'];
+    var element = $form.find('.' + elementKey)[0];
+    var existingValue = settings.values[elementKey] ? settings.values[elementKey] : null;
+    conditionalResults.push(window['Drupal']['webform'][rule.callback](element, existingValue, rule['value'] ));
+  });
 
-      // Flip the result of the action is to hide.
-      var showComponent;
-      if (ruleGroup['action'] == 'hide') {
-        showComponent = !conditionalResult;
-      }
-      else {
-        showComponent = conditionalResult;
-      }
+  // Filter out false values.
+  var filteredResults = [];
+  for (var i = 0; i < conditionalResults.length; i++) {
+    if (conditionalResults[i]) {
+      filteredResults.push(conditionalResults[i]);
+    }
+  }
 
-      var $target = $form.find('.' + ruleGroup['target']);
-      var $targetElements;
-      if (showComponent != $target.is(':visible')) {
-        if (showComponent) {
-          $targetElements = $target.find('.webform-conditional-disabled').removeClass('webform-conditional-disabled');
-          $.fn.prop ? $targetElements.prop('disabled', false) : $targetElements.removeAttr('disabled');
-          $target.show();
-        }
-        else {
-          $targetElements = $target.find(':input').addClass('webform-conditional-disabled');
-          $.fn.prop ? $targetElements.prop('disabled', true) : $targetElements.attr('disabled', true);
-          $target.hide();
-        }
-        // Trigger change if not already in recurive infinite loop
-        var target = $target.get(0);
-        target.changeDepth = target.changeDepth || 0;
-        if (target.changeDepth < 10) {
-          target.changeDepth++;
-          $target.trigger('change');
-          target.changeDepth--;
-        } else {
-          alert(Drupal.t("An infinite loop was detected in this webform's conditionals. Contact the administrator."));
-        }
-      }
+  // Calculate the and/or result.
+  if (ruleGroup['andor'] === 'or') {
+    conditionalResult = filteredResults.length > 0;
+  }
+  else {
+    conditionalResult = filteredResults.length === conditionalResults.length;
+  }
 
-    });
+  // Flip the result of the action is to hide.
+  var showComponent;
+  if (ruleGroup['action'] == 'hide') {
+    showComponent = !conditionalResult;
+  }
+  else {
+    showComponent = conditionalResult;
   }
 
-};
+  var $target = $form.find('.' + ruleGroup['target']);
+  var $targetElements;
+  if (showComponent != $target.is(':visible')) {
+    if (showComponent) {
+      $targetElements = $target.find('.webform-conditional-disabled').removeClass('webform-conditional-disabled');
+      $.fn.prop ? $targetElements.prop('disabled', false) : $targetElements.removeAttr('disabled');
+      $target.show();
+    }
+    else {
+      $targetElements = $target.find(':input').addClass('webform-conditional-disabled');
+      $.fn.prop ? $targetElements.prop('disabled', true) : $targetElements.attr('disabled', true);
+      $target.hide();
+    }
+  }
+}
 
 Drupal.webform.conditionalOperatorStringEqual = function(element, existingValue, ruleValue) {
   var returnValue = false;
diff --git a/webform.info b/webform.info
index a735218..cb53887 100644
--- a/webform.info
+++ b/webform.info
@@ -10,6 +10,8 @@ dependencies[] = views
 test_dependencies[] = token
 
 ; Files that contain classes:
+files[] = includes/webform.webformconditionals.inc
+
 files[] = includes/exporters/webform_exporter_delimited.inc
 files[] = includes/exporters/webform_exporter_excel_delimited.inc
 files[] = includes/exporters/webform_exporter_excel_xlsx.inc
diff --git a/webform.module b/webform.module
index 1b314c0..839a847 100644
--- a/webform.module
+++ b/webform.module
@@ -1734,7 +1734,11 @@ function webform_node_load($nodes, $types) {
         $nodes[$nid]->webform['conditionals'][$rule->rgid]['rules'][$rule->rid] = (array) $rule;
       }
     }
+
+    // Create a WebformConditional sorter for this node.
+    $nodes[$nid]->webform['conditional_sorter'] =  WebformConditionals::factory($node);
   }
+
 }
 
 /**
@@ -2367,6 +2371,9 @@ function webform_client_form($form, &$form_state, $node, $submission = FALSE, $i
     // Allow values from other pages to be sent to browser for conditionals.
     $form['#conditional_values'] = $input_values;
 
+    // Generate conditional topological order & report any errors.
+    $node->webform['conditional_sorter']->reportErrors();
+
     if ($page_count > 1) {
       $page_labels = webform_page_labels($node, $form_state);
       $form['progressbar'] = array(
@@ -2898,11 +2905,14 @@ function webform_client_form_validate($form, &$form_state) {
     foreach ($new_values as $cid => $values) {
       $input_values[$cid] = $values;
     }
+    // Ensure that all conditionally-hidden values are removed.
+    $input_values = $node->webform['conditional_sorter']->execute($input_values, $form_state['webform']['page_num']);
   }
   else {
     $input_values = NULL;
   }
 
+
   // Run all #element_validate and #required checks. These are skipped initially
   // by setting #validated = TRUE on all components when they are added.
   _webform_client_form_validate($form, $form_state, 'webform_client_form', $input_values);
@@ -3095,23 +3105,23 @@ function webform_client_form_pages($form, &$form_state) {
   // Assume the form is completed unless the page logic says otherwise.
   $form_state['webform_completed'] = TRUE;
 
+  // Merge any stored submission data for multistep forms.
+  $original_values = is_array($form_state['values']['submitted']) ? $form_state['values']['submitted'] : array();
+  if (isset($form_state['storage']['submitted'])) {
+    // Array + operator keeps all elements of left operand and discards any duplicate elements in right operand.
+    $original_values += $form_state['storage']['submitted'];
+  }
+
+  // Execute conditionals on submission values.
+  $form_state['values']['submitted'] = $node->webform['conditional_sorter']->execute($original_values);
+
   // Check for a multi-page form that is not yet complete.
   $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, '__AUTOSAVE__'))) {
-    // Store values from the current page in the form state storage.
-    if (is_array($form_state['values']['submitted'])) {
-      foreach ($form_state['values']['submitted'] as $key => $val) {
-        $form_state['storage']['submitted'][$key] = $val;
-      }
-    }
 
-    // Update form state values with those from storage.
-    if (isset($form_state['storage']['submitted'])) {
-      foreach ($form_state['storage']['submitted'] as $key => $val) {
-        $form_state['values']['submitted'][$key] = $val;
-      }
-    }
+    // Store values from the current page in the form state storage.
+    $form_state['storage']['submitted'] = $form_state['values']['submitted'];
 
     // Set the page number.
     if (!isset($form_state['storage']['page_num'])) {
@@ -3194,22 +3204,6 @@ function webform_client_form_pages($form, &$form_state) {
     $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'])) {
-    $original_values = is_array($form_state['values']['submitted']) ? $form_state['values']['submitted'] : array();
-    unset($form_state['values']['submitted']);
-
-    foreach ($form_state['storage']['submitted'] as $key => $val) {
-      $form_state['values']['submitted'][$key] = $val;
-    }
-    foreach ($original_values as $key => $val) {
-      $form_state['values']['submitted'][$key] = $val;
-    }
-
-    // Remove the variable so it doesn't show up in the additional processing.
-    unset($original_values);
-  }
-
   // Inform the submit handlers that a draft will be saved.
   $form_state['save_draft'] = in_array($form_state['values']['op'], array($draft_op, '__AUTOSAVE__')) ||
                               ($node->webform['auto_save'] && !$form_state['values']['details']['finished'] && !$form_state['webform_completed'] && user_is_logged_in());
@@ -3252,8 +3246,13 @@ function webform_client_form_submit($form, &$form_state) {
     // Merge with new submission data. The + operator maintains numeric keys.
     // This maintains existing data with just-submitted data when a user resumes
     // a submission previously saved as a draft.
-    $new_data = webform_submission_data($node, $form_state['values']['submitted']);
-    $submission->data = $new_data + $submission->data;
+    // Remove any existing data on this and previous pages. If components are hidden, they may
+    // be in the $submission->data but absent entirely from $new_data;
+    $pageMap = $node->webform['conditional_sorter']->getPageMap();
+    for ($page_nr = 1; $page_nr <= $form_state['webform']['page_num']; $page_nr++) {
+      $submission->data = array_diff_key($submission->data, $pageMap[$page_nr]);
+    }
+    $submission->data = webform_submission_data($node, $form_state['values']['submitted']) + $submission->data;
   }
   else {
     // Create a new submission object.
@@ -3419,10 +3418,12 @@ function template_preprocess_webform_form(&$vars) {
     $vars['nid'] = $vars['form']['submission']['#value']->nid;
   }
 
-  if (!empty($vars['form']['#node']->webform['conditionals'])) {
+  if (!empty($vars['form']['#node']->webform['conditionals']) && empty($vars['form']['preview'])) {
     module_load_include('inc', 'webform', 'includes/webform.conditionals');
     $submission_data = isset($vars['form']['#conditional_values']) ? $vars['form']['#conditional_values'] : array();
-    $settings = webform_conditional_prepare_javascript($vars['form']['#node'], $submission_data);
+    $settings = webform_conditional_prepare_javascript($vars['form']['#node'],
+                                                       $submission_data,
+                                                       $vars['form']['details']['page_num']['#value']);
     drupal_add_js(array('webform' => array('conditionals' => array('webform-client-form-' . $vars['nid'] => $settings))), 'setting');
   }
 
