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	27 Oct 2010 19:01:45 -0000
@@ -0,0 +1,404 @@
+<?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',
+    ),
+    'default' => array(
+      '#title' => t('New e-mail'),
+      '#type' => 'textfield',
+      '#form_builder' => array('element_type' => 'email'),
+    ),
+  );
+
+  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;
+  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-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) {
+  // Make hidden fields visible while editing.
+  $form_element['#field_suffix'] = '(' . t('hidden') . ')';
+  $form_element['#autocomplete_path'] = NULL; // Needed to avoid notices.
+  $form_element['#type'] = 'textfield';
+  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',
+    ),
+    'default' => array(
+      '#title' => t('Markup'),
+      '#type' => 'markup',
+      '#markup' => $default,
+      '#input_format' => filter_default_format(),
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_markup($component, $form_element) {
+  $component['extra']['format'] = $form_element['#input_format'];
+  $component['value'] = $form_element['#markup'];
+  return $component;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_markup($form_element) {
+  $form_element['#markup'] = isset($form_element['#markup']) ? $form_element['#markup'] : '';
+  $form_element['#value'] = check_markup(_webform_filter_values($form_element['#markup'], NULL, NULL, NULL, FALSE), $form_element['#input_format']);
+
+  if (strlen(trim($form_element['#value'])) == 0) {
+    $form_element['#value'] = t('This markup element currently does not contain any text.');
+  }
+  return $form_element;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-markup-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',
+    ),
+    'default' => array(
+      '#title' => t('New select list'),
+      '#type' => 'select',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => 'one',
+      '#webform' => array('type' => 'select'),
+    ),
+  );
+
+  $fields['checkboxes'] = array(
+    'title' => t('Checkboxes'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'multiple',
+      'key',
+    ),
+    'default' => array(
+      '#title' => t('New checkboxes'),
+      '#type' => 'checkboxes',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => array('one', 'two'),
+      '#multiple' => TRUE,
+      '#webform' => array('type' => 'select'),
+    ),
+  );
+
+  $fields['radios'] = array(
+    'title' => t('Radios'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'key',
+    ),
+    'default' => array(
+      '#title' => t('New radios'),
+      '#type' => 'radios',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => 'one',
+      '#webform' => array('type' => 'select'),
+    ),
+  );
+
+  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'] = empty($form_element['#multiple']) ? 'N' : 'Y';
+  $component['extra']['aslist'] = $form_element['#type'] == 'select' ? 'Y' : 'N';
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : '';
+  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',
+      'input_format',
+      'key',
+    ),
+    'default' => array(
+      '#title' => t('New textarea'),
+      '#type' => 'textarea',
+    ),
+  );
+
+  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']['format'] = isset($form_element['#input_format']) ? $form_element['#input_format'] : NULL;
+  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',
+    ),
+    'default' => array(
+      '#title' => t('New textfield'),
+      '#type' => 'textfield',
+    ),
+  );
+
+  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;
+  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	27 Oct 2010 19:01:45 -0000
@@ -0,0 +1,8 @@
+; $Id$
+name = Form builder Webform UI
+description = Form builder integration for the Webform module.
+core = 7.x
+dependencies[] = form_builder
+dependencies[] = webform
+files[] = form_builder_webform.module
+files[] = form_builder_webform.components.inc
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	27 Oct 2010 19:01:45 -0000
@@ -0,0 +1,282 @@
+<?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');
+
+  $build = array();
+  $build[] = form_builder_interface('webform', $node->nid);
+  $build[] = drupal_get_form('form_builder_webform_save_form', $node->nid);
+
+  return $build;
+}
+
+/**
+ * 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, &$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;
+}
+
+/**
+ * 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_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($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);
+    }
+  }
+
+  drupal_set_message(t('Changes to the form have been saved.'));
+  form_builder_cache_delete('webform', $node->nid);
+}
+
+/**
+ * Save the contents of a form into Webform's database tables.
+ */
+function form_builder_webform_save($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['pid'] = isset($element['#form_builder']['parent_id']) ? (int)substr($element['#form_builder']['parent_id'], 4) : 0;
+  $component['nid'] = $node->nid;
+
+  if (isset($element['#default_value'])) {
+    $component['value'] = is_array($element['#default_value']) ? implode(',', $element['#default_value']) : $element['#default_value'];
+  }
+
+  // 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);
+    // Get the unfiltered version of the client form.
+    $form = array();
+    $form_state = array();
+    $form = webform_client_form($form, $form_state, $node, array(), TRUE, FALSE);
+    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);
+    }
+
+    // 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);
+  }
+}
