web/drupal/modules/node/node.pages.inc
branchdrupal
changeset 74 0ff3ba646492
equal deleted inserted replaced
73:fcf75e232c5b 74:0ff3ba646492
       
     1 <?php
       
     2 // $Id: node.pages.inc,v 1.28.2.4 2009/04/27 11:35:01 goba Exp $
       
     3 
       
     4 /**
       
     5  * @file
       
     6  * Page callbacks for adding, editing, deleting, and revisions management for content.
       
     7  */
       
     8 
       
     9 
       
    10 /**
       
    11  * Menu callback; presents the node editing form, or redirects to delete confirmation.
       
    12  */
       
    13 function node_page_edit($node) {
       
    14   drupal_set_title(check_plain($node->title));
       
    15   return drupal_get_form($node->type .'_node_form', $node);
       
    16 }
       
    17 
       
    18 function node_add_page() {
       
    19   $item = menu_get_item();
       
    20   $content = system_admin_menu_block($item);
       
    21   return theme('node_add_list', $content);
       
    22 }
       
    23 
       
    24 /**
       
    25  * Display the list of available node types for node creation.
       
    26  *
       
    27  * @ingroup themeable
       
    28  */
       
    29 function theme_node_add_list($content) {
       
    30   $output = '';
       
    31 
       
    32   if ($content) {
       
    33     $output = '<dl class="node-type-list">';
       
    34     foreach ($content as $item) {
       
    35       $output .= '<dt>'. l($item['title'], $item['href'], $item['localized_options']) .'</dt>';      
       
    36       $output .= '<dd>'. filter_xss_admin($item['description']) .'</dd>';
       
    37     }
       
    38     $output .= '</dl>';
       
    39   }
       
    40   return $output;
       
    41 }
       
    42 
       
    43 
       
    44 /**
       
    45  * Present a node submission form or a set of links to such forms.
       
    46  */
       
    47 function node_add($type) {
       
    48   global $user;
       
    49 
       
    50   $types = node_get_types();
       
    51   $type = isset($type) ? str_replace('-', '_', $type) : NULL;
       
    52   // If a node type has been specified, validate its existence.
       
    53   if (isset($types[$type]) && node_access('create', $type)) {
       
    54     // Initialize settings:
       
    55     $node = array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'language' => '');
       
    56 
       
    57     drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)));
       
    58     $output = drupal_get_form($type .'_node_form', $node);
       
    59   }
       
    60 
       
    61   return $output;
       
    62 }
       
    63 
       
    64 function node_form_validate($form, &$form_state) {
       
    65   node_validate($form_state['values'], $form);
       
    66 }
       
    67 
       
    68 function node_object_prepare(&$node) {
       
    69   // Set up default values, if required.
       
    70   $node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
       
    71   // If this is a new node, fill in the default values.
       
    72   if (!isset($node->nid)) {
       
    73     foreach (array('status', 'promote', 'sticky') as $key) {
       
    74       $node->$key = in_array($key, $node_options);
       
    75     }
       
    76     global $user;
       
    77     $node->uid = $user->uid;
       
    78     $node->created = time();
       
    79   }
       
    80   else {
       
    81     $node->date = format_date($node->created, 'custom', 'Y-m-d H:i:s O');
       
    82     // Remove the log message from the original node object.
       
    83     $node->log = NULL;
       
    84   }
       
    85   // Always use the default revision setting.
       
    86   $node->revision = in_array('revision', $node_options);
       
    87 
       
    88   node_invoke($node, 'prepare');
       
    89   node_invoke_nodeapi($node, 'prepare');
       
    90 }
       
    91 
       
    92 /**
       
    93  * Generate the node add/edit form array.
       
    94  */
       
    95 function node_form(&$form_state, $node) {
       
    96   global $user;
       
    97 
       
    98   if (isset($form_state['node'])) {
       
    99     $node = $form_state['node'] + (array)$node;
       
   100   }
       
   101   if (isset($form_state['node_preview'])) {
       
   102     $form['#prefix'] = $form_state['node_preview'];
       
   103   }
       
   104   $node = (object)$node;
       
   105   foreach (array('body', 'title', 'format') as $key) {
       
   106     if (!isset($node->$key)) {
       
   107       $node->$key = NULL;
       
   108     }
       
   109   }
       
   110   if (!isset($form_state['node_preview'])) {
       
   111     node_object_prepare($node);
       
   112   }
       
   113   else {
       
   114     $node->build_mode = NODE_BUILD_PREVIEW;
       
   115   }
       
   116 
       
   117   // Set the id of the top-level form tag
       
   118   $form['#id'] = 'node-form';
       
   119 
       
   120   // Basic node information.
       
   121   // These elements are just values so they are not even sent to the client.
       
   122   foreach (array('nid', 'vid', 'uid', 'created', 'type', 'language') as $key) {
       
   123     $form[$key] = array(
       
   124       '#type' => 'value',
       
   125       '#value' => isset($node->$key) ? $node->$key : NULL,
       
   126     );
       
   127   }
       
   128 
       
   129   // Changed must be sent to the client, for later overwrite error checking.
       
   130   $form['changed'] = array(
       
   131     '#type' => 'hidden',
       
   132     '#default_value' => isset($node->changed) ? $node->changed : NULL,
       
   133   );
       
   134   // Get the node-specific bits.
       
   135   if ($extra = node_invoke($node, 'form', $form_state)) {
       
   136     $form = array_merge_recursive($form, $extra);
       
   137   }
       
   138   if (!isset($form['title']['#weight'])) {
       
   139     $form['title']['#weight'] = -5;
       
   140   }
       
   141 
       
   142   $form['#node'] = $node;
       
   143 
       
   144   // Add a log field if the "Create new revision" option is checked, or if the
       
   145   // current user has the ability to check that option.
       
   146   if (!empty($node->revision) || user_access('administer nodes')) {
       
   147     $form['revision_information'] = array(
       
   148       '#type' => 'fieldset',
       
   149       '#title' => t('Revision information'),
       
   150       '#collapsible' => TRUE,
       
   151       // Collapsed by default when "Create new revision" is unchecked
       
   152       '#collapsed' => !$node->revision,
       
   153       '#weight' => 20,
       
   154     );
       
   155     $form['revision_information']['revision'] = array(
       
   156       '#access' => user_access('administer nodes'),
       
   157       '#type' => 'checkbox',
       
   158       '#title' => t('Create new revision'),
       
   159       '#default_value' => $node->revision,
       
   160     );
       
   161     $form['revision_information']['log'] = array(
       
   162       '#type' => 'textarea',
       
   163       '#title' => t('Log message'),
       
   164       '#default_value' => (isset($node->log) ? $node->log : ''),
       
   165       '#rows' => 2,
       
   166       '#description' => t('An explanation of the additions or updates being made to help other authors understand your motivations.'),
       
   167     );
       
   168   }
       
   169 
       
   170   // Node author information for administrators
       
   171   $form['author'] = array(
       
   172     '#type' => 'fieldset',
       
   173     '#access' => user_access('administer nodes'),
       
   174     '#title' => t('Authoring information'),
       
   175     '#collapsible' => TRUE,
       
   176     '#collapsed' => TRUE,
       
   177     '#weight' => 20,
       
   178   );
       
   179   $form['author']['name'] = array(
       
   180     '#type' => 'textfield',
       
   181     '#title' => t('Authored by'),
       
   182     '#maxlength' => 60,
       
   183     '#autocomplete_path' => 'user/autocomplete',
       
   184     '#default_value' => $node->name ? $node->name : '',
       
   185     '#weight' => -1,
       
   186     '#description' => t('Leave blank for %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous')))),
       
   187   );
       
   188   $form['author']['date'] = array(
       
   189     '#type' => 'textfield',
       
   190     '#title' => t('Authored on'),
       
   191     '#maxlength' => 25,
       
   192     '#description' => t('Format: %time. Leave blank to use the time of form submission.', array('%time' => !empty($node->date) ? $node->date : format_date($node->created, 'custom', 'Y-m-d H:i:s O'))),
       
   193   );
       
   194 
       
   195   if (isset($node->date)) {
       
   196     $form['author']['date']['#default_value'] = $node->date;
       
   197   }
       
   198 
       
   199   // Node options for administrators
       
   200   $form['options'] = array(
       
   201     '#type' => 'fieldset',
       
   202     '#access' => user_access('administer nodes'),
       
   203     '#title' => t('Publishing options'),
       
   204     '#collapsible' => TRUE,
       
   205     '#collapsed' => TRUE,
       
   206     '#weight' => 25,
       
   207   );
       
   208   $form['options']['status'] = array(
       
   209     '#type' => 'checkbox',
       
   210     '#title' => t('Published'),
       
   211     '#default_value' => $node->status,
       
   212   );
       
   213   $form['options']['promote'] = array(
       
   214     '#type' => 'checkbox',
       
   215     '#title' => t('Promoted to front page'),
       
   216     '#default_value' => $node->promote,
       
   217   );
       
   218   $form['options']['sticky'] = array(
       
   219     '#type' => 'checkbox',
       
   220     '#title' => t('Sticky at top of lists'),
       
   221     '#default_value' => $node->sticky,
       
   222   );
       
   223 
       
   224   // These values are used when the user has no administrator access.
       
   225   foreach (array('uid', 'created') as $key) {
       
   226     $form[$key] = array(
       
   227       '#type' => 'value',
       
   228       '#value' => $node->$key,
       
   229     );
       
   230   }
       
   231 
       
   232   // Add the buttons.
       
   233   $form['buttons'] = array();
       
   234   $form['buttons']['submit'] = array(
       
   235     '#type' => 'submit',
       
   236     '#access' => !variable_get('node_preview', 0) || (!form_get_errors() && isset($form_state['node_preview'])),
       
   237     '#value' => t('Save'),
       
   238     '#weight' => 5,
       
   239     '#submit' => array('node_form_submit'),
       
   240   );
       
   241   $form['buttons']['preview'] = array(
       
   242     '#type' => 'submit',
       
   243     '#value' => t('Preview'),
       
   244     '#weight' => 10,
       
   245     '#submit' => array('node_form_build_preview'),
       
   246   );
       
   247   if (!empty($node->nid) && node_access('delete', $node)) {
       
   248     $form['buttons']['delete'] = array(
       
   249       '#type' => 'submit',
       
   250       '#value' => t('Delete'),
       
   251       '#weight' => 15,
       
   252       '#submit' => array('node_form_delete_submit'),
       
   253     );
       
   254   }
       
   255   $form['#validate'][] = 'node_form_validate';
       
   256   $form['#theme'] = array($node->type .'_node_form', 'node_form');
       
   257   return $form;
       
   258 }
       
   259 
       
   260 /**
       
   261  * Return a node body field, with format and teaser.
       
   262  */
       
   263 function node_body_field(&$node, $label, $word_count) {
       
   264 
       
   265   // Check if we need to restore the teaser at the beginning of the body.
       
   266   $include = !isset($node->teaser) || ($node->teaser == substr($node->body, 0, strlen($node->teaser)));
       
   267 
       
   268   $form = array(
       
   269     '#after_build' => array('node_teaser_js', 'node_teaser_include_verify'));
       
   270 
       
   271   $form['#prefix'] = '<div class="body-field-wrapper">';
       
   272   $form['#suffix'] = '</div>';
       
   273 
       
   274   $form['teaser_js'] = array(
       
   275     '#type' => 'textarea',
       
   276     '#rows' => 10,
       
   277     '#teaser' => 'edit-body',
       
   278     '#teaser_checkbox' => 'edit-teaser-include',
       
   279     '#disabled' => TRUE,
       
   280   );
       
   281 
       
   282   $form['teaser_include'] = array(
       
   283     '#type' => 'checkbox',
       
   284     '#title' => t('Show summary in full view'),
       
   285     '#default_value' => $include,
       
   286     '#prefix' => '<div class="teaser-checkbox">',
       
   287     '#suffix' => '</div>',
       
   288   );
       
   289 
       
   290   $form['body'] = array(
       
   291     '#type' => 'textarea',
       
   292     '#title' => check_plain($label),
       
   293     '#default_value' => $include ? $node->body : ($node->teaser . $node->body),
       
   294     '#rows' => 20,
       
   295     '#required' => ($word_count > 0),
       
   296   );
       
   297 
       
   298   $form['format'] = filter_form($node->format);
       
   299 
       
   300   return $form;
       
   301 }
       
   302 
       
   303 /**
       
   304  * Button sumit function: handle the 'Delete' button on the node form.
       
   305  */
       
   306 function node_form_delete_submit($form, &$form_state) {
       
   307   $destination = '';
       
   308   if (isset($_REQUEST['destination'])) {
       
   309     $destination = drupal_get_destination();
       
   310     unset($_REQUEST['destination']);
       
   311   }
       
   312   $node = $form['#node'];
       
   313   $form_state['redirect'] = array('node/'. $node->nid .'/delete', $destination);
       
   314 }
       
   315 
       
   316 
       
   317 function node_form_build_preview($form, &$form_state) {
       
   318   $node = node_form_submit_build_node($form, $form_state);
       
   319   $form_state['node_preview'] = node_preview($node);
       
   320 }
       
   321 
       
   322 /**
       
   323  * Present a node submission form.
       
   324  *
       
   325  * @ingroup themeable
       
   326  */
       
   327 function theme_node_form($form) {
       
   328   $output = "\n<div class=\"node-form\">\n";
       
   329 
       
   330   // Admin form fields and submit buttons must be rendered first, because
       
   331   // they need to go to the bottom of the form, and so should not be part of
       
   332   // the catch-all call to drupal_render().
       
   333   $admin = '';
       
   334   if (isset($form['author'])) {
       
   335     $admin .= "    <div class=\"authored\">\n";
       
   336     $admin .= drupal_render($form['author']);
       
   337     $admin .= "    </div>\n";
       
   338   }
       
   339   if (isset($form['options'])) {
       
   340     $admin .= "    <div class=\"options\">\n";
       
   341     $admin .= drupal_render($form['options']);
       
   342     $admin .= "    </div>\n";
       
   343   }
       
   344   $buttons = drupal_render($form['buttons']);
       
   345 
       
   346   // Everything else gets rendered here, and is displayed before the admin form
       
   347   // field and the submit buttons.
       
   348   $output .= "  <div class=\"standard\">\n";
       
   349   $output .= drupal_render($form);
       
   350   $output .= "  </div>\n";
       
   351 
       
   352   if (!empty($admin)) {
       
   353     $output .= "  <div class=\"admin\">\n";
       
   354     $output .= $admin;
       
   355     $output .= "  </div>\n";
       
   356   }
       
   357   $output .= $buttons;
       
   358   $output .= "</div>\n";
       
   359 
       
   360   return $output;
       
   361 }
       
   362 
       
   363 /**
       
   364  * Generate a node preview.
       
   365  */
       
   366 function node_preview($node) {
       
   367   if (node_access('create', $node) || node_access('update', $node)) {
       
   368     // Load the user's name when needed.
       
   369     if (isset($node->name)) {
       
   370       // The use of isset() is mandatory in the context of user IDs, because
       
   371       // user ID 0 denotes the anonymous user.
       
   372       if ($user = user_load(array('name' => $node->name))) {
       
   373         $node->uid = $user->uid;
       
   374         $node->picture = $user->picture;
       
   375       }
       
   376       else {
       
   377         $node->uid = 0; // anonymous user
       
   378       }
       
   379     }
       
   380     else if ($node->uid) {
       
   381       $user = user_load(array('uid' => $node->uid));
       
   382       $node->name = $user->name;
       
   383       $node->picture = $user->picture;
       
   384     }
       
   385 
       
   386     $node->changed = time();
       
   387 
       
   388     // Extract a teaser, if it hasn't been set (e.g. by a module-provided
       
   389     // 'teaser' form item).
       
   390     if (!isset($node->teaser)) {
       
   391       $node->teaser = empty($node->body) ? '' : node_teaser($node->body, $node->format);
       
   392       // Chop off the teaser from the body if needed.
       
   393       if (!$node->teaser_include && $node->teaser == substr($node->body, 0, strlen($node->teaser))) {
       
   394         $node->body = substr($node->body, strlen($node->teaser));
       
   395       }
       
   396     }
       
   397 
       
   398     // Display a preview of the node.
       
   399     // Previewing alters $node so it needs to be cloned.
       
   400     if (!form_get_errors()) {
       
   401       $cloned_node = drupal_clone($node);
       
   402       $cloned_node->build_mode = NODE_BUILD_PREVIEW;
       
   403       $output = theme('node_preview', $cloned_node);
       
   404     }
       
   405     drupal_set_title(t('Preview'));
       
   406 
       
   407     return $output;
       
   408   }
       
   409 }
       
   410 
       
   411 /**
       
   412  * Display a node preview for display during node creation and editing.
       
   413  *
       
   414  * @param $node
       
   415  *   The node object which is being previewed.
       
   416  *
       
   417  * @ingroup themeable
       
   418  */
       
   419 function theme_node_preview($node) {
       
   420   $output = '<div class="preview">';
       
   421 
       
   422   $preview_trimmed_version = FALSE;
       
   423   // Do we need to preview trimmed version of post as well as full version?
       
   424   if (isset($node->teaser) && isset($node->body)) {
       
   425     $teaser = trim($node->teaser);
       
   426     $body = trim(str_replace('<!--break-->', '', $node->body));
       
   427 
       
   428     // Preview trimmed version if teaser and body will appear different;
       
   429     // also (edge case) if both teaser and body have been specified by the user
       
   430     // and are actually the same.
       
   431     if ($teaser != $body || ($body && strpos($node->body, '<!--break-->') === 0)) {
       
   432       $preview_trimmed_version = TRUE;
       
   433     }
       
   434   }
       
   435 
       
   436   if ($preview_trimmed_version) {
       
   437     drupal_set_message(t('The trimmed version of your post shows what your post looks like when promoted to the main page or when exported for syndication.<span class="no-js"> You can insert the delimiter "&lt;!--break--&gt;" (without the quotes) to fine-tune where your post gets split.</span>'));
       
   438     $output .= '<h3>'. t('Preview trimmed version') .'</h3>';
       
   439     $output .= node_view(drupal_clone($node), 1, FALSE, 0);
       
   440     $output .= '<h3>'. t('Preview full version') .'</h3>';
       
   441     $output .= node_view($node, 0, FALSE, 0);
       
   442   }
       
   443   else {
       
   444     $output .= node_view($node, 0, FALSE, 0);
       
   445   }
       
   446   $output .= "</div>\n";
       
   447 
       
   448   return $output;
       
   449 }
       
   450 
       
   451 function node_form_submit($form, &$form_state) {
       
   452   global $user;
       
   453 
       
   454   $node = node_form_submit_build_node($form, $form_state);
       
   455   $insert = empty($node->nid);
       
   456   node_save($node);
       
   457   $node_link = l(t('view'), 'node/'. $node->nid);
       
   458   $watchdog_args = array('@type' => $node->type, '%title' => $node->title);
       
   459   $t_args = array('@type' => node_get_types('name', $node), '%title' => $node->title);
       
   460 
       
   461   if ($insert) {
       
   462     watchdog('content', '@type: added %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link);
       
   463     drupal_set_message(t('@type %title has been created.', $t_args));
       
   464   }
       
   465   else {
       
   466     watchdog('content', '@type: updated %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link);
       
   467     drupal_set_message(t('@type %title has been updated.', $t_args));
       
   468   }
       
   469   if ($node->nid) {
       
   470     unset($form_state['rebuild']);
       
   471     $form_state['nid'] = $node->nid;
       
   472     $form_state['redirect'] = 'node/'. $node->nid;
       
   473   }
       
   474   else {
       
   475     // In the unlikely case something went wrong on save, the node will be
       
   476     // rebuilt and node form redisplayed the same way as in preview.
       
   477     drupal_set_message(t('The post could not be saved.'), 'error');
       
   478   }
       
   479 }
       
   480 
       
   481 /**
       
   482  * Build a node by processing submitted form values and prepare for a form rebuild.
       
   483  */
       
   484 function node_form_submit_build_node($form, &$form_state) {
       
   485   // Unset any button-level handlers, execute all the form-level submit
       
   486   // functions to process the form values into an updated node.
       
   487   unset($form_state['submit_handlers']);
       
   488   form_execute_handlers('submit', $form, $form_state);
       
   489   $node = node_submit($form_state['values']);
       
   490   $form_state['node'] = (array)$node;
       
   491   $form_state['rebuild'] = TRUE;
       
   492   return $node;
       
   493 }
       
   494 
       
   495 /**
       
   496  * Menu callback -- ask for confirmation of node deletion
       
   497  */
       
   498 function node_delete_confirm(&$form_state, $node) {
       
   499   $form['nid'] = array(
       
   500     '#type' => 'value',
       
   501     '#value' => $node->nid,
       
   502   );
       
   503 
       
   504   return confirm_form($form,
       
   505     t('Are you sure you want to delete %title?', array('%title' => $node->title)),
       
   506     isset($_GET['destination']) ? $_GET['destination'] : 'node/'. $node->nid,
       
   507     t('This action cannot be undone.'),
       
   508     t('Delete'),
       
   509     t('Cancel')
       
   510   );
       
   511 }
       
   512 
       
   513 /**
       
   514  * Execute node deletion
       
   515  */
       
   516 function node_delete_confirm_submit($form, &$form_state) {
       
   517   if ($form_state['values']['confirm']) {
       
   518     node_delete($form_state['values']['nid']);
       
   519   }
       
   520 
       
   521   $form_state['redirect'] = '<front>';
       
   522 }
       
   523 
       
   524 /**
       
   525  * Generate an overview table of older revisions of a node.
       
   526  */
       
   527 function node_revision_overview($node) {
       
   528   drupal_set_title(t('Revisions for %title', array('%title' => $node->title)));
       
   529 
       
   530   $header = array(t('Revision'), array('data' => t('Operations'), 'colspan' => 2));
       
   531 
       
   532   $revisions = node_revision_list($node);
       
   533 
       
   534   $rows = array();
       
   535   $revert_permission = FALSE;
       
   536   if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
       
   537     $revert_permission = TRUE;
       
   538   }
       
   539   $delete_permission = FALSE;
       
   540   if ((user_access('delete revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
       
   541     $delete_permission = TRUE;
       
   542   }
       
   543   foreach ($revisions as $revision) {
       
   544     $row = array();
       
   545     $operations = array();
       
   546 
       
   547     if ($revision->current_vid > 0) {
       
   548       $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'small'), "node/$node->nid"), '!username' => theme('username', $revision)))
       
   549                                . (($revision->log != '') ? '<p class="revision-log">'. filter_xss($revision->log) .'</p>' : ''),
       
   550                      'class' => 'revision-current');
       
   551       $operations[] = array('data' => theme('placeholder', t('current revision')), 'class' => 'revision-current', 'colspan' => 2);
       
   552     }
       
   553     else {
       
   554       $row[] = t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'small'), "node/$node->nid/revisions/$revision->vid/view"), '!username' => theme('username', $revision)))
       
   555                . (($revision->log != '') ? '<p class="revision-log">'. filter_xss($revision->log) .'</p>' : '');
       
   556       if ($revert_permission) {
       
   557         $operations[] = l(t('revert'), "node/$node->nid/revisions/$revision->vid/revert");
       
   558       }
       
   559       if ($delete_permission) {
       
   560         $operations[] = l(t('delete'), "node/$node->nid/revisions/$revision->vid/delete");
       
   561       }
       
   562     }
       
   563     $rows[] = array_merge($row, $operations);
       
   564   }
       
   565 
       
   566   return theme('table', $header, $rows);
       
   567 }
       
   568 
       
   569 /**
       
   570  * Ask for confirmation of the reversion to prevent against CSRF attacks.
       
   571  */
       
   572 function node_revision_revert_confirm($form_state, $node_revision) {
       
   573   $form['#node_revision'] = $node_revision;
       
   574   return confirm_form($form, t('Are you sure you want to revert to the revision from %revision-date?', array('%revision-date' => format_date($node_revision->revision_timestamp))), 'node/'. $node_revision->nid .'/revisions', '', t('Revert'), t('Cancel'));
       
   575 }
       
   576 
       
   577 function node_revision_revert_confirm_submit($form, &$form_state) {
       
   578   $node_revision = $form['#node_revision'];
       
   579   $node_revision->revision = 1;
       
   580   $node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($node_revision->revision_timestamp)));
       
   581   if (module_exists('taxonomy')) {
       
   582     $node_revision->taxonomy = array_keys($node_revision->taxonomy);
       
   583   }
       
   584 
       
   585   node_save($node_revision);
       
   586 
       
   587   watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid));
       
   588   drupal_set_message(t('@type %title has been reverted back to the revision from %revision-date.', array('@type' => node_get_types('name', $node_revision), '%title' => $node_revision->title, '%revision-date' => format_date($node_revision->revision_timestamp))));
       
   589   $form_state['redirect'] = 'node/'. $node_revision->nid .'/revisions';
       
   590 }
       
   591 
       
   592 function node_revision_delete_confirm($form_state, $node_revision) {
       
   593   $form['#node_revision'] = $node_revision;
       
   594   return confirm_form($form, t('Are you sure you want to delete the revision from %revision-date?', array('%revision-date' => format_date($node_revision->revision_timestamp))), 'node/'. $node_revision->nid .'/revisions', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
       
   595 }
       
   596 
       
   597 function node_revision_delete_confirm_submit($form, &$form_state) {
       
   598   $node_revision = $form['#node_revision'];
       
   599   db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $node_revision->nid, $node_revision->vid);
       
   600   node_invoke_nodeapi($node_revision, 'delete revision');
       
   601   watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid));
       
   602   drupal_set_message(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($node_revision->revision_timestamp), '@type' => node_get_types('name', $node_revision), '%title' => $node_revision->title)));
       
   603   $form_state['redirect'] = 'node/'. $node_revision->nid;
       
   604   if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node_revision->nid)) > 1) {
       
   605     $form_state['redirect'] .= '/revisions';
       
   606   }
       
   607 }