/[drupal]/drupal/modules/node/node.pages.inc
ViewVC logotype

Contents of /drupal/modules/node/node.pages.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.99 - (show annotations) (download) (as text)
Mon Nov 2 04:45:28 2009 UTC (3 weeks, 5 days ago) by webchick
Branch: MAIN
Changes since 1.98: +2 -2 lines
File MIME type: text/x-php
#484060 by EclipseGc: Remove duplicate access checking from node_add().
1 <?php
2 // $Id: node.pages.inc,v 1.98 2009/11/02 04:45:02 webchick 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(stdClass $node) {
14 $type_name = node_type_get_name($node);
15 drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => $type_name, '@title' => $node->title[FIELD_LANGUAGE_NONE][0]['value'])), PASS_THROUGH);
16 return drupal_get_form($node->type . '_node_form', $node);
17 }
18
19 function node_add_page() {
20 $item = menu_get_item();
21 $content = system_admin_menu_block($item);
22 // Bypass the node/add listing if only one content type is available.
23 if (count($content) == 1) {
24 $item = array_shift($content);
25 drupal_goto($item['href']);
26 }
27 return theme('node_add_list', array('content' => $content));
28 }
29
30 /**
31 * Display the list of available node types for node creation.
32 *
33 * @ingroup themeable
34 */
35 function theme_node_add_list($variables) {
36 $content = $variables['content'];
37 $output = '';
38
39 if ($content) {
40 $output = '<dl class="node-type-list">';
41 foreach ($content as $item) {
42 $output .= '<dt>' . l($item['title'], $item['href'], $item['localized_options']) . '</dt>';
43 $output .= '<dd>' . filter_xss_admin($item['description']) . '</dd>';
44 }
45 $output .= '</dl>';
46 }
47 else {
48 $output = '<p>' . t('You have not created any content types yet. Please 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>';
49 }
50 return $output;
51 }
52
53
54 /**
55 * Present a node submission form or a set of links to such forms.
56 */
57 function node_add($type) {
58 global $user;
59
60 $types = node_type_get_types();
61 $type = isset($type) ? str_replace('-', '_', $type) : NULL;
62 // If a node type has been specified, validate its existence.
63 if (isset($types[$type])) {
64 // Initialize settings:
65 $node = (object)array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'language' => '');
66
67 drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)), PASS_THROUGH);
68 $output = drupal_get_form($type . '_node_form', $node);
69 }
70
71 return $output;
72 }
73
74 function node_form_validate($form, &$form_state) {
75 $node = (object)$form_state['values'];
76 node_validate($node, $form);
77
78 // Field validation. Requires access to $form_state, so this cannot be
79 // done in node_validate() as it currently exists.
80 field_attach_form_validate('node', $node, $form, $form_state);
81 }
82
83 function node_object_prepare(stdClass $node) {
84 // Set up default values, if required.
85 $node_options = variable_get('node_options_' . $node->type, array('status', 'promote'));
86 // If this is a new node, fill in the default values.
87 if (!isset($node->nid)) {
88 foreach (array('status', 'promote', 'sticky') as $key) {
89 $node->$key = (int) in_array($key, $node_options);
90 }
91 global $user;
92 $node->uid = $user->uid;
93 $node->created = REQUEST_TIME;
94 }
95 else {
96 $node->date = format_date($node->created, 'custom', 'Y-m-d H:i:s O');
97 // Remove the log message from the original node object.
98 $node->log = NULL;
99 }
100 // Always use the default revision setting.
101 $node->revision = in_array('revision', $node_options);
102
103 node_invoke($node, 'prepare');
104 module_invoke_all('node_prepare', $node);
105 }
106
107 /**
108 * Generate the node add/edit form array.
109 */
110 function node_form($form, &$form_state, stdClass $node) {
111 global $user;
112
113 if (isset($form_state['node'])) {
114 $node = (object)($form_state['node'] + (array)$node);
115 }
116 if (isset($form_state['node_preview'])) {
117 $form['#prefix'] = $form_state['node_preview'];
118 }
119 foreach (array('title') as $key) {
120 if (!isset($node->$key)) {
121 $node->$key = NULL;
122 }
123 }
124 if (!isset($form_state['node_preview'])) {
125 node_object_prepare($node);
126 }
127 else {
128 $node->in_preview = TRUE;
129 }
130
131 // Set the id and identify this as a node edit form.
132 $form['#id'] = 'node-form';
133 $form['#node_edit_form'] = TRUE;
134
135 // Basic node information.
136 // These elements are just values so they are not even sent to the client.
137 foreach (array('nid', 'vid', 'uid', 'created', 'type', 'language') as $key) {
138 $form[$key] = array(
139 '#type' => 'value',
140 '#value' => isset($node->$key) ? $node->$key : NULL,
141 );
142 }
143
144 // Changed must be sent to the client, for later overwrite error checking.
145 $form['changed'] = array(
146 '#type' => 'hidden',
147 '#default_value' => isset($node->changed) ? $node->changed : NULL,
148 );
149 // Get the node-specific bits.
150 if ($extra = node_invoke($node, 'form', $form_state)) {
151 $form = array_merge_recursive($form, $extra);
152 }
153
154 $form['#node'] = $node;
155
156 $form['additional_settings'] = array(
157 '#type' => 'vertical_tabs',
158 '#weight' => 99,
159 );
160
161 // Add a log field if the "Create new revision" option is checked, or if the
162 // current user has the ability to check that option.
163 if (!empty($node->revision) || user_access('administer nodes')) {
164 $form['revision_information'] = array(
165 '#type' => 'fieldset',
166 '#title' => t('Revision information'),
167 '#collapsible' => TRUE,
168 // Collapsed by default when "Create new revision" is unchecked
169 '#collapsed' => !$node->revision,
170 '#group' => 'additional_settings',
171 '#attached' => array(
172 'js' => array(drupal_get_path('module', 'node') . '/node.js'),
173 ),
174 '#weight' => 20,
175 );
176 $form['revision_information']['revision'] = array(
177 '#access' => user_access('administer nodes'),
178 '#type' => 'checkbox',
179 '#title' => t('Create new revision'),
180 '#default_value' => $node->revision,
181 '#states' => array(
182 // Check the revision log checkbox when the log textarea is filled in.
183 'checked' => array(
184 'textarea[name="log"]' => array('empty' => FALSE),
185 ),
186 ),
187 );
188 $form['revision_information']['log'] = array(
189 '#type' => 'textarea',
190 '#title' => t('Revision log message'),
191 '#rows' => 4,
192 '#default_value' => !empty($node->log) ? $node->log : '',
193 '#description' => t('Provide an explanation of the changes you are making. This will help other authors understand your motivations.'),
194 );
195 }
196
197 // Node author information for administrators
198 $form['author'] = array(
199 '#type' => 'fieldset',
200 '#access' => user_access('administer nodes'),
201 '#title' => t('Authoring information'),
202 '#collapsible' => TRUE,
203 '#collapsed' => TRUE,
204 '#group' => 'additional_settings',
205 '#attached' => array(
206 'js' => array(drupal_get_path('module', 'node') . '/node.js'),
207 ),
208 '#weight' => 90,
209 );
210 $form['author']['name'] = array(
211 '#type' => 'textfield',
212 '#title' => t('Authored by'),
213 '#maxlength' => 60,
214 '#autocomplete_path' => 'user/autocomplete',
215 '#default_value' => !empty($node->name) ? $node->name : '',
216 '#weight' => -1,
217 '#description' => t('Leave blank for %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous')))),
218 );
219 $form['author']['date'] = array(
220 '#type' => 'textfield',
221 '#title' => t('Authored on'),
222 '#maxlength' => 25,
223 '#description' => t('Format: %time. The date format is YYYY-MM-DD and %timezone is the timezone offset from UTC. 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'), '%timezone' => !empty($node->date) ? $node->date : format_date($node->created, 'custom', 'O'))),
224 );
225
226 if (isset($node->date)) {
227 $form['author']['date']['#default_value'] = $node->date;
228 }
229
230 // Node options for administrators
231 $form['options'] = array(
232 '#type' => 'fieldset',
233 '#access' => user_access('administer nodes'),
234 '#title' => t('Publishing options'),
235 '#collapsible' => TRUE,
236 '#collapsed' => TRUE,
237 '#group' => 'additional_settings',
238 '#attached' => array(
239 'js' => array(drupal_get_path('module', 'node') . '/node.js'),
240 ),
241 '#weight' => 95,
242 );
243 $form['options']['status'] = array(
244 '#type' => 'checkbox',
245 '#title' => t('Published'),
246 '#default_value' => $node->status,
247 );
248 $form['options']['promote'] = array(
249 '#type' => 'checkbox',
250 '#title' => t('Promoted to front page'),
251 '#default_value' => $node->promote,
252 );
253 $form['options']['sticky'] = array(
254 '#type' => 'checkbox',
255 '#title' => t('Sticky at top of lists'),
256 '#default_value' => $node->sticky,
257 );
258
259 // These values are used when the user has no administrator access.
260 foreach (array('uid', 'created') as $key) {
261 $form[$key] = array(
262 '#type' => 'value',
263 '#value' => $node->$key,
264 );
265 }
266
267 // Add the buttons.
268 $form['buttons'] = array();
269 $form['buttons']['#weight'] = 100;
270 $form['buttons']['submit'] = array(
271 '#type' => 'submit',
272 '#access' => variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview'])),
273 '#value' => t('Save'),
274 '#weight' => 5,
275 '#submit' => array('node_form_submit'),
276 );
277 $form['buttons']['preview'] = array(
278 '#access' => variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_DISABLED,
279 '#type' => 'submit',
280 '#value' => t('Preview'),
281 '#weight' => 10,
282 '#submit' => array('node_form_build_preview'),
283 );
284 if (!empty($node->nid) && node_access('delete', $node)) {
285 $form['buttons']['delete'] = array(
286 '#type' => 'submit',
287 '#value' => t('Delete'),
288 '#weight' => 15,
289 '#submit' => array('node_form_delete_submit'),
290 );
291 }
292 $form['#validate'][] = 'node_form_validate';
293 $form['#theme'] = array($node->type . '_node_form', 'node_form');
294
295 $form['#builder_function'] = 'node_form_submit_build_node';
296 field_attach_form('node', $node, $form, $form_state, $node->language);
297
298 return $form;
299 }
300
301 /**
302 * Button submit function: handle the 'Delete' button on the node form.
303 */
304 function node_form_delete_submit($form, &$form_state) {
305 $destination = array();
306 if (isset($_GET['destination'])) {
307 $destination = drupal_get_destination();
308 unset($_GET['destination']);
309 }
310 $node = $form['#node'];
311 $form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination));
312 }
313
314
315 function node_form_build_preview($form, &$form_state) {
316 $node = node_form_submit_build_node($form, $form_state);
317 $form_state['node_preview'] = node_preview($node);
318 }
319
320 /**
321 * Present a node submission form.
322 *
323 * @ingroup themeable
324 */
325 function theme_node_form($variables) {
326 $form = $variables['form'];
327
328 $output = "\n<div class=\"node-form\">\n";
329
330 $output .= " <div class=\"standard\">\n";
331 $output .= drupal_render_children($form);
332 $output .= " </div>\n";
333
334 $output .= "</div>\n";
335
336 return $output;
337 }
338
339 /**
340 * Generate a node preview.
341 */
342 function node_preview(stdClass $node) {
343 if (node_access('create', $node) || node_access('update', $node)) {
344 _field_invoke_multiple('load', 'node', array($node->nid => $node));
345 // Load the user's name when needed.
346 if (isset($node->name)) {
347 // The use of isset() is mandatory in the context of user IDs, because
348 // user ID 0 denotes the anonymous user.
349 if ($user = user_load_by_name($node->name)) {
350 $node->uid = $user->uid;
351 $node->picture = $user->picture;
352 }
353 else {
354 $node->uid = 0; // anonymous user
355 }
356 }
357 elseif ($node->uid) {
358 $user = user_load($node->uid);
359 $node->name = $user->name;
360 $node->picture = $user->picture;
361 }
362
363 $node->changed = REQUEST_TIME;
364 $nodes = array($node->nid => $node);
365 field_attach_prepare_view('node', $nodes, 'full');
366
367 // Display a preview of the node.
368 // Previewing alters $node so it needs to be cloned.
369 if (!form_get_errors()) {
370 $cloned_node = clone $node;
371 $cloned_node->in_preview = TRUE;
372 $output = theme('node_preview', array('node' => $cloned_node));
373 }
374 drupal_set_title(t('Preview'), PASS_THROUGH);
375
376 return $output;
377 }
378 }
379
380 /**
381 * Display a node preview for display during node creation and editing.
382 *
383 * @param $variables
384 * An associative array containing:
385 * - node: The node object which is being previewed.
386 *
387 * @ingroup themeable
388 */
389 function theme_node_preview($variables) {
390 $node = $variables['node'];
391
392 $output = '<div class="preview">';
393
394 $preview_trimmed_version = FALSE;
395
396 $trimmed = drupal_render(node_build(clone $node, 'teaser'));
397 $full = drupal_render(node_build($node, 'full'));
398
399 // Do we need to preview trimmed version of post as well as full version?
400 if ($trimmed != $full) {
401 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>'));
402 $output .= '<h3>' . t('Preview trimmed version') . '</h3>';
403 $output .= $trimmed;
404 $output .= '<h3>' . t('Preview full version') . '</h3>';
405 $output .= $full;
406 }
407 else {
408 $output .= $full;
409 }
410 $output .= "</div>\n";
411
412 return $output;
413 }
414
415 function node_form_submit($form, &$form_state) {
416 $node = node_form_submit_build_node($form, $form_state);
417 $insert = empty($node->nid);
418 node_save($node);
419 $node_link = l(t('view'), 'node/' . $node->nid);
420 $watchdog_args = array('@type' => $node->type, '%title' => $node->title[FIELD_LANGUAGE_NONE][0]['value']);
421 $t_args = array('@type' => node_type_get_name($node), '%title' => $node->title[FIELD_LANGUAGE_NONE][0]['value']);
422
423 if ($insert) {
424 watchdog('content', '@type: added %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link);
425 drupal_set_message(t('@type %title has been created.', $t_args));
426 }
427 else {
428 watchdog('content', '@type: updated %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link);
429 drupal_set_message(t('@type %title has been updated.', $t_args));
430 }
431 if ($node->nid) {
432 unset($form_state['rebuild']);
433 $form_state['nid'] = $node->nid;
434 $form_state['redirect'] = 'node/' . $node->nid;
435 }
436 else {
437 // In the unlikely case something went wrong on save, the node will be
438 // rebuilt and node form redisplayed the same way as in preview.
439 drupal_set_message(t('The post could not be saved.'), 'error');
440 }
441 }
442
443 /**
444 * Build a node by processing submitted form values and prepare for a form rebuild.
445 */
446 function node_form_submit_build_node($form, &$form_state) {
447 // Unset any button-level handlers, execute all the form-level submit
448 // functions to process the form values into an updated node.
449 unset($form_state['submit_handlers']);
450 form_execute_handlers('submit', $form, $form_state);
451 $node = node_submit((object)$form_state['values']);
452
453 field_attach_submit('node', $node, $form, $form_state);
454
455 $form_state['node'] = (array)$node;
456 $form_state['rebuild'] = TRUE;
457 return $node;
458 }
459
460 /**
461 * Menu callback -- ask for confirmation of node deletion
462 */
463 function node_delete_confirm($form, &$form_state, stdClass $node) {
464 $form['nid'] = array(
465 '#type' => 'value',
466 '#value' => $node->nid,
467 );
468
469 return confirm_form($form,
470 t('Are you sure you want to delete %title?', array('%title' => $node->title[FIELD_LANGUAGE_NONE][0]['value'])),
471 'node/' . $node->nid,
472 t('This action cannot be undone.'),
473 t('Delete'),
474 t('Cancel')
475 );
476 }
477
478 /**
479 * Execute node deletion
480 */
481 function node_delete_confirm_submit($form, &$form_state) {
482 if ($form_state['values']['confirm']) {
483 $node = node_load($form_state['values']['nid']);
484 node_delete($form_state['values']['nid']);
485 watchdog('content', '@type: deleted %title.', array('@type' => $node->type, '%title' => $node->title[FIELD_LANGUAGE_NONE][0]['value']));
486 drupal_set_message(t('@type %title has been deleted.', array('@type' => node_type_get_name($node), '%title' => $node->title[FIELD_LANGUAGE_NONE][0]['value'])));
487 }
488
489 $form_state['redirect'] = '<front>';
490 }
491
492 /**
493 * Generate an overview table of older revisions of a node.
494 */
495 function node_revision_overview(stdClass $node) {
496 drupal_set_title(t('Revisions for %title', array('%title' => $node->title[FIELD_LANGUAGE_NONE][0]['value'])), PASS_THROUGH);
497
498 $header = array(t('Revision'), array('data' => t('Operations'), 'colspan' => 2));
499
500 $revisions = node_revision_list($node);
501
502 $rows = array();
503 $revert_permission = FALSE;
504 if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
505 $revert_permission = TRUE;
506 }
507 $delete_permission = FALSE;
508 if ((user_access('delete revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
509 $delete_permission = TRUE;
510 }
511 foreach ($revisions as $revision) {
512 $row = array();
513 $operations = array();
514
515 if ($revision->current_vid > 0) {
516 $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'short'), "node/$node->nid"), '!username' => theme('username', array('account' => $revision))))
517 . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : ''),
518 'class' => array('revision-current'));
519 $operations[] = array('data' => theme('placeholder', array('text' => t('current revision'))), 'class' => array('revision-current'), 'colspan' => 2);
520 }
521 else {
522 $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))))
523 . (($revision->log != '') ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : '');
524 if ($revert_permission) {
525 $operations[] = l(t('revert'), "node/$node->nid/revisions/$revision->vid/revert");
526 }
527 if ($delete_permission) {
528 $operations[] = l(t('delete'), "node/$node->nid/revisions/$revision->vid/delete");
529 }
530 }
531 $rows[] = array_merge($row, $operations);
532 }
533
534 $build['node_revisions_table'] = array(
535 '#theme' => 'table',
536 '#rows' => $rows,
537 '#header' => $header,
538 );
539
540 return $build;
541 }
542
543 /**
544 * Ask for confirmation of the reversion to prevent against CSRF attacks.
545 */
546 function node_revision_revert_confirm($form, $form_state, $node_revision) {
547 $form['#node_revision'] = $node_revision;
548 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'));
549 }
550
551 function node_revision_revert_confirm_submit($form, &$form_state) {
552 $node_revision = $form['#node_revision'];
553 $node_revision->revision = 1;
554 $node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($node_revision->revision_timestamp)));
555
556 node_save($node_revision);
557
558 watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title[FIELD_LANGUAGE_NONE][0]['value'], '%revision' => $node_revision->vid));
559 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->title[FIELD_LANGUAGE_NONE][0]['value'], '%revision-date' => format_date($node_revision->revision_timestamp))));
560 $form_state['redirect'] = 'node/' . $node_revision->nid . '/revisions';
561 }
562
563 function node_revision_delete_confirm($form, $form_state, $node_revision) {
564 $form['#node_revision'] = $node_revision;
565 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'));
566 }
567
568 function node_revision_delete_confirm_submit($form, &$form_state) {
569 $node_revision = $form['#node_revision'];
570 node_revision_delete($node_revision->vid);
571
572 watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title[FIELD_LANGUAGE_NONE][0]['value'], '%revision' => $node_revision->vid));
573 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->title[FIELD_LANGUAGE_NONE][0]['value'])));
574 $form_state['redirect'] = 'node/' . $node_revision->nid;
575 if (db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid', array(':nid' => $node_revision->nid))->fetchField() > 1) {
576 $form_state['redirect'] .= '/revisions';
577 }
578 }

  ViewVC Help
Powered by ViewVC 1.1.2