Index: modules/webform/form_builder_webform.components.inc
===================================================================
RCS file: modules/webform/form_builder_webform.components.inc
diff -N modules/webform/form_builder_webform.components.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/webform/form_builder_webform.components.inc	29 Dec 2010 03:33:56 -0000
@@ -0,0 +1,724 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   Default webform component callbacks for functionality related to the Form Builder.
+ */
+
+/**
+ * @defgroup form-builder-webform-email-callbacks Callbacks for the Email component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_email() {
+  $fields = array();
+
+  $fields['email'] = array(
+    'title' => t('E-mail'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'size',
+      'key',
+      'title_display',
+    ),
+    'default' => array(
+      '#title' => t('New e-mail'),
+      '#type' => 'textfield',
+      '#theme_wrappers' => array('webform_element'),
+      '#form_builder' => array('element_type' => 'email'),
+      '#title_display' => 'above',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_email($component, $form_element) {
+  $component['extra']['width'] = isset($form_element['#size']) ? $form_element['#size'] : NULL;
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-email-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-fieldset-callbacks Callbacks for the Fieldset component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_fieldset() {
+  $fields = array();
+
+  $fields['fieldset'] = array(
+    'title' => t('Fieldset'),
+    'properties' => array(
+      'title',
+      'description',
+      'collapsible',
+      'collapsed',
+      'key',
+    ),
+    'default' => array(
+      '#title' => t('New fieldset'),
+      '#type' => 'fieldset',
+      '#collapsible' => FALSE,
+      '#collapsed' => FALSE,
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_fieldset($component, $form_element) {
+  $component['extra']['collapsible'] = isset($form_element['#collapsible']) ? $form_element['#collapsible'] : NULL;
+  $component['extra']['collapsed'] = isset($form_element['#collapsed']) ? $form_element['#collapsed'] : NULL;
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : '';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-fieldset-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-file-callbacks Callbacks for the File component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_file() {
+  $defaults = _webform_defaults_file();
+
+  $fields['file'] = array(
+    'title' => t('File'),
+    'properties' => array(
+      'title',
+      'description',
+      'required',
+      'key',
+      'title_display',
+      'webform_file_filtering',
+      'webform_file_savelocation',
+      'webform_file_width',
+    ),
+    'default' => array(
+      '#title' => t('New file'),
+      '#type' => 'file',
+      '#theme_wrappers' => array('webform_element'),
+      '#title_display' => 'above',
+      '#webform_file_filtering' => $defaults['extra']['filtering'],
+      '#webform_file_savelocation' => $defaults['extra']['savelocation'],
+      '#webform_file_width' => $defaults['extra']['width'],
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_properties_component().
+ */
+function _form_builder_webform_form_builder_properties_file() {
+  return array(
+    'webform_file_filtering' => array(
+      'form' => 'form_builder_webform_property_webform_file_filtering_form',
+    ),
+    'webform_file_savelocation' => array(
+      'form' => 'form_builder_webform_property_webform_file_savelocation_form',
+    ),
+    'webform_file_width' => array(
+      'form' => 'form_builder_webform_property_webform_file_width_form',
+    ),
+  );
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_file($form_element) {
+  // If we are loading a file element, the actual element we want to render is
+  // stored in one of its children (indicated by the #webform_form_key
+  // property), so we inherit data from that and then remove the children we
+  // don't want. See _webform_render_file().
+  if (isset($form_element['#webform_form_key'])) {
+    $key = $form_element['#webform_form_key'];
+    if (!empty($form_element[$key]['#type']) && $form_element[$key]['#type'] == 'file') {
+      $form_element['#type'] = $form_element[$key]['#type'];
+      unset($form_element['#theme']);
+      foreach (element_children($form_element) as $key) {
+        unset($form_element[$key]);
+      }
+      // Webform stores the #required property for files in a custom key, so
+      // copy that value into the actual #required property here.
+      if (isset($form_element['#webform_required'])) {
+        $form_element['#required'] = $form_element['#webform_required'];
+      }
+      // Set the custom webform file properties based on the values stored with
+      // the webform component.
+      if (isset($form_element['#webform_component']['extra']['filtering'])) {
+        $form_element['#webform_file_filtering'] = $form_element['#webform_component']['extra']['filtering'];
+      }
+      if (isset($form_element['#webform_component']['extra']['savelocation'])) {
+        $form_element['#webform_file_savelocation'] = $form_element['#webform_component']['extra']['savelocation'];
+      }
+      if (isset($form_element['#webform_component']['extra']['width'])) {
+        $form_element['#webform_file_width'] = $form_element['#webform_component']['extra']['width'];
+      }
+    }
+  }
+
+  return $form_element;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_file($component, $form_element) {
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  $component['extra']['filtering'] = isset($form_element['#webform_file_filtering']) ? $form_element['#webform_file_filtering'] : array();
+  $component['extra']['savelocation'] = isset($form_element['#webform_file_savelocation']) ? $form_element['#webform_file_savelocation'] : NULL;
+  $component['extra']['width'] = isset($form_element['#webform_file_width']) ? $form_element['#webform_file_width'] : NULL;
+
+  return $component;
+}
+
+/**
+ * Configuration form for the "webform_file_filtering" property.
+ */
+function form_builder_webform_property_webform_file_filtering_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_file_edit_form($element, 'webform_file_filtering', 'validation', array('validation', 'filtering'), array('extra', 'filtering'));
+}
+
+/**
+ * Configuration form for the "webform_file_savelocation" property.
+ */
+function form_builder_webform_property_webform_file_savelocation_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_file_edit_form($element, 'webform_file_savelocation', 'default', array('extra', 'savelocation'), array('extra', 'savelocation'));
+}
+
+/**
+ * Configuration form for the "webform_file_width" property.
+ */
+function form_builder_webform_property_webform_file_width_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_file_edit_form($element, 'webform_file_width', 'display', array('display', 'width'), array('extra', 'width'));
+}
+
+/**
+ * Helper function; builds a form for editing part of a webform file component.
+ *
+ * The returned form is derived from a subcomponent of the _webform_edit_file()
+ * form provided by the Webform module.
+ *
+ * @param $element
+ *   A form array representing the file element whose configuration form we are
+ *   building.
+ * @param $property
+ *   The property of $element which stores the state of portions of the webform
+ *   component that this form is responsible for configuring. The property
+ *   should be passed in without the leading "#".
+ * @param $form_builder_property_group
+ *   The Form Builder property group in which this configuration form should be
+ *   displayed.
+ * @param $form_nested_keys
+ *   An array of nested keys representing the location of the subcomponent of
+ *   the _webform_edit_file() form that this configuration form will be taken
+ *   from. For example, if the part of the configuration form we are interested
+ *   in is located in $form['display']['width'], where $form is the output of
+ *   _webform_edit_file(), we would pass array('display', 'width') in for this
+ *   parameter.
+ * @param $component_nested_keys
+ *   An array of nested keys representing the location of the portions of the
+ *   webform component that this form is responsible for configuring. For
+ *   example, if this form configures the data that is stored in
+ *   $component['extra']['filtering'], where $component has the structure of
+ *   the array returned by _webform_defaults_file(), we would pass
+ *   array('extra', 'filtering') in for this parameter.
+ *
+ * @return
+ *   A form array that can be used to edit the specified part of the webform
+ *   file component represented by $element.
+ *
+ * @see _webform_edit_file()
+ * @see _webform_defaults_file()
+ */
+function _form_builder_webform_build_file_edit_form($element, $property, $form_builder_property_group, $form_nested_keys, $component_nested_keys) {
+  // The Webform module stores existing component data as part of the passed-in
+  // element. If the component doesn't exist yet, initialize a default
+  // component.
+  $component = isset($element['#webform_component']) ? $element['#webform_component'] : _webform_defaults_file();
+
+  // 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"])) {
+    // This code is based on drupal_array_set_nested_value() in Drupal 7 and
+    // sets the part of the $component array specified by the provided keys.
+    $ref = &$component;
+    foreach ($component_nested_keys as $key) {
+      $ref = &$ref[$key];
+    }
+    $ref = $element["#$property"];
+  }
+
+  // Build the entire _webform_edit_file() form based on the current state of
+  // the component, and obtain the slice of it that we want.
+  $form = _webform_edit_file($component);
+  // Obtain the slice using code based on drupal_array_set_nested_value() in
+  // Drupal 7.
+  $ref = &$form;
+  foreach ($form_nested_keys as $key) {
+    $ref = &$ref[$key];
+  }
+  $form = $ref;
+
+  // Force the form to have a consistent #tree structure so it will appear in
+  // $form_state['values'] the way we want.
+  _form_builder_webform_force_tree($form);
+
+  // Indicate the Form Builder property group that this form will be displayed
+  // in.
+  $form['#form_builder'] = array('property_group' => $form_builder_property_group);
+
+  // Return the form, keyed by the name of the property that is being
+  // configured.
+  return array($property => $form);
+}
+
+/**
+ * Helper function; replaces custom form #parents with a #tree structure.
+ *
+ * This is a helper function to force #tree = TRUE on all parts of a form,
+ * regardless of any custom #parents that were originally defined as part of
+ * the form. It is used to ensure a consistent structure within
+ * $form_state['values'] when the form is submitted.
+ *
+ * @param $form
+ *   The form array to modify.
+ */
+function _form_builder_webform_force_tree(&$form) {
+  unset($form['#parents']); 
+  $form['#tree'] = TRUE; 
+  foreach (element_children($form) as $key) {
+    _form_builder_webform_force_tree($form[$key]);
+  }
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-file-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-hidden-callbacks Callbacks for the Hidden component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_hidden() {
+  $fields = array();
+
+  $fields['hidden'] = array(
+    'title' => t('Hidden'),
+    'properties' => array(
+      'title',
+      'default_value',
+      'key',
+    ),
+    'default' => array(
+      '#title' => t('Hidden field'),
+      '#type' => 'hidden',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_hidden($form_element) {
+  // Convert the hidden element to a markup element before displaying it.
+  $form_element['#type'] = 'markup';
+  $form_element['#form_builder']['element_type'] = 'markup';
+  unset($form_element['#theme']);
+
+  // Display the title of the hidden field as regular markup.
+  $form_element['#value'] = t('@title - <em>hidden field</em>', array('@title' => $form_element['#title']));
+
+  return $form_element;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-hidden-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-markup-callbacks Callbacks for the Markup component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_markup() {
+  $fields = array();
+
+  $default = '';
+  $default .= '<p><strong>' . t('New HTML Markup') . '</strong></p>' . "\n\n";
+  $default .= '<p>' . t('Enter any text supported by available text formats.') . '</p>';
+
+  $fields['markup'] = array(
+    'title' => t('Markup'),
+    'properties' => array(
+      'title',
+      'markup',
+      'input_format',
+      'key',
+      'title_display',
+    ),
+    'default' => array(
+      '#title' => t('Markup'),
+      '#type' => 'markup',
+      '#theme_wrappers' => array('webform_element'),
+      '#markup' => $default,
+      '#input_format' => variable_get('filter_default_format', 1),
+      '#title_display' => 'above',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_markup($component, $form_element) {
+  $component['value'] = $form_element['#markup'];
+  $component['extra']['format'] = isset($form_element['#input_format']) ? $form_element['#input_format'] : variable_get('filter_default_format', 1);
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_markup($form_element) {
+  // Filter the markup with the appropriate text format before displaying it.
+  $value = isset($form_element['#markup']) ? $form_element['#markup'] : '';
+  $format = isset($form_element['#input_format']) ? $form_element['#input_format'] : variable_get('filter_default_format', 1);
+  $form_element['#value'] = check_markup(_webform_filter_values($value, NULL, NULL, NULL, FALSE), $format);
+  if (strlen(trim($form_element['#value'])) == 0) {
+    $form_element['#value'] = t('Empty markup field');
+  }
+
+  return $form_element;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-markup-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-pagebreak-callbacks Callbacks for the Pagebreak component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_pagebreak() {
+  $fields = array();
+
+  $fields['pagebreak'] = array(
+    'title' => t('Page break'),
+    'properties' => array(
+      'title',
+      'key',
+    ),
+    'default' => array(
+      '#title' => t('Page break'),
+      '#type' => 'pagebreak',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+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'];
+  }
+  return $form_element;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_pagebreak($form_element) {
+  // Convert the pagebreak element to a markup element before displaying it.
+  $form_element['#type'] = 'markup';
+  $form_element['#form_builder']['element_type'] = 'markup';
+  unset($form_element['#theme']);
+
+  // Display the title of the pagebreak field as regular markup.
+  $form_element['#value'] = '--- ' . check_plain($form_element['#title']) . ' ---';
+  $form_element['#value'] .= '<div class="description">' . t('(Fields below will be displayed on a new page)') . '</div>';
+
+  return $form_element;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-pagebreak-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-select-callbacks Callbacks for the Select component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_select() {
+  $fields = array();
+
+  $fields['select'] = array(
+    'title' => t('Select list'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'multiple',
+      'key',
+      'title_display',
+    ),
+    'default' => array(
+      '#title' => t('New select list'),
+      '#type' => 'select',
+      '#theme_wrappers' => array('webform_element'),
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => 'one',
+      '#webform' => array('type' => 'select'),
+      '#title_display' => 'above',
+    ),
+  );
+
+  $fields['checkboxes'] = array(
+    'title' => t('Checkboxes'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'multiple',
+      'key',
+      'title_display',
+    ),
+    'default' => array(
+      '#title' => t('New checkboxes'),
+      '#type' => 'checkboxes',
+      '#theme_wrappers' => array('checkboxes', 'webform_element'),
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => array('one', 'two'),
+      '#multiple' => TRUE,
+      '#webform' => array('type' => 'select'),
+      '#title_display' => 'above',
+    ),
+  );
+
+  $fields['radios'] = array(
+    'title' => t('Radios'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'key',
+      'title_display',
+    ),
+    'default' => array(
+      '#title' => t('New radios'),
+      '#type' => 'radios',
+      '#theme_wrappers' => array('radios', 'webform_element'),
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => 'one',
+      '#webform' => array('type' => 'select'),
+      '#title_display' => 'above',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_select($form_element) {
+  if (in_array($form_element['#type'], array('radios', 'checkboxes', 'select'))) {
+    $form_element['#webform']['type'] = 'select';
+    if ($form_element['#type'] == 'checkboxes') {
+      $form_element['#multiple'] = TRUE;
+    }
+    return $form_element;
+  }
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_select($component, $form_element) {
+  $options = '';
+
+  foreach ($form_element['#options'] as $key => $option_value) {
+    $options .= $key . '|' . $option_value . "\n";
+  }
+
+  $component['extra']['items'] = $options;
+  $component['extra']['multiple'] = $form_element['#form_builder']['element_type'] == 'checkboxes';
+  $component['extra']['aslist'] = $form_element['#form_builder']['element_type'] == 'select';
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : '';
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-select-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-textarea-callbacks Callbacks for the Textarea component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_textarea() {
+  $fields = array();
+
+  $fields['textarea'] = array(
+    'title' => t('Textarea'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'rows',
+      'cols',
+      'key',
+      'title_display',
+    ),
+    'default' => array(
+      '#title' => t('New textarea'),
+      '#type' => 'textarea',
+      '#theme_wrappers' => array('webform_element'),
+      '#title_display' => 'above',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_textarea($component, $form_element) {
+  $component['extra']['description'] = $form_element['#description'];
+  $component['extra']['cols'] = $form_element['#cols'];
+  $component['extra']['rows'] = $form_element['#rows'];
+  $component['extra']['disabled'] = empty($form_element['#disabled']) ? NULL : TRUE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-textarea-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-textfield-callbacks Callbacks for the Textfield component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_textfield() {
+  $fields = array();
+
+  $fields['textfield'] = array(
+    'title' => t('Textfield'),
+    'properties' => array(
+      'title',
+      'description',
+      'field_prefix',
+      'field_suffix',
+      'default_value',
+      'required',
+      'size',
+      'key',
+      'title_display',
+    ),
+    'default' => array(
+      '#title' => t('New textfield'),
+      '#type' => 'textfield',
+      '#theme_wrappers' => array('webform_element'),
+      '#title_display' => 'above',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_textfield($component, $form_element) {
+  $component['extra']['width'] = isset($form_element['#size']) ? $form_element['#size'] : NULL;
+  $component['extra']['maxlength'] = isset($form_element['#maxlength']) ? $form_element['#maxlength'] : NULL;
+  $component['extra']['field_prefix'] = isset($form_element['#field_prefix']) ? $form_element['#field_prefix'] : NULL;
+  $component['extra']['field_suffix'] = isset($form_element['#field_suffix']) ? $form_element['#field_suffix'] : NULL;
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-textfield-callbacks"
+ */
Index: modules/webform/form_builder_webform.info
===================================================================
RCS file: modules/webform/form_builder_webform.info
diff -N modules/webform/form_builder_webform.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/webform/form_builder_webform.info	29 Dec 2010 03:33:56 -0000
@@ -0,0 +1,6 @@
+; $Id$
+name = Form builder Webform UI
+description = Form builder integration for the Webform module.
+core = 6.x
+dependencies[] = form_builder
+dependencies[] = webform
Index: modules/webform/form_builder_webform.module
===================================================================
RCS file: modules/webform/form_builder_webform.module
diff -N modules/webform/form_builder_webform.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/webform/form_builder_webform.module	29 Dec 2010 03:33:56 -0000
@@ -0,0 +1,363 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   Form Builder integration for the Webform module.
+ */
+
+/**
+ * Implements hook_menu_alter().
+ */
+function form_builder_webform_menu_alter(&$items) {
+  $items['node/%webform_menu/webform']['page callback'] = 'form_builder_webform_components_page';
+  $items['node/%webform_menu/webform/components']['page callback'] = 'form_builder_webform_components_page';
+}
+
+/**
+ * Menu callback; display a form builder interface to edit webform components.
+ */
+function form_builder_webform_components_page($node) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
+
+  $output = '';
+  $output .= form_builder_interface('webform', $node->nid);
+  $output .= drupal_get_form('form_builder_webform_save_form', $node->nid);
+
+  return $output;
+}
+
+/**
+ * Form to save the Form Builder interface.
+ *
+ * The actual Form Builder interface is displayed as part of the
+ * form_builder_webform_components_page() function.
+ */
+function form_builder_webform_save_form(&$form_state, $nid) {
+  $form['nid'] = array(
+    '#type' => 'value',
+    '#value' => $nid,
+  );
+  $form['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  $form['cancel'] = array(
+    '#type' => 'submit',
+    '#value' => t('Cancel'),
+    '#submit' => array('form_builder_webform_cancel'),
+  );
+
+  return $form;
+}
+
+/**
+ * Submit handler; save the current Form Builder interface changes.
+ */
+function form_builder_webform_save_form_submit($form, &$form_state) {
+  $node = node_load($form_state['values']['nid']);
+  form_builder_webform_save_node($node);
+  drupal_set_message(t('Changes to the form have been saved.'));
+}
+
+/**
+ * Save the current Form Builder interface changes for a webform node.
+ */
+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.
+  foreach ($node->webform['components'] as $component) {
+    $element_id = 'cid_' . $component['cid'];
+    if (!in_array($element_id, $element_ids)) {
+      webform_component_delete($node, $component);
+    }
+  }
+
+  // Reset the node cache, since $node->webform['components'] has changed.
+  // @todo: Decide if this belongs in the above Webform API functions instead?
+  node_load(NULL, NULL, TRUE);
+
+  // Remove the cached form_builder form.
+  form_builder_cache_delete('webform', $node->nid);
+}
+
+/**
+ * Save the contents of a form component into Webform's database tables.
+ */
+function form_builder_webform_save_component($node, $element_id, $form) {
+  $element = form_builder_get_element($form, $element_id);
+  $type = isset($element['#webform']['type']) ? $element['#webform']['type'] : $element['#form_builder']['element_type'];
+
+  // Check for existing components.
+  $cid = substr($element_id, 4);
+  if (isset($node->webform['components'][$cid])) {
+    $component = $node->webform['components'][$cid];
+  }
+  // Populate a new default component.
+  elseif (isset($element['#webform']['is_new'])) {
+    if ($component = webform_component_invoke($type, 'defaults')) {
+      $component['type'] = $type;
+    }
+  }
+
+  // If the component type isn't found, don't try to save anything.
+  if (!isset($component)) {
+    return;
+  }
+
+  // Set typical component settings.
+  $component['name'] = $element['#title'];
+  $component['weight'] = $element['#weight'];
+  $component['form_key'] = $element['#key'];
+  $component['mandatory'] = isset($element['#required']) ? $element['#required'] : 0;
+  $component['email'] = 0;
+  $component['nid'] = $node->nid;
+
+  // Set the parent ID to default to the form base.
+  $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']['is_new']) && $parent['#webform']['is_new']) {
+      $results = db_query("SELECT cid, form_key FROM {webform_component} WHERE form_key = '%s' AND nid = %d", $element['#form_builder']['parent_id'], $node->nid);
+      while ($result = db_fetch_object($results)) {
+        $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'];
+    }
+  }
+
+  // Set the component's value. If the form element doesn't have a default,
+  // then new components should not be modified (they should use whatever the
+  // component default is), but existing components should have their stored
+  // value removed.
+  if (isset($element['#default_value'])) {
+    $component['value'] = is_array($element['#default_value']) ? implode(',', $element['#default_value']) : $element['#default_value'];
+  }
+  elseif (empty($element['#webform']['is_new'])) {
+    $component['value'] = NULL;
+  }
+
+  // Save any specific settings.
+  if ($saved_component = form_builder_webform_component_invoke($type, 'form_builder_save', $component, $element)) {
+    $component = $saved_component;
+  }
+
+  if (!isset($component['cid'])) {
+    webform_component_insert($component);
+  }
+  elseif ($component != $node->webform['components'][$component['cid']]) {
+    webform_component_update($component);
+  }
+}
+
+/**
+ * Submit handler for the "Cancel" button.
+ */
+function form_builder_webform_cancel(&$form, &$form_state) {
+  drupal_set_message(t('Changes to the form have been discarded.'));
+  form_builder_cache_delete('webform', $form_state['values']['nid']);
+}
+
+/**
+ * Implements hook_form_builder_types().
+ *
+ * Define the fields within webforms that are editable.
+ */
+function form_builder_webform_form_builder_types() {
+  $fields = array();
+
+  $components = webform_components();
+  foreach ($components as $type => $component) {
+    if ($additional_fields = form_builder_webform_component_invoke($type, 'form_builder_types')) {
+      $fields = array_merge($fields, $additional_fields);
+    }
+  }
+
+  return array('webform' => $fields);
+}
+
+/**
+ * Implements hook_form_builder_properties().
+ */
+function form_builder_webform_form_builder_properties($form_type) {
+  $properties = array();
+
+  if ($form_type == 'webform') {
+    $components = webform_components();
+    foreach ($components as $type => $component) {
+      if ($additional_properties = form_builder_webform_component_invoke($type, 'form_builder_properties')) {
+        $properties = array_merge($properties, $additional_properties);
+      }
+    }
+  }
+
+  return $properties;
+}
+
+/**
+ * Implements hook_form_builder_load().
+ *
+ * Load a complete FAPI array based on a form type and ID.
+ */
+function form_builder_webform_form_builder_load($form_builder_type, $form_builder_id) {
+  if ($form_builder_type == 'webform') {
+    // Webform identifies its forms by Node Id.
+    $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_state, $node, array(), TRUE, FALSE);
+
+    // Change 'pagebreak' components back, as described above.
+    foreach ($pagebreak_component_keys as $key) {
+      $form['submitted'][$key]['#type'] = 'pagebreak';
+    }
+
+    // Perform final processing of the form, and return it.
+    $form += array('submitted' => array());
+    form_builder_webform_load_process($form['submitted'], $node);
+    return $form['submitted'];
+  }
+}
+
+/**
+ * Recursive helper function to populate #form_builder['element_id'] values.
+ */
+function form_builder_webform_load_process(&$form, $node, $pid = 0) {
+  foreach (element_children($form) as $key) {
+    $cid = webform_get_cid($node, $key, $pid);
+    $form[$key]['#form_builder'] = array(
+      'element_id' => 'cid_' . $cid,
+    );
+
+    // Add any component-specific loading. Note that all components are
+    // invoked here because the component type isn't yet known.
+    foreach (webform_components() as $type => $info) {
+      if ($element = form_builder_webform_component_invoke($type, 'form_builder_load', $form[$key])) {
+        $form[$key] = $element;
+      }
+    }
+    form_builder_webform_load_process($form[$key], $node, $cid);
+  }
+}
+
+/**
+ * Implements hook_form_builder_add_element_alter().
+ *
+ * Modify a FAPI element before it is added to the form array.
+ */
+function form_builder_webform_form_builder_add_element_alter(&$element, $form_type, $form_id) {
+  if ($form_type == 'webform') {
+    $element['#webform']['is_new'] = TRUE;
+  }
+}
+
+/**
+ * Implements hook_form_builder_preview_alter().
+ *
+ * The most common use of the preview altering is filtering field descriptions
+ * via filter_xss() or other functions. Webform has its own filtering function
+ * for this purpose.
+ */
+function form_builder_webform_form_builder_preview_alter(&$element, $form_type, $form_id) {
+  if ($form_type == 'webform') {
+    // Filter all descriptions for all components.
+    if (isset($element['#description'])) {
+      $element['#description'] = _webform_filter_descriptions($element['#description']);
+    }
+
+    if (isset($element['#default_value']) && is_string($element['#default_value'])) {
+      $element['#value'] = _webform_filter_values($element['#default_value'], NULL, NULL, NULL, FALSE);
+    }
+
+    // Add info to the #webform_component array so that theme_webform_element will
+    // work properly.
+    $element['#webform_component']['type'] = $element['#form_builder']['element_type'];
+
+    // Let components do any extra filtering if needed.
+    $type = isset($element['#webform']['type']) ? $element['#webform']['type'] : $element['#form_builder']['element_type'];
+    if ($new_element = form_builder_webform_component_invoke($type, 'form_builder_preview_alter', $element)) {
+      $element = $new_element;
+    }
+  }
+}
+
+/**
+ * Invoke a form builder callback for a webform component.
+ *
+ * If the webform component implements the callback itself, this function
+ * returns the result obtained from that. Otherwise, if this module has a
+ * default implementation of the callback on behalf of the component, the
+ * result obtained from that is returned.
+ *
+ * @param $type
+ *   The component type as a string.
+ * @param $callback
+ *   The callback to execute.
+ * @param ...
+ *   Any additional parameters required by the $callback.
+ */
+function form_builder_webform_component_invoke($type, $callback) {
+  $args = func_get_args();
+
+  // First try invoking the callback in the webform component itself.
+  $result = call_user_func_array('webform_component_invoke', $args);
+  if (isset($result)) {
+    return $result;
+  }
+
+  // Otherwise look for a default implementation provided by this module.
+  $type = array_shift($args);
+  $callback = array_shift($args);
+  $function = '_form_builder_webform_' . $callback . '_' . $type;
+  module_load_include('inc', 'form_builder_webform', 'form_builder_webform.components');
+  if (function_exists($function)) {
+    return call_user_func_array($function, $args);
+  }
+}
+
+/**
+ * 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);
+}
