From edc8b4f3b9b258f3423f34dd7b040c2f8748a21b Mon Sep 17 00:00:00 2001
From: Eric Rasmussen <ericrasmussen1@gmail.com>
Date: Wed, 10 Apr 2013 11:58:46 -0500
Subject: [PATCH] [gh-670] Upgrade Form Builder to 7.x-1.3

---
 .../examples/form_builder_examples.info       |   6 +-
 .../examples/form_builder_examples.module     |   4 +-
 .../modules/form_builder/form_builder.info    |   6 +-
 .../modules/form_builder/form_builder.install |   1 +
 .../all/modules/form_builder/form_builder.js  |   5 +-
 .../includes/form_builder.admin.inc           |  42 ++++---
 .../includes/form_builder.api.inc             |  18 ++-
 .../includes/form_builder.cache.inc           |   2 -
 .../includes/form_builder.properties.inc      |   2 +-
 .../form_builder_webform.components.inc       |  90 +++++++++----
 .../modules/webform/form_builder_webform.info |   6 +-
 .../webform/form_builder_webform.module       | 119 ++++++++----------
 12 files changed, 176 insertions(+), 125 deletions(-)

diff --git a/sites/all/modules/form_builder/examples/form_builder_examples.info b/sites/all/modules/form_builder/examples/form_builder_examples.info
index 373b88101..8523dd538 100644
--- a/sites/all/modules/form_builder/examples/form_builder_examples.info
+++ b/sites/all/modules/form_builder/examples/form_builder_examples.info
@@ -3,9 +3,9 @@ description = Form builder support for CCK, Webform, and Profile modules.
 core = 7.x
 dependencies[] = form_builder
 
-; Information added by drupal.org packaging script on 2012-03-08
-version = "7.x-1.0"
+; Information added by drupal.org packaging script on 2012-09-27
+version = "7.x-1.3"
 core = "7.x"
 project = "form_builder"
-datestamp = "1331181344"
+datestamp = "1348708781"
 
diff --git a/sites/all/modules/form_builder/examples/form_builder_examples.module b/sites/all/modules/form_builder/examples/form_builder_examples.module
index 4766f8bfc..e3407b2de 100644
--- a/sites/all/modules/form_builder/examples/form_builder_examples.module
+++ b/sites/all/modules/form_builder/examples/form_builder_examples.module
@@ -446,10 +446,10 @@ function form_builder_examples_export_recurse($form, $parents = array()) {
         }
         else {
           if (($property == '#title') || ($property == '#description')) {
-            $output .= "  '". $property . "' => t('" . $form[$property] ."'),\n";
+            $output .= "  '". $property . "' => t('" . str_replace("'", "\'", $form[$property]) ."'),\n";
           }
           else {
-            $output .= "  '". $property . "' => '" . $form[$property] ."',\n";
+            $output .= "  '". $property . "' => '" . str_replace("'", "\'", $form[$property]) ."',\n";
           }
         }
       }
diff --git a/sites/all/modules/form_builder/form_builder.info b/sites/all/modules/form_builder/form_builder.info
index 20e893b27..7a0ed0db0 100644
--- a/sites/all/modules/form_builder/form_builder.info
+++ b/sites/all/modules/form_builder/form_builder.info
@@ -3,9 +3,9 @@ description = Form building framework.
 dependencies[] = options_element
 core = 7.x
 
-; Information added by drupal.org packaging script on 2012-03-08
-version = "7.x-1.0"
+; Information added by drupal.org packaging script on 2012-09-27
+version = "7.x-1.3"
 core = "7.x"
 project = "form_builder"
-datestamp = "1331181344"
+datestamp = "1348708781"
 
diff --git a/sites/all/modules/form_builder/form_builder.install b/sites/all/modules/form_builder/form_builder.install
index 04d5e5bfc..c7e691e6e 100644
--- a/sites/all/modules/form_builder/form_builder.install
+++ b/sites/all/modules/form_builder/form_builder.install
@@ -21,6 +21,7 @@ function form_builder_requirements($phase) {
     if (empty($form_builder_types)) {
       $requirements['form_builder_types']['title'] = $t('Form builder');
       $requirements['form_builder_types']['severity'] = REQUIREMENT_ERROR;
+      $requirements['form_builder_types']['value'] = $t('No dependent modules found.');
       $requirements['form_builder_types']['description'] = t('Form builder module is installed but no modules implement support for it. You may want to disable Form builder module until it is needed.');
     }
   }
diff --git a/sites/all/modules/form_builder/form_builder.js b/sites/all/modules/form_builder/form_builder.js
index 5968e7fad..f49159093 100644
--- a/sites/all/modules/form_builder/form_builder.js
+++ b/sites/all/modules/form_builder/form_builder.js
@@ -546,8 +546,11 @@ Drupal.formBuilder.addElement = function(response) {
   // Set the variable stating we're done updating.
   Drupal.formBuilder.updatingElement = false;
 
-  // Insert the new position form containing the new element.
+  // Insert the new position form containing the new element, but maintain
+  // the existing form action.
+  var positionAction = $('#form-builder-positions').attr('action');
   $('#form-builder-positions').replaceWith(response.positionForm);
+  $('#form-builder-positions').attr('action', positionAction);
 
   // Submit the new positions form to save the new element position.
   Drupal.formBuilder.updateElementPosition($new.get(0));
diff --git a/sites/all/modules/form_builder/includes/form_builder.admin.inc b/sites/all/modules/form_builder/includes/form_builder.admin.inc
index 5f0e1a2b2..478ec3afd 100644
--- a/sites/all/modules/form_builder/includes/form_builder.admin.inc
+++ b/sites/all/modules/form_builder/includes/form_builder.admin.inc
@@ -67,14 +67,14 @@ function form_builder_add_page($form_type, $form_id, $element_type) {
 
     if (isset($_REQUEST['js'])) {
       $element = form_builder_cache_field_load($form_type, $form_id, $element_id);
-      $preview_form = form_builder_cache_load($form_type, $form_id);
+      $form_cache = form_builder_cache_load($form_type, $form_id);
 
       $data = array(
         'formType' => $form_type,
         'formId' => $form_id,
         'elementId' => $element_id,
         'html' => form_builder_field_render($form_type, $form_id, $element_id),
-        'positionForm' => drupal_render(drupal_get_form('form_builder_positions', $preview_form, $form_type, $form_id)),
+        'positionForm' => drupal_render(drupal_get_form('form_builder_positions', $form_cache, $form_type, $form_id)),
       );
 
       form_builder_json_output($data);
@@ -147,7 +147,7 @@ function form_builder_field_palette() {
     $groups = module_invoke_all('form_builder_palette_groups');
     // TODO: We shouldn't have to clear the cache here.
     $form = form_builder_cache_load($active['form_type'], $active['form_id'], NULL, TRUE);
-    $active_fields = form_builder_get_element_ids($form);
+    $active_fields = form_builder_get_element_types($form);
     foreach ($fields as $key => $field) {
       if ($field['unique'] && in_array($key, $active_fields)) {
         $fields[$key]['in_use'] = TRUE;
@@ -199,6 +199,9 @@ function form_builder_preview($f, &$form_state, $form, $form_type, $form_id) {
   $form['#attached']['js'][] = 'misc/form.js';
   $form['#attached']['js'][] = 'misc/collapse.js';
 
+  $form['#attached']['js'][] = drupal_get_path('module', 'filter') . '/filter.js';
+  $form['#attached']['css'][] = drupal_get_path('module', 'filter') . '/filter.css';
+
   $form['#attached']['js'][] = array('data' => array('machineName' => array()), 'type' => 'setting');
   $form['#attached']['js'][] = 'misc/machine-name.js';
 
@@ -220,17 +223,17 @@ function form_builder_preview($f, &$form_state, $form, $form_type, $form_id) {
 /**
  * Form containing all the current weights and parents of elements.
  */
-function form_builder_positions($form, &$form_state, $preview_form, $form_type, $form_id) {
+function form_builder_positions($form, &$form_state, $form_cache, $form_type, $form_id) {
   $form = array(
     '#tree' => TRUE,
     '#form_builder' => array(
       'form_type' => $form_type,
       'form_id' => $form_id,
-      'form' => $preview_form,
+      'form' => $form_cache,
     ),
   );
 
-  form_builder_positions_prepare($form, $preview_form);
+  _form_builder_positions_prepare($form, $form_cache);
 
   // Drupal MUST have a button to register submissions.
   // Add a button even though the form is only submitted via AJAX.
@@ -245,30 +248,30 @@ function form_builder_positions($form, &$form_state, $preview_form, $form_type,
 /**
  * Recursive helper for form_builder_positions(). Add weight fields.
  */
-function form_builder_positions_prepare(&$form, &$preview_form, $parent_id = FORM_BUILDER_ROOT) {
-  foreach (element_children($preview_form) as $key) {
+function _form_builder_positions_prepare(&$form, $form_cache, $parent_id = FORM_BUILDER_ROOT) {
+  foreach (element_children($form_cache) as $key) {
     // Keep record of the current parent ID.
     $previous_parent_id = $parent_id;
 
-    if (isset($preview_form[$key]['#form_builder']['element_id'])) {
+    if (isset($form_cache[$key]['#form_builder']['element_id'])) {
       // Set the parent ID for this element.
-      $preview_form[$key]['#form_builder']['parent_id'] = $parent_id;
-      $element_id = $preview_form[$key]['#form_builder']['element_id'];
+      $form_cache[$key]['#form_builder']['parent_id'] = $parent_id;
+      $element_id = $form_cache[$key]['#form_builder']['element_id'];
       $parent_id = $element_id;
 
       $form[$element_id]['weight'] = array(
         '#type' => 'hidden',
-        '#default_value' => isset($preview_form[$key]['#weight']) ? $preview_form[$key]['#weight'] : 0,
+        '#default_value' => isset($form_cache[$key]['#weight']) ? $form_cache[$key]['#weight'] : 0,
         '#attributes' => array('class' => array('form-builder-weight form-builder-element-' . $element_id)),
       );
       $form[$element_id]['parent'] = array(
         '#type' => 'hidden',
-        '#default_value' => $preview_form[$key]['#form_builder']['parent_id'],
+        '#default_value' => $form_cache[$key]['#form_builder']['parent_id'],
         '#attributes' => array('class' => array('form-builder-parent form-builder-element-' . $element_id)),
       );
     }
 
-    form_builder_positions_prepare($form, $preview_form[$key], $parent_id);
+    _form_builder_positions_prepare($form, $form_cache[$key], $parent_id);
     $parent_id = $previous_parent_id;
   }
 }
@@ -282,7 +285,7 @@ function form_builder_positions_submit(&$form, &$form_state) {
 
   $form_type = $form['#form_builder']['form_type'];
   $form_id = $form['#form_builder']['form_id'];
-  $preview_form = $form['#form_builder']['form'];
+  $form_cache = $form['#form_builder']['form'];
 
   foreach (element_children($form) as $element_id) {
     // Skip items without weight value (like the form token, build_id, etc).
@@ -291,14 +294,17 @@ function form_builder_positions_submit(&$form, &$form_state) {
     }
 
     // Check for changed weights or parents.
-    $element = form_builder_get_element($preview_form, $element_id);
+    $element = form_builder_get_element($form_cache, $element_id);
     $element['#weight'] = $form_state['values'][$element_id]['weight'];
     $element['#form_builder']['parent_id'] = $form_state['values'][$element_id]['parent'];
-    form_builder_set_element($preview_form, $element);
+    form_builder_set_element($form_cache, $element);
   }
 
   // Save all the changes made.
-  form_builder_cache_save($form_type, $form_id, $preview_form);
+  form_builder_cache_save($form_type, $form_id, $form_cache);
+
+  // Don't redirect, which will cause an unnecessary HTTP request.
+  $form_state['redirect'] = FALSE;
 }
 
 /**
diff --git a/sites/all/modules/form_builder/includes/form_builder.api.inc b/sites/all/modules/form_builder/includes/form_builder.api.inc
index b22cb4a22..700808873 100644
--- a/sites/all/modules/form_builder/includes/form_builder.api.inc
+++ b/sites/all/modules/form_builder/includes/form_builder.api.inc
@@ -278,6 +278,22 @@ function form_builder_get_element_ids($form) {
   return $element_ids;
 }
 
+/**
+ * Recursive function to get the types of all element within a form.
+ */
+function form_builder_get_element_types($form) {
+  $element_types = array();
+  foreach (element_children($form) as $key) {
+    if (isset($form[$key]['#form_builder']['element_type'])) {
+      $element_types[] = $form[$key]['#form_builder']['element_type'];
+    }
+    $additional_types = form_builder_get_element_types($form[$key]);
+    $element_types = array_merge($element_types, $additional_types);
+  }
+
+  return $element_types;
+}
+
 /**
  * Loader function to retrieve a form builder configuration array.
  *
@@ -333,7 +349,7 @@ function form_builder_add_default_properties($form, $form_type, $key = NULL, $pa
       else {
         // If the type cannot be found, prevent editing of this field.
         unset($form['#form_builder']);
-        return;
+        return $form;
       }
     }
 
diff --git a/sites/all/modules/form_builder/includes/form_builder.cache.inc b/sites/all/modules/form_builder/includes/form_builder.cache.inc
index 5f91cb5a3..2b803759e 100644
--- a/sites/all/modules/form_builder/includes/form_builder.cache.inc
+++ b/sites/all/modules/form_builder/includes/form_builder.cache.inc
@@ -92,8 +92,6 @@ function form_builder_cache_purge($expire_threshold = NULL) {
 
   return db_delete('form_builder_cache')
     ->condition('updated', REQUEST_TIME - $expire_threshold, '<')
-    ->condition('type', $form_type)
-    ->condition('form_id', $form_id)
     ->execute();
 }
 
diff --git a/sites/all/modules/form_builder/includes/form_builder.properties.inc b/sites/all/modules/form_builder/includes/form_builder.properties.inc
index 42edc687f..f8e739152 100644
--- a/sites/all/modules/form_builder/includes/form_builder.properties.inc
+++ b/sites/all/modules/form_builder/includes/form_builder.properties.inc
@@ -242,7 +242,7 @@ function form_builder_property_default_value_form(&$form_state, $form_type, $ele
     // exception, though.
     '#type' => $element['#type'] == 'textarea' ? 'textarea' : 'textfield',
     '#title' => t('Default value'),
-    '#default_value' => $element['#default_value'],
+    '#default_value' => $element['#type'] == 'value' ? $element['#value'] : $element['#default_value'],
     '#weight' => 1,
   );
 
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc b/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
index b48773467..3466bebc3 100644
--- a/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
@@ -37,13 +37,13 @@ function _form_builder_webform_form_builder_map_date() {
         'form_parents' => array('default', 'timezone'),
         'storage_parents' => array('extra', 'timezone'),
       ),
-      'year_start' => array(
-        'form_parents' => array('validation', 'year_start'),
-        'storage_parents' => array('extra', 'year_start'),
+      'start_date' => array(
+        'form_parents' => array('validation', 'start_date'),
+        'storage_parents' => array('extra', 'start_date'),
       ),
-      'year_end' => array(
-        'form_parents' => array('validation', 'year_end'),
-        'storage_parents' => array('extra', 'year_end'),
+      'end_date' => array(
+        'form_parents' => array('validation', 'end_date'),
+        'storage_parents' => array('extra', 'end_date'),
       ),
       'year_textfield' => array(
         'form_parents' => array('display', 'year_textfield'),
@@ -204,6 +204,22 @@ function _form_builder_webform_form_builder_map_file() {
   );
 }
 
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_file($form_element) {
+  if (isset($form_element['#upload_validators'])) {
+    // Extension list and size comes from #upload_validators on load.
+    $form_element['#webform_file_extensions']['types'] = empty($form_element['#upload_validators']['file_validate_extensions'][0]) ? array() : explode(' ', $form_element['#upload_validators']['file_validate_extensions'][0]);
+    $form_element['#webform_file_size'] = empty($form_element['#upload_validators']['file_validate_size'][0]) ? '' : format_size($form_element['#upload_validators']['file_validate_size'][0]);
+    // File directory and scheme come from #upload_location on load.
+    $form_element['#webform_file_directory'] = preg_replace('/^webform[\/]?/', '', file_uri_target($form_element['#upload_location']));
+    $form_element['#webform_file_scheme'] = file_uri_scheme($form_element['#upload_location']);
+  }
+
+  return $form_element;
+}
+
 /**
  * Implements _form_builder_webform_form_builder_preview_alter_component().
  */
@@ -384,6 +400,17 @@ function _form_builder_webform_form_builder_types_hidden() {
   return $fields;
 }
 
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_hidden($form_element) {
+  // Hidden elements may be #type "value" or "hidden". Set the internal property
+  // to keep track of hidden fields.
+  $form_element['#form_builder']['element_type'] = 'hidden';
+
+  return $form_element;
+}
+
 /**
  * Implements _form_builder_webform_form_builder_preview_alter_component().
  */
@@ -399,12 +426,7 @@ function _form_builder_webform_form_builder_preview_alter_hidden($form_element)
 
   // Display the title of the hidden field as regular markup.
   $form_element['#children'] = t('@title - <em>hidden field</em>', array('@title' => $form_element['#title']));
-  $form_element['#title_display'] = 'none';
-
-  // Give the element a wrapper class so that themers can recognize it
-  // represents a hidden element.
-  $form_element['#attributes']['class'][] = 'form-builder-preview-hidden-webform-element';
-  array_unshift($form_element['#theme_wrappers'], 'container');
+  $form_element['#title'] = NULL;
 
   return $form_element;
 }
@@ -598,12 +620,30 @@ function _form_builder_webform_form_builder_load_pagebreak($form_element) {
   // Pagebreak components are rendered as hidden elements by webform, but
   // hidden elements do not have a #title property. So we have to convert the
   // rendered value to be used as the #title instead.
-  if ($form_element['#type'] == 'pagebreak') {
-    $form_element['#title'] = $form_element['#value'];
-  }
+  $form_element['#title'] = $form_element['#value'];
+  $form_element['#form_builder']['element_type'] = 'pagebreak';
+
   return $form_element;
 }
 
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_pagebreak($component, $form_element) {
+  // Ensure pagebreaks are saved at the root level.
+  if ($component['pid'] !== 0) {
+    drupal_set_message(t('Page breaks may not be nested inside fieldsets. Each pagebreak has been moved outside of fieldsets.'), 'status', FALSE);
+
+    $form_cache = form_builder_cache_load('webform', $form_element['#form_builder']['form_id']);
+    $parent = form_builder_get_element($form_cache, $form_element['#form_builder']['parent_id']);
+
+    $component['weight'] = $parent['#weight'] + 1;
+    $component['pid'] = 0;
+  }
+
+  return $component;
+}
+
 /**
  * Implements _form_builder_webform_form_builder_preview_alter_component().
  */
@@ -746,7 +786,7 @@ function _form_builder_webform_form_builder_save_select($component, $form_elemen
  */
 function form_builder_webform_property_select_options_form(&$form_state, $form_type, $element) {
   // Use the default options form, but enhance to allow Webform tokens.
-  $form = form_builder_property_options_form($form_state, $form_type, $element);
+  $form = form_builder_property_options_form($form_state, $form_type, $element, 'options');
   $form['options']['#default_value_pattern'] = '^%.+\[.+\]$';
   return $form;
 }
@@ -885,7 +925,7 @@ function _form_builder_webform_form_builder_map_time() {
         'storage_parents' => array('extra', 'timezone'),
       ),
       'hourformat' => array(
-        'storage_parents' => array('display', 'hourformat'),
+        'form_parents' => array('display', 'hourformat'),
         'storage_parents' => array('extra', 'hourformat'),
       ),
     ),
@@ -916,8 +956,9 @@ function _form_builder_webform_mapped_form(&$form_state, $form_type, $element, $
 function _form_builder_webform_save_mapped_component($component, $element) {
   if ($map = _form_builder_webform_property_map($component['type'])) {
     foreach ($map['properties'] as $property => $property_map) {
-      if (isset($element['#' . $property]) && isset($property_map['storage_parents'])) {
-        _form_builder_webform_save_mapped_component_value($component, $element['#' . $property], $property_map['storage_parents']);
+      if (isset($property_map['storage_parents'])) {
+        $property_value = isset($element['#' . $property]) ? $element['#' . $property] : NULL;
+        _form_builder_webform_save_mapped_component_value($component, $property_value, $property_map['storage_parents']);
       }
     }
   }
@@ -967,6 +1008,9 @@ function _form_builder_webform_default($component_type, $merge_extras = array())
   // Call the loading function to make sure that the default element gets the
   // same treatment as an existing one.
   $default_element = _form_builder_webform_set_mapped_type($default_element);
+  if ($element = form_builder_webform_component_invoke($component_type, 'form_builder_load', $default_element)) {
+    $default_element = $element;
+  }
 
   return $default_element;
 }
@@ -1016,11 +1060,12 @@ function _form_builder_webform_build_edit_form($component_type, $element, $prope
   // component.
   $defaults_function = '_webform_defaults_' . $component_type;
   $component = isset($element['#webform_component']) ? $element['#webform_component'] : $defaults_function();
+  $nid = isset($component['nid']) ? $component['nid'] : NULL;
 
   // The most up-to-date configuration data stored by Form Builder for the
   // part of the component we are editing is also stored in the passed-in
   // element, and should always take precedence.
-  if (isset($element["#$property"])) {
+  if (array_key_exists("#$property", $element)) {
     drupal_array_set_nested_value($component, $component_nested_keys, $element["#$property"]);
   }
 
@@ -1028,7 +1073,10 @@ function _form_builder_webform_build_edit_form($component_type, $element, $prope
   // the component, and obtain the slice of it that we want.
   $empty_form = array();
   $empty_form_state = form_state_defaults();
-  $node = (object) array('nid' => NULL);
+
+  // The full node is needed here so that the "private" option can be access
+  // checked.
+  $node = !isset($nid) ? (object) array('nid' => NULL) : node_load($nid);
   $form = webform_component_edit_form($empty_form, $empty_form_state, $node, $component);
   $form = drupal_array_get_nested_value($form, $form_nested_keys);
 
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.info b/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
index 3f48fec72..a6856e38a 100644
--- a/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
@@ -4,9 +4,9 @@ core = 7.x
 dependencies[] = form_builder
 dependencies[] = webform
 
-; Information added by drupal.org packaging script on 2012-03-08
-version = "7.x-1.0"
+; Information added by drupal.org packaging script on 2012-09-27
+version = "7.x-1.3"
 core = "7.x"
 project = "form_builder"
-datestamp = "1331181344"
+datestamp = "1348708781"
 
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.module b/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
index a0d356e2a..2a7c83856 100644
--- a/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
@@ -52,11 +52,14 @@ function form_builder_webform_save_form($form, &$form_state, $nid) {
     '#type' => 'value',
     '#value' => $nid,
   );
-  $form['save'] = array(
+  $form['actions'] = array(
+    '#type' => 'actions',
+  );
+  $form['actions']['save'] = array(
     '#type' => 'submit',
     '#value' => t('Save'),
   );
-  $form['cancel'] = array(
+  $form['actions']['cancel'] = array(
     '#type' => 'submit',
     '#value' => t('Cancel'),
     '#submit' => array('form_builder_webform_cancel'),
@@ -81,22 +84,47 @@ function form_builder_webform_save_node($node) {
   $form_cache = form_builder_cache_load('webform', $node->nid);
   $element_ids = form_builder_preview_prepare($form_cache, 'webform', $node->nid);
 
-  // Save modified or created components.
-  foreach ($element_ids as $id) {
-    form_builder_webform_save_component($node, $id, $form_cache);
-  }
-
-  // Delete components that have been removed.
+  // Remove components if deleted and calculate the highest in-use CID.
+  $max_cid = 0;
   foreach ($node->webform['components'] as $component) {
     $element_id = 'cid_' . $component['cid'];
+    $cid = $component['cid'];
+
+    // Max CID is used in the creation of new components, preventing conflicts.
+    $max_cid = max($max_cid, $cid);
+
+    // Remove components from the $node that have been removed in the UI.
     if (!in_array($element_id, $element_ids)) {
-      webform_component_delete($node, $component);
+      if (isset($node->webform['components'][$cid])) {
+        unset($node->webform['components'][$cid]);
+      }
+    }
+  }
+
+  // Update any new/updated components in the node record.
+  foreach ($element_ids as $element_id) {
+    $component = form_builder_webform_get_component($node, $element_id, $form_cache);
+    if ($component) {
+      if (empty($component['cid'])) {
+        $cid = ++$max_cid;
+        $component['cid'] = $cid;
+        // Reassign the component ID to the form so that future elements that
+        // may depend on this one set their parent ID (pid) properly.
+        $element = form_builder_get_element($form_cache, $element_id);
+        $element['#webform_component']['cid'] = $cid;
+        form_builder_set_element($form_cache, $element);
+      }
+      else {
+        $cid = $component['cid'];
+      }
+      $node->webform['components'][$cid] = $component;
     }
   }
 
-  // Reset the node cache, since $node->webform['components'] has changed.
-  // @todo: Decide if this belongs in the above Webform API functions instead?
-  entity_get_controller('node')->resetCache(array($node->nid));
+  // Save the node itself to update components and allow other modules to
+  // respond to any changes. The Form Builder cache is intentionally left in
+  // place so other modules can check it for changes also.
+  node_save($node);
 
   // Remove the cached form_builder form.
   form_builder_cache_delete('webform', $node->nid);
@@ -105,7 +133,7 @@ function form_builder_webform_save_node($node) {
 /**
  * Save the contents of a form component into Webform's database tables.
  */
-function form_builder_webform_save_component($node, $element_id, $form) {
+function form_builder_webform_get_component($node, $element_id, $form) {
   module_load_include('inc', 'form_builder_webform', 'form_builder_webform.components');
 
   $element = form_builder_get_element($form, $element_id);
@@ -140,21 +168,9 @@ function form_builder_webform_save_component($node, $element_id, $form) {
   $component['pid'] = 0;
 
   // Set the parent ID for the component if it is nested inside another component.
-  // This must be done this way so that children of newly added components get a
-  // proper pid when the cid of the new component has just been generated.
   $parent = form_builder_get_element($form, $element['#form_builder']['parent_id']);
-  if ($parent) {
-    // If the parent is new, the database must be queried for the cid of the parent.
-    if (isset($parent['#webform_component']['is_new']) && $parent['#webform_component']['is_new']) {
-      $results = db_query('SELECT cid, form_key FROM {webform_component} WHERE form_key = :key AND nid = :nid', array(':key' => $element['#form_builder']['parent_id'], ':nid' => $node->nid));
-      foreach($results as $result) {
-        $component['pid'] = $result->cid;
-      }
-    }
-    // If the parent is already stored in the webform, grab its cid value.
-    elseif (isset($parent['#webform_component']['cid'])) {
-      $component['pid'] = $parent['#webform_component']['cid'];
-    }
+  if ($parent && isset($parent['#webform_component']['cid'])) {
+    $component['pid'] = $parent['#webform_component']['cid'];
   }
 
   // Set the component's value. If the form element doesn't have a default,
@@ -176,12 +192,7 @@ function form_builder_webform_save_component($node, $element_id, $form) {
     $component = $saved_component;
   }
 
-  if (!isset($component['cid'])) {
-    webform_component_insert($component);
-  }
-  elseif ($component != $node->webform['components'][$component['cid']]) {
-    webform_component_update($component);
-  }
+  return $component;
 }
 
 /**
@@ -272,32 +283,11 @@ function form_builder_webform_form_builder_load($form_builder_type, $form_builde
     $nid = $form_builder_id;
     $node = node_load($nid);
 
-    // Since webform_client_form() has special handling for the 'pagebreak'
-    // component that we do not want to occur here (here we want to display the
-    // entire webform on a single page, without page breaks), we temporarily
-    // change the component to 'pagebreak_clone' and then change it back
-    // afterwards. See _webform_render_pagebreak_clone().
-    // @todo: Replace this with something cleaner, if webform eventually allows
-    //   us to do that.
-    $pagebreak_component_keys = array();
-    foreach ($node->webform['components'] as &$component) {
-      if ($component['type'] == 'pagebreak') {
-        $component['type'] = 'pagebreak_clone';
-        $pagebreak_component_keys[] = $component['form_key'];
-      }
-    }
-
     // Get the unfiltered version of the client form.
     $form = array();
     $form_state = array();
     $form = webform_client_form($form, $form_state, $node, array(), TRUE, FALSE);
 
-    // Change 'pagebreak' components back, as described above.
-    foreach ($pagebreak_component_keys as $key) {
-      $form['submitted'][$key]['#type'] = 'pagebreak';
-      $form['submitted'][$key]['#webform_component']['type'] = 'pagebreak';
-    }
-
     // Perform final processing of the form, and return it.
     $form += array('submitted' => array());
     form_builder_webform_load_process($form['submitted'], $node);
@@ -340,6 +330,7 @@ function form_builder_webform_load_process(&$form, $node, $pid = 0) {
  */
 function form_builder_webform_form_builder_add_element_alter(&$element, $form_type, $form_id) {
   if ($form_type == 'webform') {
+    $element['#webform_component']['nid'] = is_numeric($form_id) ? $form_id : NULL;
     $element['#webform_component']['is_new'] = TRUE;
   }
 }
@@ -369,7 +360,7 @@ function form_builder_webform_form_builder_preview_alter(&$element, $form_type,
     }
 
     // A #title_display property of 0 (as stored by Webform) means no setting.
-    if (isset($element['#title_display']) && $element['#title_display'] == 0) {
+    if (isset($element['#title_display']) && strcmp('0', $element['#title_display']) === 0) {
       unset($element['#title_display']);
     }
   }
@@ -454,20 +445,6 @@ function form_builder_webform_component_invoke($component_type, $callback) {
   }
 }
 
-/**
- * Implements _webform_render_component().
- *
- * This "component" is only used as a temporary replacement for the standard
- * pagebreak component when the form builder version of the webform is being
- * rendered; this occurs when form_builder_webform_form_builder_load() calls
- * webform_client_form(). Therefore, we do not need to register it as a regular
- * webform component anywhere else (and don't want to, since we don't want it
- * to be available elsewhere in the webform UI).
- */
-function _webform_render_pagebreak_clone($component, $value = NULL, $filter = TRUE) {
-  return webform_component_invoke('pagebreak', 'render', $component, $value, $filter);
-}
-
 /**
  * Helper function; Retrieve a component's map and merge in generic properties.
  */
@@ -501,7 +478,7 @@ function _form_builder_webform_property_map($component_type) {
     }
 
     if (webform_component_feature($component_type, 'private')) {
-      $map['properties']['private'] = array(
+      $map['properties']['webform_private'] = array(
         'form_parents' => array('display', 'private'),
         'storage_parents' => array('extra', 'private'),
       );
@@ -514,6 +491,8 @@ function _form_builder_webform_property_map($component_type) {
     // All components support the key property.
     $map['properties']['key'] = array();
 
+    drupal_alter('form_builder_webform_property_map', $map, $component_type);
+
     $maps[$component_type] = $map;
   }
 
-- 
GitLab