=== modified file 'includes/form.inc' --- includes/form.inc 2009-03-30 03:15:40 +0000 +++ includes/form.inc 2009-04-05 04:52:20 +0000 @@ -208,7 +208,7 @@ function drupal_build_form($form_id, &$f // the form, passing in the latest $form_state in addition to any // other variables passed into drupal_get_form(). - if (!empty($form_state['rebuild']) || !empty($form_state['storage'])) { + if (!form_get_errors() && (!empty($form_state['rebuild']) || !empty($form_state['storage']))) { $form = drupal_rebuild_form($form_id, $form_state); } === modified file 'modules/node/node.test' --- modules/node/node.test 2009-03-31 01:49:50 +0000 +++ modules/node/node.test 2009-04-05 04:54:20 +0000 @@ -637,3 +637,39 @@ class NodeRSSContentTestCase extends Dru $this->assertText($test_text, t('Extra node content appears in RSS feed.')); } } + +class TwoStepNodeTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => t('Two step node'), + 'description' => t('Test that two step nodes keep their taxonomy.'), + 'group' => t('Node') + ); + } + + function setUp() { + parent::setUp('taxonomy', 'twostepnode'); + } + + function testTwoStepNode() { + $this->account = $this->drupalCreateUser(array('create twostepnode content')); + $this->drupalLogin($this->account); + // Create a vocabulary. + $vocabulary = new stdClass(); + $vocabulary->name = $this->randomName(); + $vocabulary->nodes = array('twostepnode' => 'twostepnode'); + taxonomy_vocabulary_save($vocabulary); + $term = new stdClass(); + $term->name = $this->randomName(); + $term->vid = $vocabulary->vid; + taxonomy_term_save($term); + $title = $this->randomName(); + $edit = array('title' => $title); + $this->drupalPost('node/add/twostepnode', $edit, t('Next')); + $edit = array("taxonomy[$term->vid]" => $term->tid); + $this->drupalPost(NULL, $edit, t('Preview')); + $this->assertText(t('Required body field is required.'), t('Error present')); + $options = $this->xpath('//option[@value="'. $term->tid .'"]'); + $this->assertTrue($options[0]['selected'] == 'selected', t('Term still selected')); + } +} === added file 'modules/node/tests/twostepnode.info' --- modules/node/tests/twostepnode.info 1970-01-01 00:00:00 +0000 +++ modules/node/tests/twostepnode.info 2009-04-05 04:13:54 +0000 @@ -0,0 +1,6 @@ +; $Id$ +name = Two step node +description = Provides a node type with a 2-step form for testing. +core = 7.x +files[] = twostepnode.module +hidden = TRUE === added file 'modules/node/tests/twostepnode.module' --- modules/node/tests/twostepnode.module 1970-01-01 00:00:00 +0000 +++ modules/node/tests/twostepnode.module 2009-04-05 04:51:38 +0000 @@ -0,0 +1,130 @@ + array( + 'name' => t('2-step node'), + 'base' => 'twostepnode', + 'description' => t('A node that uses a multi-step node form for testing.'), + ), + ); +} + +/** + * Implementation of hook_perm. + */ +function twostepnode_perm() { + return node_list_permissions('twostepnode'); +} + +/** + * Implementation of hook_access. + */ +function twostepnode_access($op, $node, $account) { + global $user; + switch ($op) { + case 'create': + return user_access('create twostepnode content', $account); + case 'update': + return user_access('edit any twostepnode content', $account) || (user_access('edit own twostepnode content', $account) && ($node->uid == $account->uid)); + case 'delete': + return user_access('delete any twostepnode content', $account) || (user_access('delete own twostepnode content', $account) && ($node->uid == $account->uid)); + } +} + +/** + * Implementation of hook_form(). + */ +function twostepnode_form($node, $form_state) { + $form['title'] = array( + '#title' => t('Title'), + '#type' => 'textfield', + '#required' => TRUE, + '#default_value' => isset($form_state['storage']['title']) ? $form_state['storage']['title'] : $node->title, + ); + $form['body_field'] = node_body_field($node, t('Required body'), 1); + return $form; +} + +/** + * Implementation of hook_form_alter(). + * + * When first adding the node, put the 'Title' field on its own page in a + * multistep node form. We need to do this in hook_form_alter() itself + * instead of a form_id-specific form alter so that we're likely to come after + * everyone else's alterings, e.g. taxonomy, menu, etc. + */ +function twostepnode_form_alter(&$form, $form_state, $form_id) { + if ($form_id == 'twostepnode_node_form') { + $node = $form['#node']; + if (empty($form_state['storage']['title']) && empty($node->title)) { + _twostepnode_step1($form, array('title')); + } + else { + // For the actual submit button, add a handler to clear out + // $form_state['storage']['title'] so that we actually submit the form. + $form['buttons']['submit']['#submit'][] = 'twostepnode_node_form_final_submit'; + } + } +} + +/** + * Helper function to convert the node form into step 1 of a multi-step form. + * + * Marks all form elements to #access FALSE except those required on step 1, + * converts the usual "preview" button into a "next" button and hides the + * submit button. + */ +function _twostepnode_step1(&$form) { + // Hide all the elements we don't want on step 1. + foreach (element_children($form) as $child) { + if ($child != 'buttons' && + (empty($form[$child]['#type']) || + ($form[$child]['#type'] != 'hidden' + && $form[$child]['#type'] != 'value' + && $form[$child]['#type'] != 'token' + && ($child != 'title')))) { + $form[$child]['#access'] = FALSE; + } + } + + // Change preview to next and hide submit. + $form['buttons']['preview'] = array( + '#type' => 'submit', + '#value' => t('Next'), + '#weight' => 50, + '#submit' => array('twostepnode_node_form_next_handler'), + ); + $form['buttons']['submit']['#access'] = FALSE; +} + +/** + * Submit handler for the 'Next' button on step 1. + * + * Saves the title value into $form_state['storage']. + */ +function twostepnode_node_form_next_handler($form, &$form_state) { + if (isset($form_state['values']['title'])) { + $form_state['storage']['title'] = $form_state['values']['title']; + } +} + +/** + * Submit handler for the "Save" button on step 2. + * + * Clears out $form_state['storage']['title'] so the form will submit and will + * not rebuild itself. + */ +function twostepnode_node_form_final_submit(&$form, &$form_state) { + unset($form_state['storage']['title']); +} +