diff --git modules/book/book.module modules/book/book.module index 2f6dfc0..26c67d9 100644 --- modules/book/book.module +++ modules/book/book.module @@ -403,7 +403,7 @@ function book_get_books() { function book_form_alter(&$form, &$form_state, $form_id) { if (!empty($form['#node_edit_form'])) { // Add elements to the node form. - $node = $form['#node']; + $node = $form_state['node']; $access = user_access('administer book outlines'); if (!$access) { @@ -423,13 +423,18 @@ function book_form_alter(&$form, &$form_state, $form_id) { // won't be changed via AJAX, a button is provided in the node form to submit // the form and generate options in the parent select corresponding to the // selected book. This is similar to what happens during a node preview. - '#submit' => array('node_form_submit_build_node'), + '#submit' => array('book_node_form_rebuild'), '#weight' => 20, ); } } } +function book_node_form_rebuild($form, &$form_state) { + $form_state['node']->book = $form_state['values']['book']; + $form_state['rebuild'] = TRUE; +} + /** * Build the parent selection form element for the node form or outline tab. * diff --git modules/field/field.form.inc modules/field/field.form.inc index cbc39e0..4215593 100644 --- modules/field/field.form.inc +++ modules/field/field.form.inc @@ -369,17 +369,21 @@ function field_default_form_errors($entity_type, $entity, $field, $instance, $la * to return just the changed part of the form. */ function field_add_more_submit($form, &$form_state) { - // Set the form to rebuild and run submit handlers. + // If a builder function has been specified, execute it. Entity forms can + // use it to implement their own form persistence mode. + // @todo: Once all entity forms have been fixed to not make use of this, + // remove it. See http://drupal.org/node/735800. if (isset($form['#builder_function']) && function_exists($form['#builder_function'])) { - $entity = $form['#builder_function']($form, $form_state); - - // Make the changes we want to the form state. - $field_name = $form_state['clicked_button']['#field_name']; - $langcode = $form_state['clicked_button']['#language']; - if ($form_state['values'][$field_name . '_add_more']) { - $form_state['field_item_count'][$field_name] = count($form_state['values'][$field_name][$langcode]); - } + $form['#builder_function']($form, $form_state); + } + // Make the changes we want to the form state. + $field_name = $form_state['clicked_button']['#field_name']; + $langcode = $form_state['clicked_button']['#language']; + if ($form_state['values'][$field_name . '_add_more']) { + $form_state['field_item_count'][$field_name] = count($form_state['values'][$field_name][$langcode]); } + // Make sure the form rebuilds regardless whether we submit with JS. + $form_state['rebuild'] = TRUE; } /** diff --git modules/node/node.pages.inc modules/node/node.pages.inc index 2cdfc11..5d7a568 100644 --- modules/node/node.pages.inc +++ modules/node/node.pages.inc @@ -76,6 +76,8 @@ function node_add($type) { } function node_form_validate($form, &$form_state) { + // @todo for D8: Fix this to use a proper built node object or scratch entity + // level validation in favour of validation tied to the form. $node = (object)$form_state['values']; node_validate($node, $form); @@ -89,14 +91,11 @@ function node_form_validate($form, &$form_state) { */ function node_form($form, &$form_state, $node) { global $user; - // This form has its own multistep persistence. - if ($form_state['rebuild']) { - $form_state['input'] = array(); - } - if (isset($form_state['node'])) { - $node = (object)($form_state['node'] + (array)$node); - } + // Submit handlers may have updated $form_state['node'] so keep this changes. + $form_state += array('node' => $node); + $node = $form_state['node']; + if (isset($form_state['node_preview'])) { $form['#prefix'] = $form_state['node_preview']; } @@ -141,6 +140,7 @@ function node_form($form, &$form_state, $node) { $form['title']['#weight'] = -5; } + // @todo Remove this in D8 as it's deprecated by $form_state['node']. $form['#node'] = $node; $form['additional_settings'] = array( @@ -277,7 +277,6 @@ function node_form($form, &$form_state, $node) { $form['#validate'][] = 'node_form_validate'; $form['#theme'] = array($node->type . '_node_form', 'node_form'); - $form['#builder_function'] = 'node_form_submit_build_node'; field_attach_form('node', $node, $form, $form_state, $node->language); return $form; @@ -300,6 +299,7 @@ function node_form_delete_submit($form, &$form_state) { function node_form_build_preview($form, &$form_state) { $node = node_form_submit_build_node($form, $form_state); $form_state['node_preview'] = node_preview($node); + $form_state['rebuild'] = TRUE; } /** @@ -397,7 +397,6 @@ function node_form_submit($form, &$form_state) { drupal_set_message(t('@type %title has been updated.', $t_args)); } if ($node->nid) { - unset($form_state['rebuild']); $form_state['values']['nid'] = $node->nid; $form_state['nid'] = $node->nid; $form_state['redirect'] = 'node/' . $node->nid; @@ -406,25 +405,33 @@ function node_form_submit($form, &$form_state) { // In the unlikely case something went wrong on save, the node will be // rebuilt and node form redisplayed the same way as in preview. drupal_set_message(t('The post could not be saved.'), 'error'); + $form_state['rebuild'] = TRUE; } // Clear the page and block caches. cache_clear_all(); } /** - * Build a node by processing submitted form values and prepare for a form rebuild. + * Build a node by processing submitted form values and prepare for a form + * rebuild. As this function invokes form level submit handlers only call it + * if the form has already been fully validated. */ function node_form_submit_build_node($form, &$form_state) { // Unset any button-level handlers, execute all the form-level submit // functions to process the form values into an updated node. unset($form_state['submit_handlers']); form_execute_handlers('submit', $form, $form_state); - $node = node_submit((object)$form_state['values']); + $node = node_submit((object)($form_state['values'] + (array)$form_state['node'])); field_attach_submit('node', $node, $form, $form_state); - $form_state['node'] = (array)$node; - $form_state['rebuild'] = TRUE; + // Invoke the node submit hook. + foreach (module_implements('node_submit') as $module) { + $function = $module . '_node_submit'; + $function($node, $form, $form_state); + } + + $form_state['node'] = $node; return $node; } diff --git modules/poll/poll.module modules/poll/poll.module index d3607fc..9191c35 100644 --- modules/poll/poll.module +++ modules/poll/poll.module @@ -353,15 +353,16 @@ function poll_form($node, &$form_state) { * return just the changed part of the form. */ function poll_more_choices_submit($form, &$form_state) { - include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'node') . '/node.pages.inc'; - // Set the form to rebuild and run submit handlers. - node_form_submit_build_node($form, $form_state); - // Make the changes we want to the form state. if ($form_state['values']['poll_more']) { $n = $_GET['q'] == 'system/ajax' ? 1 : 5; $form_state['choice_count'] = count($form_state['values']['choice']) + $n; } + $form_state['node']->choice = array_values($form_state['values']['choice']); + // We reassign values based on the updated $node during the rebuild, so + // disable form API persistence for the form elements below 'choice'. + unset($form_state['input']['choice']); + $form_state['rebuild'] = TRUE; } function _poll_choice_form($key, $chid = NULL, $value = '', $votes = 0, $weight = 0, $size = 10) { @@ -423,6 +424,8 @@ function poll_node_form_submit(&$form, &$form_state) { // Renumber fields $form_state['values']['choice'] = array_values($form_state['values']['choice']); $form_state['values']['teaser'] = poll_teaser((object)$form_state['values']); + // Disable the form API persistence for the choice form elements. + unset($form_state['input']['choice']); } /**