Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/form_controller/CHANGELOG.txt,v
retrieving revision 1.3
diff -u -p -r1.3 CHANGELOG.txt
--- CHANGELOG.txt 14 Nov 2009 23:46:39 -0000 1.3
+++ CHANGELOG.txt 19 Nov 2009 11:42:04 -0000
@@ -4,8 +4,9 @@ Form controller x.x-x.x, xxxx-xx-xx
-----------------------------------
-Form controller 6.x-1.x, xxxx-xx-xx
+Form controller 6.x-2.x, xxxx-xx-xx
-----------------------------------
+#602600 by sun: Revamped module; pre-alpha code to support many implementations.
#602600 by sun: Very rough port to D6.
Index: form_controller.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/form_controller/form_controller.info,v
retrieving revision 1.3
diff -u -p -r1.3 form_controller.info
--- form_controller.info 14 Nov 2009 23:46:39 -0000 1.3
+++ form_controller.info 19 Nov 2009 11:26:12 -0000
@@ -3,3 +3,4 @@ name = Form controller
description = Helper module for managing form elements of other modules.
package = Development
core = 6.x
+dependencies[] = contact
Index: form_controller.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/form_controller/form_controller.module,v
retrieving revision 1.4
diff -u -p -r1.4 form_controller.module
--- form_controller.module 14 Nov 2009 23:46:39 -0000 1.4
+++ form_controller.module 19 Nov 2009 11:39:54 -0000
@@ -3,7 +3,9 @@
/**
* @file
- * Loader and callback functions for Form controller.
+ * Form controller.
+ *
+ * @todo Increase module weight, since #process does not work on 'form' in D6.
*/
/**
@@ -18,7 +20,8 @@ function form_controller_perm() {
*/
function form_controller_menu() {
$items['form_controller'] = array(
- 'page callback' => 'form_controller',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('form_controller_form'),
'access arguments' => array('administer forms'),
'type' => MENU_CALLBACK,
);
@@ -27,115 +30,271 @@ function form_controller_menu() {
/**
* Implements hook_form_alter().
- *
- * Attaches Form controller to all forms, if there are any hook_form_controller()
- * implementations.
*/
function form_controller_form_alter(&$form, &$form_state, $form_id) {
- if (!user_access('administer forms') || $form_id == 'form_controller_form' || !form_controller_get_modules()) {
+ static $implementations;
+ if (!isset($implementations)) {
+ $implementations = (bool) module_implements('form_controller_info');
+ }
+ if ($form_id == 'form_controller_form' || !$implementations) {
return;
}
- $form['form_controller'] = array(
- '#prefix' => '
',
- '#value' => l(t('Configure this form'), "form_controller/form_controller_form/$form_id"),
- '#suffix' => '
',
- '#weight' => -1000,
- );
-}
+ // @todo This breaks form submissions in D6, so we have to inline the code :(
+ /*
+ $form['#input'] = TRUE;
+ $form['#process'][] = 'form_controller_process_form';
+ */
+ form_controller_process_form($form, array(), $form_state);
-/**
- * Menu callback; retrieves and renders a form.
- */
-function form_controller($form_id, $target_form_id = NULL) {
- // Output target form_id as title in form settings widget.
- if (empty($_POST) && $form_id == 'form_controller_form') {
- echo ''. t('Form settings for %form_id', array('%form_id' => $target_form_id)) .'
';
+ if (!user_access('administer forms')) {
+ return;
}
- $output = drupal_get_form($form_id, $target_form_id);
- // Output and clear form validation error messages, if there are any.
- echo theme_status_messages();
- echo $output;
- exit;
+ // @todo Toggle this + form_controller globally, auto-disable after 6 hours.
+ if (!isset($form['#cache'])) {
+ $form['#cache'] = TRUE;
+ }
+
+ // Store page title for potential usage in implementation forms.
+ $form['#form_controller']['title'] = drupal_set_title();
+
+ // Output a contextual configuration link.
+ $output = '';
+ $output .= l(t('Configure this form'), 'form_controller/' . $form['form_build_id']['#value']);
+ $output .= '
';
+ if (!isset($form['#prefix'])) {
+ $form['#prefix'] = '';
+ }
+ $form['#prefix'] .= $output . $form['#prefix'];
}
/**
- * Builds a form based on hook_form_controller() implementations.
+ * Form builder to control form alterations.
*/
-function form_controller_form($target_form_id) {
- $form = array();
+function form_controller_form(&$form_state, $form_build_id, $target_form_id = NULL) {
+ // Reload form from cache.
+ $form_state = array('storage' => NULL, 'submitted' => FALSE);
+ $cached_form = form_get_cache($form_build_id, $form_state);
+ $cached_form['#post'] = array();
+
+ // Rebuild cached form.
+ $form_id = $cached_form['form_id']['#value'];
+ $processed_form = form_builder($form_id, $cached_form, $form_state);
+
+ // Build form information.
+ $form_elements = form_controller_get_elements($processed_form);
+ $context = array(
+ 'form_id' => $form_id,
+ 'form' => $processed_form,
+ 'elements' => $form_elements,
+ );
+ $form_state['form_controller'] = $context;
+
+ drupal_set_title(t('Configure %title form (@form_id)', array(
+ '%title' => $cached_form['#form_controller']['title'],
+ '@form_id' => $form_id,
+ )));
- $form['form_controller']['target_form_id'] = array(
- '#type' => 'value',
- '#value' => $target_form_id,
- );
- foreach (form_controller_get_modules() as $module) {
- $function = $module .'_form_controller';
- $form['form_controller'][$module] = $function('settings', $target_form_id);
- $form['form_controller'][$module]['#tree'] = TRUE;
+ $form = array();
+ $alterations = module_invoke_all('form_controller_info');
+ foreach ($alterations as $name => $info) {
+ // Fetch configuration form.
+ // @todo Take over configuration storage for most/simple implementations.
+ if (isset($info['form callback']) && function_exists($info['form callback'])) {
+ $function = $info['form callback'];
+ $settings = $function($form, $form_id, $context);
+ if (isset($settings) && is_array($settings)) {
+ $form[$name] = array(
+ '#type' => 'fieldset',
+ '#title' => check_plain($info['title']),
+ '#description' => check_plain($info['description']),
+ '#collapsible' => TRUE,
+ //'#collapsed' => TRUE,
+ '#tree' => TRUE,
+ );
+ $form[$name] += $settings;
+ }
+ }
}
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save'),
- );
+ $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
+
return $form;
}
/**
- * Render and return a Form controller settings form.
+ * Helper function to retrieve all user input fields in a form.
*
- * To ensure that no other module adds elements to our form, we simply render
- * everything below $form['form_controller'] only.
+ * This was mainly designed for Form controller implementations like Mollom,
+ * which want to do something with all exposed user input widgets in a form.
+ * I currently can't think of other implementations that would want to retrieve
+ * all widgets, so we limit this to real user input elements.
*/
-function theme_form_controller_form($form) {
- foreach ($form as $key => $value) {
- if ($key[0] != '#' && !in_array($key, array('form_controller', 'submit', 'form_token', 'form_id'))) {
- unset($form[$key]);
+function form_controller_get_elements($elements) {
+ static $input = array('textfield', 'textarea');
+
+ $items = array();
+ foreach (element_children($elements) as $key) {
+ // @todo Find a better way to skip form_controller-controlled elements.
+ // Wait. Why should we skip any possibly valid and useful form elements?
+ // Anything that's contained in the form may be used by any implementation, no?
+ if (isset($elements[$key]['#form_controller'])) {
+ continue;
+ }
+ // Skip autocomplete widgets.
+ if (!empty($elements[$key]['#autocomplete_path'])) {
+ continue;
+ }
+ // Skip elements without a #type.
+ if (isset($elements[$key]['#type']) && in_array($elements[$key]['#type'], $input)) {
+ $items[] = $elements[$key];
+ }
+ // Recurse into children, if there are any.
+ if (element_children($elements[$key])) {
+ // @todo Do we want to key by $key?
+ $items = array_merge($items, form_controller_get_elements($elements[$key]));
}
}
- return drupal_render($form);
+ return $items;
}
-/**
- * Form controller settings validation callback.
- *
- * Allows hook_form_controller() implementations to react on form submissions.
- * To invalidate the form, implementations should invoke form_set_error().
- */
-function form_controller_form_validate($form_id, $form_values) {
- foreach (form_controller_get_modules() as $module) {
- $form_values[$module]['#form_id'] = $form_values['target_form_id'];
- $function = $module .'_form_controller';
- $function('validate', $form_values[$module]);
+function form_controller_process_form(&$element, $edit, &$form_state) {
+ // Build form information.
+ $form_id = $element['form_id']['#value'];
+ $form_elements = form_controller_get_elements($element);
+ $context = array(
+ 'form_id' => $form_id,
+ 'form' => $element,
+ 'elements' => $form_elements,
+ );
+ $form_state['form_controller'] = $context;
+
+ // @todo Cache this.
+ foreach (module_invoke_all('form_controller_info') as $name => $info) {
+ if (!empty($info['process callback']) && function_exists($info['process callback'])) {
+ $function = $info['process callback'];
+ $function($element, $form_state, $form_id, $form_elements);
+ }
}
+
+ // return $element;
+}
+
+function form_controller_get_value($form_state, $parents) {
+ $values = $form_state['values'];
+ foreach ($parents as $parent) {
+ $values = (isset($values[$parent]) ? $values[$parent] : NULL);
+ }
+ return $values;
}
+// @see http://drupal.org/node/633058 for a D7 patch.
+function form_controller_validate_username($element, &$form_state) {
+ if (!empty($element['#value']) && !($account = user_load(array('name' => $element['#value'])))) {
+ form_error($element, t('The username %name does not exist.', array('%name' => $element['#value'])));
+ }
+}
+
+
+
+
/**
- * Form controller settings submit callback.
+ * Implements hook_form_controller_info().
*
- * Returns form values to hook_form_controller() implementations.
+ * Example implementation for Contact module. Replace 'contact' with 'mollom'
+ * or whatever to imagine other implementations.
*/
-function form_controller_form_submit($form_id, $form_values) {
- foreach (form_controller_get_modules() as $module) {
- $form_values[$module]['#form_id'] = $form_values['target_form_id'];
- $function = $module .'_form_controller';
- $function('submit', $form_values[$module]);
+function contact_form_controller_info() {
+ $alterations['contact_webmaster'] = array(
+ 'title' => t('Contact webmaster'),
+ 'description' => t('Sends the chosen field contents to a selected user.'),
+ 'form callback' => 'contact_form_configure_webmaster',
+ 'process callback' => 'contact_form_process_webmaster',
+ );
+ return $alterations;
+}
+
+function contact_form_configure_webmaster(&$complete_form, $form_id, $context) {
+ // Fetch configuration.
+ // @todo Take over configuration storage for most/simple implementations.
+ $config = variable_get('contact_webmaster_forms', array());
+
+ // I really wonder why Form API allows #element_validate, but not #element_submit... 15/11/2009 sun
+ $form['#submit'][] = 'contact_form_configure_webmaster_submit';
+
+ $form['status'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Send an e-mail notification upon form submission'),
+ '#default_value' => isset($config[$form_id]),
+ );
+ if (!isset($config[$form_id])) {
+ $config[$form_id] = array();
+ }
+ $config[$form_id] += array(
+ 'recipient' => '',
+ 'message' => '',
+ );
+ $form['recipient'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Recipient'),
+ '#default_value' => $config[$form_id]['recipient'],
+ '#autocomplete_path' => 'user/autocomplete',
+ '#element_validate' => array('form_controller_validate_username'),
+ );
+ $options = array();
+ foreach ($context['elements'] as $key => $element) {
+ if (isset($element['#title'])) {
+ $parents = implode('][', $element['#parents']);
+ $options[$parents] = $element['#title'];
+ }
}
- echo TRUE;
- exit;
+ $form['element'] = array(
+ '#type' => 'select',
+ '#title' => t('Field containing message'),
+ '#default_value' => $config[$form_id]['message'],
+ '#options' => $options,
+ );
+ $complete_form['#submit'][] = 'contact_form_configure_webmaster_submit';
+
+ return $form;
}
-/**
- * Get a list of current hook_form_controller() implementations.
- */
-function form_controller_get_modules() {
- // Development 15/11/2009 sun
- return TRUE;
- static $modules;
- if (!isset($modules)) {
- $modules = module_implements('form_controller');
+function contact_form_configure_webmaster_submit($form, &$form_state) {
+ // @todo Take over configuration storage for most/simple implementations.
+
+ $config = variable_get('contact_webmaster_forms', array());
+ $form_id = $form_state['form_controller']['form_id'];
+ if ($form_state['values']['contact_webmaster']['status']) {
+ $elements = $form_state['form_controller']['elements'];
+
+ $config[$form_id] = array(
+ 'recipient' => $form_state['values']['contact_webmaster']['recipient'],
+ 'element' => explode('][', $form_state['values']['contact_webmaster']['element']),
+ );
+ }
+ else {
+ unset($config[$form_id]);
}
- return $modules;
+ variable_set('contact_webmaster_forms', $config);
+}
+
+function contact_form_process_webmaster(&$form, &$form_state, $form_id, $form_elements) {
+ $config = variable_get('contact_webmaster_forms', array());
+ if (isset($config[$form_id])) {
+ $form['#submit'][] = 'contact_form_webmaster_submit';
+ }
+}
+
+function contact_form_webmaster_submit($form, &$form_state) {
+ $config = variable_get('contact_webmaster_forms', array());
+ $form_id = $form['form_id']['#value'];
+
+ $recipient = $config[$form_id]['recipient'];
+ $message = form_controller_get_value($form_state, $config[$form_id]['element']);
+
+ drupal_set_message('' . var_export(array(
+ 'recipient' => $recipient,
+ 'message' => $message,
+ ), TRUE) . '
');
}