diff --git modules/book/book.module modules/book/book.module index d60ab18..318b483 100644 --- modules/book/book.module +++ modules/book/book.module @@ -399,7 +399,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) { @@ -419,13 +419,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 63b9a84..89e60e6 100644 --- modules/field/field.form.inc +++ modules/field/field.form.inc @@ -131,11 +131,6 @@ function field_default_form($entity_type, $entity, $field, $instance, $langcode, * - drag-n-drop value reordering */ function field_multiple_value_form($field, $instance, $langcode, $items, &$form, &$form_state) { - // This form has its own multistep persistance. - if ($form_state['rebuild']) { - $form_state['input'] = array(); - } - $field_name = $field['field_name']; // Determine the number of widgets to display. @@ -368,16 +363,16 @@ 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. 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]); } } diff --git modules/field/tests/field.test modules/field/tests/field.test index 29a9e33..5205fec 100644 --- modules/field/tests/field.test +++ modules/field/tests/field.test @@ -1562,18 +1562,17 @@ class FieldFormTestCase extends FieldTestCase { $edit["$this->field_name[$langcode][$delta][value]"] = $value; $edit["$this->field_name[$langcode][$delta][_weight]"] = $weight; // We'll need three slightly different formats to check the values. - $values[$weight] = $value; + $values[$delta] = $value; + $weights[$delta] = $weight; $field_values[$weight]['value'] = (string)$value; $pattern[$weight] = "]*value=\"$value\" [^>]*"; } // Press 'add more' button -> 4 widgets $this->drupalPost(NULL, $edit, t('Add another item')); - ksort($values); - $values = array_values($values); for ($delta = 0; $delta <= $delta_range; $delta++) { $this->assertFieldByName("$this->field_name[$langcode][$delta][value]", $values[$delta], "Widget $delta is displayed and has the right value"); - $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $delta, "Widget $delta has the right weight"); + $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $weights[$delta], "Widget $delta has the right weight"); } ksort($pattern); $pattern = implode('.*', array_values($pattern)); @@ -1632,7 +1631,8 @@ class FieldFormTestCase extends FieldTestCase { $edit["$this->field_name[$langcode][$delta][value]"] = $value; $edit["$this->field_name[$langcode][$delta][_weight]"] = $weight; // We'll need three slightly different formats to check the values. - $values[$weight] = $value; + $values[$delta] = $value; + $weights[$delta] = $weight; $field_values[$weight]['value'] = (string)$value; $pattern[$weight] = "]*value=\"$value\" [^>]*"; } @@ -1641,11 +1641,9 @@ class FieldFormTestCase extends FieldTestCase { $commands = $this->drupalPostAJAX(NULL, $edit, $this->field_name . '_add_more'); $this->content = $commands[1]['data']; - ksort($values); - $values = array_values($values); for ($delta = 0; $delta <= $delta_range; $delta++) { $this->assertFieldByName("$this->field_name[$langcode][$delta][value]", $values[$delta], "Widget $delta is displayed and has the right value"); - $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $delta, "Widget $delta has the right weight"); + $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $weights[$delta], "Widget $delta has the right weight"); } ksort($pattern); $pattern = implode('.*', array_values($pattern)); diff --git modules/node/node.pages.inc modules/node/node.pages.inc index fce7bfd..b9aaaf4 100644 --- modules/node/node.pages.inc +++ modules/node/node.pages.inc @@ -72,6 +72,7 @@ function node_add($type) { } function node_form_validate($form, &$form_state) { + // @todo for D8: Fix to don't pass that half baken $node object around. $node = (object)$form_state['values']; node_validate($node, $form); @@ -85,14 +86,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']; } @@ -134,6 +132,7 @@ function node_form($form, &$form_state, $node) { $form['title']['#weight'] = -5; } + // @todo Drop this for D8 so only $form_state[$entity_type] is used. $form['#node'] = $node; $form['additional_settings'] = array( @@ -266,7 +265,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; @@ -289,6 +287,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; } /** @@ -403,7 +402,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; @@ -412,23 +410,30 @@ 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; } } /** - * 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'])); + // Invoke the node submit hook. + foreach (module_implements('node_submit') as $module) { + $function = $module . '_node_submit'; + $function($node, $form, $form_state); + } field_attach_submit('node', $node, $form, $form_state); + $form_state['node'] = $node; - $form_state['node'] = (array)$node; - $form_state['rebuild'] = TRUE; return $node; } diff --git modules/poll/poll.module modules/poll/poll.module index 41ac9e2..b51b9ec 100644 --- modules/poll/poll.module +++ modules/poll/poll.module @@ -355,15 +355,15 @@ 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']); + // Disable the form API persistence for the choice form elements. + unset($form_state['input']['choice']); + $form_state['rebuild'] = TRUE; } function _poll_choice_form($key, $chid = NULL, $value = '', $votes = 0, $weight = 0, $size = 10) { @@ -425,6 +425,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']); } /**