node.pages.inc 11.6 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5 6 7 8 9
 * Callbacks for adding, editing, and deleting content and managing revisions.
 *
 * Also includes validation, submission and other helper functions.
 *
 * @see node_menu()
10 11
 */

12
use Drupal\node\Node;
13 14

/**
15 16 17
 * Page callback: Presents the node editing form.
 *
 * @see node_menu()
18
 */
19
function node_page_edit($node) {
20
  $type_name = node_type_get_name($node);
21
  drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => $type_name, '@title' => $node->label())), PASS_THROUGH);
22
  return entity_get_form($node);
23 24
}

25
/**
26 27 28
 * Page callback: Displays add content links for available content types.
 *
 * Redirects to node/add/[type] if only one content type is available.
29 30 31
 *
 * @see node_menu()
 */
32
function node_add_page() {
33 34 35 36 37 38 39
  $content = array();
  // Only use node types the user has access to.
  foreach (node_type_get_types() as $type) {
    if (node_hook($type->type, 'form') && node_access('create', $type->type)) {
      $content[$type->type] = $type;
    }
  }
40 41
  // Bypass the node/add listing if only one content type is available.
  if (count($content) == 1) {
42 43
    $type = array_shift($content);
    drupal_goto('node/add/' . $type->type);
44
  }
45
  return array('#theme' => 'node_add_list', '#content' => $content);
46 47
}

48
/**
49 50 51 52 53
 * Returns HTML for a list of available node types for node creation.
 *
 * @param $variables
 *   An associative array containing:
 *   - content: An array of content types.
54
 *
55
 * @see node_add_page()
56 57
 * @ingroup themeable
 */
58 59
function theme_node_add_list($variables) {
  $content = $variables['content'];
60 61 62 63
  $output = '';

  if ($content) {
    $output = '<dl class="node-type-list">';
64 65 66
    foreach ($content as $type) {
      $output .= '<dt>' . l($type->name, 'node/add/' . $type->type) . '</dt>';
      $output .= '<dd>' . filter_xss_admin($type->description) . '</dd>';
67 68 69
    }
    $output .= '</dl>';
  }
70
  else {
71
    $output = '<p>' . t('You have not created any content types yet. Go to the <a href="@create-content">content type creation page</a> to add a new content type.', array('@create-content' => url('admin/structure/types/add'))) . '</p>';
72
  }
73 74 75 76 77
  return $output;
}


/**
78 79
 * Page callback: Provides the node submission form.
 *
80 81
 * @param $node_type
 *   The node type object for the submitted node.
82 83 84 85 86
 *
 * @return
 *   Returns a node submission form.
 *
 * @see node_menu()
87
 */
88
function node_add($node_type) {
89 90
  global $user;

91
  $type = $node_type->type;
92 93 94 95
  $node = entity_create('node', array(
    'uid' => $user->uid,
    'name' => (isset($user->name) ? $user->name : ''),
    'type' => $type,
96
    'langcode' => node_type_get_default_langcode($type)
97
  ));
98
  drupal_set_title(t('Create @name', array('@name' => $node_type->name)), PASS_THROUGH);
99
  $output = entity_get_form($node);
100 101 102 103 104

  return $output;
}

/**
105 106
 * Generates a node preview.
 *
107
 * @param Drupal\node\Node $node
108 109 110 111 112 113
 *   The node to preview.
 *
 * @return
 *   Themed node preview.
 *
 * @see node_form_build_preview()
114
 */
115
function node_preview(Node $node) {
116
  if (node_access('create', $node) || node_access('update', $node)) {
117
    _field_invoke_multiple('load', 'node', array($node->nid => $node));
118
    // Load the user's name when needed.
119 120 121
    if (isset($node->name)) {
      // The use of isset() is mandatory in the context of user IDs, because
      // user ID 0 denotes the anonymous user.
122
      if ($user = user_load_by_name($node->name)) {
123 124 125 126 127 128 129
        $node->uid = $user->uid;
        $node->picture = $user->picture;
      }
      else {
        $node->uid = 0; // anonymous user
      }
    }
130
    elseif ($node->uid) {
131
      $user = user_load($node->uid);
132 133 134 135
      $node->name = $user->name;
      $node->picture = $user->picture;
    }

136
    $node->changed = REQUEST_TIME;
137 138
    $nodes = array($node->nid => $node);
    field_attach_prepare_view('node', $nodes, 'full');
139

140
    // Display a preview of the node.
141
    if (!form_get_errors()) {
142 143 144
      $node->in_preview = TRUE;
      $output = theme('node_preview', array('node' => $node));
      unset($node->in_preview);
145 146 147 148 149 150 151
    }

    return $output;
  }
}

/**
152
 * Returns HTML for a node preview for display during node creation and editing.
153
 *
154 155
 * @param $variables
 *   An associative array containing:
156
 *   - node: The node entity which is being previewed.
157
 *
158
 * @see NodeFormController::preview()
159
 * @ingroup themeable
160
 */
161 162 163
function theme_node_preview($variables) {
  $node = $variables['node'];

164
  $output = '';
165

166
  $preview_trimmed_version = FALSE;
167

168 169 170 171
  $elements = node_view(clone $node, 'teaser');
  $trimmed = drupal_render($elements);
  $elements = node_view($node, 'full');
  $full = drupal_render($elements);
172 173 174

  // Do we need to preview trimmed version of post as well as full version?
  if ($trimmed != $full) {
175
    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>'));
176
    $output .= '<h3>' . t('Preview trimmed version') . '</h3>';
177
    $output .= $trimmed;
178
    $output .= '<h3>' . t('Preview full version') . '</h3>';
179
    $output .= $full;
180 181
  }
  else {
182
    $output .= $full;
183 184 185 186 187 188
  }

  return $output;
}

/**
189 190 191
 * Page callback: Form constructor for node deletion confirmation form.
 *
 * @see node_menu()
192
 */
193
function node_delete_confirm($form, &$form_state, $node) {
194 195
  // Always provide entity id in the same form key as in the entity edit form.
  $form['nid'] = array('#type' => 'value', '#value' => $node->nid);
196
  return confirm_form($form,
197
    t('Are you sure you want to delete %title?', array('%title' => $node->label())),
198
    'node/' . $node->nid,
199
    t('This action cannot be undone.'),
200
    t('Delete'),
201 202
    t('Cancel')
  );
203 204 205
}

/**
206
 * Form submission handler for node_delete_confirm().
207 208 209
 */
function node_delete_confirm_submit($form, &$form_state) {
  if ($form_state['values']['confirm']) {
210
    $node = node_load($form_state['values']['nid']);
211
    node_delete($form_state['values']['nid']);
212 213
    watchdog('content', '@type: deleted %title.', array('@type' => $node->type, '%title' => $node->label()));
    drupal_set_message(t('@type %title has been deleted.', array('@type' => node_type_get_name($node), '%title' => $node->label())));
214 215 216 217 218 219
  }

  $form_state['redirect'] = '<front>';
}

/**
220 221 222
 * Page callback: Generates an overview table of older revisions of a node.
 *
 * @see node_menu()
223
 */
224
function node_revision_overview($node) {
225
  drupal_set_title(t('Revisions for %title', array('%title' => $node->label())), PASS_THROUGH);
226 227 228 229 230 231 232 233 234 235 236

  $header = array(t('Revision'), array('data' => t('Operations'), 'colspan' => 2));

  $revisions = node_revision_list($node);

  $rows = array();
  $revert_permission = FALSE;
  if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
    $revert_permission = TRUE;
  }
  $delete_permission = FALSE;
237
  if ((user_access('delete revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
238 239 240 241 242 243 244
    $delete_permission = TRUE;
  }
  foreach ($revisions as $revision) {
    $row = array();
    $operations = array();

    if ($revision->current_vid > 0) {
245
      $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'short'), "node/$node->nid"), '!username' => theme('username', array('account' => $revision))))
246
                               . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : ''),
247
                     'class' => array('revision-current'));
248
      $operations[] = array('data' => drupal_placeholder(t('current revision')), 'class' => array('revision-current'), 'colspan' => 2);
249 250
    }
    else {
251
      $row[] = t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'short'), "node/$node->nid/revisions/$revision->vid/view"), '!username' => theme('username', array('account' => $revision))))
252
               . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : '');
253 254 255 256 257 258 259 260 261
      if ($revert_permission) {
        $operations[] = l(t('revert'), "node/$node->nid/revisions/$revision->vid/revert");
      }
      if ($delete_permission) {
        $operations[] = l(t('delete'), "node/$node->nid/revisions/$revision->vid/delete");
      }
    }
    $rows[] = array_merge($row, $operations);
  }
262

263 264 265 266
  $build['node_revisions_table'] = array(
    '#theme' => 'table',
    '#rows' => $rows,
    '#header' => $header,
267 268 269
    '#attached' => array (
      'css' => array(drupal_get_path('module', 'node') . '/node.admin.css'),
    ),
270
  );
271

272
  return $build;
273 274
}

275
/**
276 277 278 279 280 281
 * Page callback: Form constructor for the reversion confirmation form.
 *
 * This form prevents against CSRF attacks.
 *
 * @see node_menu()
 * @see node_revision_revert_confirm_submit()
282
 */
283
function node_revision_revert_confirm($form, $form_state, $node_revision) {
284
  $form['#node_revision'] = $node_revision;
285
  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'));
286 287
}

288 289 290
/**
 * Form submission handler for node_revision_revert_confirm().
 */
291 292 293
function node_revision_revert_confirm_submit($form, &$form_state) {
  $node_revision = $form['#node_revision'];
  $node_revision->revision = 1;
294 295
  // Make this the new default revision for the node.
  $node_revision->isDefaultRevision = TRUE;
296 297 298 299 300 301

  // The revision timestamp will be updated when the revision is saved. Keep the
  // original one for the confirmation message.
  $original_revision_timestamp = $node_revision->revision_timestamp;

  $node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($original_revision_timestamp)));
302

303
  $node_revision->save();
304

305 306
  watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->label(), '%revision' => $node_revision->vid));
  drupal_set_message(t('@type %title has been reverted back to the revision from %revision-date.', array('@type' => node_type_get_name($node_revision), '%title' => $node_revision->label(), '%revision-date' => format_date($original_revision_timestamp))));
307
  $form_state['redirect'] = 'node/' . $node_revision->nid . '/revisions';
308
}
309

310 311 312 313 314 315 316 317
/**
 * Page callback: Form constructor for the revision deletion confirmation form.
 *
 * This form prevents against CSRF attacks.
 *
 * @see node_menu()
 * @see node_revision_delete_confirm_submit()
 */
318
function node_revision_delete_confirm($form, $form_state, $node_revision) {
319
  $form['#node_revision'] = $node_revision;
320
  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'));
321 322
}

323 324 325
/**
 * Form submission handler for node_revision_delete_confirm().
 */
326 327
function node_revision_delete_confirm_submit($form, &$form_state) {
  $node_revision = $form['#node_revision'];
328 329
  node_revision_delete($node_revision->vid);

330 331
  watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->label(), '%revision' => $node_revision->vid));
  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_type_get_name($node_revision), '%title' => $node_revision->label())));
332
  $form_state['redirect'] = 'node/' . $node_revision->nid;
333
  if (db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid', array(':nid' => $node_revision->nid))->fetchField() > 1) {
334 335 336
    $form_state['redirect'] .= '/revisions';
  }
}