diff options
author | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-08-27 04:40:12 +0000 |
---|---|---|
committer | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-08-27 04:40:12 +0000 |
commit | 0259ee968ffa4db893e57a80931aaf9f8ae69e5e (patch) | |
tree | bb1a50b608ee02f5909c4c7f193235f1a9d20140 | |
parent | 715d3e54325492cf6ef05f2311faa9a9c8296c15 (diff) | |
download | brdo-0259ee968ffa4db893e57a80931aaf9f8ae69e5e.tar.gz brdo-0259ee968ffa4db893e57a80931aaf9f8ae69e5e.tar.bz2 |
#367567 by effulgentsia, yched, quicksketch, sun, and chx: Move AHAH-'add more' to the new generic AHAH callback, and add support for form definition functions being kept in non-.module files.
-rw-r--r-- | includes/ajax.inc | 4 | ||||
-rw-r--r-- | includes/form.inc | 31 | ||||
-rw-r--r-- | modules/field/field.form.inc | 128 | ||||
-rw-r--r-- | modules/field/field.module | 17 | ||||
-rw-r--r-- | modules/field/field.test | 10 |
5 files changed, 55 insertions, 135 deletions
diff --git a/includes/ajax.inc b/includes/ajax.inc index 6a5a25e59..e3e324f82 100644 --- a/includes/ajax.inc +++ b/includes/ajax.inc @@ -149,7 +149,7 @@ function ajax_render($commands = array(), $header = TRUE) { */ function ajax_render_error($error = '') { $commands = array(); - $commands[] = ajax_command_error(empty($error) ? t('An error occurred while handling the request: The server received invalid input.') : $error); + $commands[] = ajax_command_alert(empty($error) ? t('An error occurred while handling the request: The server received invalid input.') : $error); ajax_render($commands); } @@ -301,7 +301,7 @@ function ajax_process_form($element) { 'wrapper' => empty($element['#ajax']['wrapper']) ? NULL : $element['#ajax']['wrapper'], 'selector' => empty($element['#ajax']['selector']) ? '#' . $element['#id'] : $element['#ajax']['selector'], 'effect' => empty($element['#ajax']['effect']) ? 'none' : $element['#ajax']['effect'], - 'speed ' => empty($element['#ajax']['effect']) ? 'none' : $element['#ajax']['effect'], + 'speed' => empty($element['#ajax']['effect']) ? 'none' : $element['#ajax']['effect'], 'method' => empty($element['#ajax']['method']) ? 'replace' : $element['#ajax']['method'], 'progress' => empty($element['#ajax']['progress']) ? array('type' => 'throbber') : $element['#ajax']['progress'], 'button' => isset($element['#executes_submit_callback']) ? array($element['#name'] => $element['#value']) : FALSE, diff --git a/includes/form.inc b/includes/form.inc index b57b7c816..0e6221ce7 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -155,6 +155,19 @@ function drupal_build_form($form_id, &$form_state) { $form_build_id = 'form-' . md5(uniqid(mt_rand(), TRUE)); $form['#build_id'] = $form_build_id; + // Record the filepath of the include file containing the original form, + // so the form builder callbacks can be loaded when the form is being + // rebuilt on a different path (such as 'system/ajax'). + // @see form_get_cache() + // @see drupal_retrieve_form() + // menu_get_item() is not available at installation time. + if (!defined('MAINTENANCE_MODE')) { + $item = menu_get_item(); + if (!empty($item['file'])) { + $form['#include_file'] = $item['file']; + } + } + // Fix the form method, if it is 'get' in $form_state, but not in $form. if ($form_state['method'] == 'get' && !isset($form['#method'])) { $form['#method'] = 'get'; @@ -299,6 +312,15 @@ function drupal_rebuild_form($form_id, &$form_state, $form_build_id = NULL) { function form_get_cache($form_build_id, &$form_state) { if ($cached = cache_get('form_' . $form_build_id, 'cache_form')) { $form = $cached->data; + // If the original form is contained in an optional include file, load the + // file and re-populate $form_state for subsequent rebuilds. + // @see drupal_build_form() + // @see drupal_retrieve_form() + if (!empty($form['#include_file']) && file_exists($form['#include_file'])) { + require_once DRUPAL_ROOT . '/' . $form['#include_file']; + $form_state['include_file'] = $form['#include_file']; + } + global $user; if ((isset($form['#cache_token']) && drupal_valid_token($form['#cache_token'])) || (!isset($form['#cache_token']) && !$user->uid)) { if ($cached = cache_get('storage_' . $form_build_id, 'cache_form')) { @@ -452,6 +474,15 @@ function drupal_retrieve_form($form_id, &$form_state) { $form = call_user_func_array(isset($callback) ? $callback : $form_id, $args); $form['#form_id'] = $form_id; $form['#args'] = $form_state['args']; + + // Whenever this form is (re)built, restore the include file property from + // $form_state, if existent. + // @see drupal_build_form() + // @see form_get_cache() + if (!empty($form_state['include_file'])) { + $form['#include_file'] = $form_state['include_file']; + } + return $form; } diff --git a/modules/field/field.form.inc b/modules/field/field.form.inc index 3e1d47e08..b28acd07b 100644 --- a/modules/field/field.form.inc +++ b/modules/field/field.form.inc @@ -141,8 +141,7 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form, $title = check_plain(t($instance['label'])); $description = field_filter_xss(t($instance['description'])); - $bundle_name_url_css = str_replace('_', '-', $instance['bundle']); - $field_name_url_css = str_replace('_', '-', $field_name); + $wrapper_id = str_replace('_', '-', $field_name) . '-wrapper'; $form_element = array( '#theme' => 'field_multiple_value_form', @@ -150,8 +149,9 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form, '#title' => $title, '#required' => $instance['required'], '#description' => $description, - '#prefix' => '<div id="' . $field_name_url_css . '-wrapper">', + '#prefix' => '<div id="' . $wrapper_id . '">', '#suffix' => '</div>', + '#max_delta' => $max, ); $function = $instance['widget']['module'] . '_field_widget'; @@ -188,28 +188,25 @@ function field_multiple_value_form($field, $instance, $langcode, $items, &$form, } } - // Add AHAH add more button, if not working with a programmed form. + // Add 'add more' button, if not working with a programmed form. if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])) { - $bundle_name_url_str = str_replace('_', '-', $instance['bundle']); - $field_name_url_str = str_replace('_', '-', $field_name); $form_element[$field_name . '_add_more'] = array( '#type' => 'submit', '#name' => $field_name . '_add_more', '#value' => t('Add another item'), + '#attributes' => array('class' => array('field-add-more-submit')), // Submit callback for disabled JavaScript. '#submit' => array('field_add_more_submit'), '#ajax' => array( - 'path' => 'field/js_add_more/' . $bundle_name_url_css . '/' . $field_name_url_css, - 'wrapper' => $field_name_url_css . '-wrapper', + 'callback' => 'field_add_more_js', + 'wrapper' => $wrapper_id, 'method' => 'replace', 'effect' => 'fade', ), - // When JS is disabled, the field_add_more_submit handler will find - // the relevant field using these entries. + // The field_add_more_submit() and field_add_more_js() handlers will + // find the relevant field using those entries. '#field_name' => $field_name, - '#bundle' => $instance['bundle'], - '#attributes' => array('class' => array('field-add-more-submit')), '#language' => $langcode, ); } @@ -343,114 +340,27 @@ function field_add_more_submit($form, &$form_state) { } /** - * Menu callback for AHAH addition of new empty widgets. + * Ajax callback for addition of new empty widgets. */ -function field_add_more_js($bundle_name, $field_name) { - // Arguments are coming from the url, so we translate back dashes. - $field_name = str_replace('-', '_', $field_name); - - $invalid = FALSE; - if (empty($_POST['form_build_id'])) { - // Invalid request. - $invalid = TRUE; - } - - // Retrieve the cached form. - $form_state = form_state_defaults(); - $form_build_id = $_POST['form_build_id']; - $form = form_get_cache($form_build_id, $form_state); - if (!$form) { - // Invalid form_build_id. - $invalid = TRUE; - } - +function field_add_more_js($form, $form_state) { // Retrieve field information. + $field_name = $form_state['clicked_button']['#field_name']; $field = $form['#fields'][$field_name]['field']; - $instance = $form['#fields'][$field_name]['instance']; - $form_path = $form['#fields'][$field_name]['form_path']; if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) { - // Ivnalid - $invalid = TRUE; - } - - if ($invalid) { ajax_render(array()); } - - // We don't simply return a new empty widget row to append to existing ones, - // because: - // - ahah.js won't simply let us add a new row to a table - // @todo ajax.js lets you. :) - // - attaching the 'draggable' behavior won't be easy - // So we resort to rebuilding the whole table of widgets including the - // existing ones, which makes us jump through a few hoops. - - // The form that we get from the cache is unbuilt. We need to build it so - // that _value callbacks can be executed and $form_state['values'] populated. - // We only want to affect $form_state['values'], not the $form itself - // (built forms aren't supposed to enter the cache) nor the rest of - // $form_state, so we use copies of $form and $form_state. - $form_copy = $form; - $form_state_copy = $form_state; - $form_state_copy['input'] = array(); - form_builder($_POST['form_id'], $form_copy, $form_state_copy); - // Just grab the data we need. - $form_state['values'] = $form_state_copy['values']; - // Reset cached ids, so that they don't affect the actual form we output. - drupal_static_reset('form_clean_id'); - - // Ensure that a valid language is provided. - $langcode = key($_POST[$field_name]); - if ($langcode != FIELD_LANGUAGE_NONE) { - $langcode = field_multilingual_valid_language($langcode); - } - - // Sort the $form_state['values'] we just built *and* the incoming $_POST data - // according to d-n-d reordering. - unset($form_state['values'][$field_name][$langcode][$field['field_name'] . '_add_more']); - foreach ($_POST[$field_name][$langcode] as $delta => $item) { - $form_state['values'][$field_name][$langcode][$delta]['_weight'] = $item['_weight']; - } - $form_state['values'][$field_name][$langcode] = _field_sort_items($field, $form_state['values'][$field_name][$langcode]); - $_POST[$field_name][$langcode] = _field_sort_items($field, $_POST[$field_name][$langcode]); - - // Build our new form element for the whole field, asking for one more element. - $form_state['field_item_count'] = array($field_name => count($_POST[$field_name][$langcode]) + 1); - $items = $form_state['values'][$field_name][$langcode]; - $form_element = field_default_form(NULL, NULL, $field, $instance, $langcode, $items, $form, $form_state); - // Let other modules alter it. - drupal_alter('form', $form_element, array(), 'field_add_more_js'); - - // Add the new element at the right location in the (original, unbuilt) form. - $target = &$form; - foreach ($form_path as $key) { - $target = &$target[$key]; - } - $target = $form_element[$field_name]; - - // Save the new definition of the form. - $form_state['values'] = array(); - form_set_cache($form_build_id, $form, $form_state); - - // Build the new form against the incoming $_POST values so that we can - // render the new element. - $delta = max(array_keys($_POST[$field_name][$langcode])) + 1; - $_POST[$field_name][$langcode][$delta]['_weight'] = $delta; - $form_state = form_state_defaults(); - $form_state['input'] = $_POST; - $form = form_builder($_POST['form_id'], $form, $form_state); - - // Render the new output. - // We fetch the form element from the built $form. + // Navigate to the right part of the form. + $form_path = $form['#fields'][$field_name]['form_path']; $field_form = $form; foreach ($form_path as $key) { $field_form = $field_form[$key]; } + // Add a DIV around the new field to receive the AJAX effect. - $field_form[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : ''); - $field_form[$delta]['#suffix'] = (isset($field_form[$delta]['#suffix']) ? $field_form[$delta]['#suffix'] : '') . '</div>'; - // Prevent duplicate wrapper. - unset($field_form['#prefix'], $field_form['#suffix']); + $langcode = $field_form['#language']; + $delta = $field_form[$langcode]['#max_delta']; + $field_form[$langcode][$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($field_form[$langcode][$delta]['#prefix']) ? $field_form[$langcode][$delta]['#prefix'] : ''); + $field_form[$langcode][$delta]['#suffix'] = (isset($field_form[$langcode][$delta]['#suffix']) ? $field_form[$langcode][$delta]['#suffix'] : '') . '</div>'; $output = theme('status_messages') . drupal_render($field_form); diff --git a/modules/field/field.module b/modules/field/field.module index 5781ae116..9115c87b4 100644 --- a/modules/field/field.module +++ b/modules/field/field.module @@ -156,23 +156,6 @@ function field_init() { } /** - * Implement hook_menu(). - */ -function field_menu() { - $items = array(); - - // Callback for AHAH add more buttons. - $items['field/js_add_more'] = array( - 'page callback' => 'field_add_more_js', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - 'file' => 'field.form.inc', - ); - - return $items; -} - -/** * Implement hook_theme(). */ function field_theme() { diff --git a/modules/field/field.test b/modules/field/field.test index 6f7607f8c..d1a717ba5 100644 --- a/modules/field/field.test +++ b/modules/field/field.test @@ -1375,8 +1375,7 @@ class FieldFormTestCase extends FieldTestCase { $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*"; } // Press 'add more' button through AHAH. - $path = 'field/js_add_more/' . str_replace('_', '-', $this->instance['bundle']) . '/' . str_replace('_', '-', $this->instance['field_name']); - $this->_fieldPostAhah($path, $edit, t('Add another item')); + $this->_fieldPostAhah($edit, t('Add another item')); ksort($values); $values = array_values($values); @@ -1401,11 +1400,8 @@ class FieldFormTestCase extends FieldTestCase { * Since the result is generally not a full-fledged form, this cannot be * called iteratively. */ - function _fieldPostAhah($path, $edit, $submit, array $options = array(), array $headers = array()) { - // @TODO: the framework should make it possible to submit a form to a - // different URL than its action or the current. For now, we can just force - // it. - $this->additionalCurlOptions[CURLOPT_URL] = url($path, array('absolute' => TRUE)); + function _fieldPostAhah($edit, $submit, array $options = array(), array $headers = array()) { + $this->additionalCurlOptions[CURLOPT_URL] = url('system/ajax', array('absolute' => TRUE)); $this->drupalPost(NULL, $edit, $submit); unset($this->additionalCurlOptions[CURLOPT_URL]); |