Initial code using Drupal 6.38
This commit is contained in:
commit
4824608a33
467 changed files with 90887 additions and 0 deletions
410
modules/node/content_types.inc
Normal file
410
modules/node/content_types.inc
Normal file
|
@ -0,0 +1,410 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Content type editing UI.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Displays the content type admin overview page.
|
||||
*/
|
||||
function node_overview_types() {
|
||||
$types = node_get_types();
|
||||
$names = node_get_types('names');
|
||||
$header = array(t('Name'), t('Type'), t('Description'), array('data' => t('Operations'), 'colspan' => '2'));
|
||||
$rows = array();
|
||||
|
||||
foreach ($names as $key => $name) {
|
||||
$type = $types[$key];
|
||||
if (node_hook($type, 'form')) {
|
||||
$type_url_str = str_replace('_', '-', $type->type);
|
||||
$row = array(
|
||||
l($name, 'admin/content/node-type/'. $type_url_str),
|
||||
check_plain($type->type),
|
||||
filter_xss_admin($type->description),
|
||||
);
|
||||
// Set the edit column.
|
||||
$row[] = array('data' => l(t('edit'), 'admin/content/node-type/'. $type_url_str));
|
||||
|
||||
// Set the delete column.
|
||||
if ($type->custom) {
|
||||
$row[] = array('data' => l(t('delete'), 'admin/content/node-type/'. $type_url_str .'/delete'));
|
||||
}
|
||||
else {
|
||||
$row[] = array('data' => '');
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($rows)) {
|
||||
$rows[] = array(array('data' => t('No content types available.'), 'colspan' => '5', 'class' => 'message'));
|
||||
}
|
||||
|
||||
return theme('table', $header, $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the node type editing form.
|
||||
*/
|
||||
function node_type_form(&$form_state, $type = NULL) {
|
||||
if (!isset($type->type)) {
|
||||
$type = new stdClass();
|
||||
$type->type = $type->name = $type->module = $type->description = $type->help = '';
|
||||
$type->min_word_count = 0;
|
||||
$type->has_title = TRUE;
|
||||
$type->has_body = TRUE;
|
||||
$type->title_label = t('Title');
|
||||
$type->body_label = t('Body');
|
||||
$type->custom = TRUE;
|
||||
$type->modified = FALSE;
|
||||
$type->locked = FALSE;
|
||||
}
|
||||
|
||||
$form['#node_type'] = $type; // Make the type object available to implementations of hook_form_alter.
|
||||
|
||||
$form['identity'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Identification'),
|
||||
);
|
||||
$form['identity']['name'] = array(
|
||||
'#title' => t('Name'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $type->name,
|
||||
'#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>create content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and <strong>spaces</strong>. This name must be unique.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
if (!$type->locked) {
|
||||
$form['identity']['type'] = array(
|
||||
'#title' => t('Type'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $type->type,
|
||||
'#maxlength' => 32,
|
||||
'#required' => TRUE,
|
||||
'#description' => t('The machine-readable name of this content type. This text will be used for constructing the URL of the <em>create content</em> page for this content type. This name must contain only lowercase letters, numbers, and underscores. Underscores will be converted into hyphens when constructing the URL of the <em>create content</em> page. This name must be unique.'),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['identity']['type'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $type->type,
|
||||
);
|
||||
$form['identity']['type_display'] = array(
|
||||
'#title' => t('Type'),
|
||||
'#type' => 'item',
|
||||
'#value' => theme('placeholder', $type->type),
|
||||
'#description' => t('The machine-readable name of this content type. This field cannot be modified for system-defined content types.'),
|
||||
);
|
||||
}
|
||||
|
||||
$form['identity']['description'] = array(
|
||||
'#title' => t('Description'),
|
||||
'#type' => 'textarea',
|
||||
'#default_value' => $type->description,
|
||||
'#description' => t('A brief description of this content type. This text will be displayed as part of the list on the <em>create content</em> page.'),
|
||||
);
|
||||
|
||||
$form['submission'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Submission form settings'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
);
|
||||
$form['submission']['title_label'] = array(
|
||||
'#title' => t('Title field label'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $type->title_label,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
if (!$type->has_title) {
|
||||
// Avoid overwriting a content type that intentionally does not have a
|
||||
// title field.
|
||||
$form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
|
||||
$form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
|
||||
$form['submission']['title_label']['#required'] = FALSE;
|
||||
}
|
||||
$form['submission']['body_label'] = array(
|
||||
'#title' => t('Body field label'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => isset($type->body_label) ? $type->body_label : '',
|
||||
'#description' => t('To omit the body field for this content type, remove any text and leave this field blank.'),
|
||||
);
|
||||
$form['submission']['min_word_count'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Minimum number of words'),
|
||||
'#default_value' => $type->min_word_count,
|
||||
'#options' => drupal_map_assoc(array(0, 1, 10, 25, 50, 75, 100, 125, 150, 175, 200)),
|
||||
'#description' => t('The minimum number of words for the body field to be considered valid for this content type. This can be useful to rule out submissions that do not meet the site\'s standards, such as short test posts.')
|
||||
);
|
||||
$form['submission']['help'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Explanation or submission guidelines'),
|
||||
'#default_value' => $type->help,
|
||||
'#description' => t('This text will be displayed at the top of the submission form for this content type. It is useful for helping or instructing your users.')
|
||||
);
|
||||
$form['workflow'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Workflow settings'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
);
|
||||
$form['workflow']['node_options'] = array('#type' => 'checkboxes',
|
||||
'#title' => t('Default options'),
|
||||
'#default_value' => variable_get('node_options_'. $type->type, array('status', 'promote')),
|
||||
'#options' => array(
|
||||
'status' => t('Published'),
|
||||
'promote' => t('Promoted to front page'),
|
||||
'sticky' => t('Sticky at top of lists'),
|
||||
'revision' => t('Create new revision'),
|
||||
),
|
||||
'#description' => t('Users with the <em>administer nodes</em> permission will be able to override these options.'),
|
||||
);
|
||||
|
||||
$form['old_type'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $type->type,
|
||||
);
|
||||
$form['orig_type'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => isset($type->orig_type) ? $type->orig_type : '',
|
||||
);
|
||||
$form['module'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $type->module,
|
||||
);
|
||||
$form['custom'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $type->custom,
|
||||
);
|
||||
$form['modified'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $type->modified,
|
||||
);
|
||||
$form['locked'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $type->locked,
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save content type'),
|
||||
'#weight' => 40,
|
||||
);
|
||||
|
||||
if ($type->custom) {
|
||||
if (!empty($type->type)) {
|
||||
$form['delete'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Delete content type'),
|
||||
'#weight' => 45,
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form['reset'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Reset to defaults'),
|
||||
'#weight' => 50,
|
||||
);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the content type submission form generated by node_type_form().
|
||||
*/
|
||||
function node_type_form_validate($form, &$form_state) {
|
||||
$type = new stdClass();
|
||||
$type->type = trim($form_state['values']['type']);
|
||||
$type->name = trim($form_state['values']['name']);
|
||||
|
||||
// Work out what the type was before the user submitted this form
|
||||
$old_type = trim($form_state['values']['old_type']);
|
||||
|
||||
$types = node_get_types('names');
|
||||
|
||||
if (!$form_state['values']['locked']) {
|
||||
if (isset($types[$type->type]) && $type->type != $old_type) {
|
||||
form_set_error('type', t('The machine-readable name %type is already taken.', array('%type' => $type->type)));
|
||||
}
|
||||
if (!preg_match('!^[a-z0-9_]+$!', $type->type)) {
|
||||
form_set_error('type', t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
|
||||
}
|
||||
// 'theme' conflicts with theme_node_form().
|
||||
// '0' is invalid, since elsewhere we check it using empty().
|
||||
if (in_array($type->type, array('0', 'theme'))) {
|
||||
form_set_error('type', t("Invalid machine-readable name. Please enter a name other than %invalid.", array('%invalid' => $type->type)));
|
||||
}
|
||||
}
|
||||
|
||||
$names = array_flip($types);
|
||||
|
||||
if (isset($names[$type->name]) && $names[$type->name] != $old_type) {
|
||||
form_set_error('name', t('The human-readable name %name is already taken.', array('%name' => $type->name)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_form_submit().
|
||||
*/
|
||||
function node_type_form_submit($form, &$form_state) {
|
||||
$op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
|
||||
|
||||
$type = new stdClass();
|
||||
|
||||
$type->type = trim($form_state['values']['type']);
|
||||
$type->name = trim($form_state['values']['name']);
|
||||
$type->orig_type = trim($form_state['values']['orig_type']);
|
||||
$type->old_type = isset($form_state['values']['old_type']) ? $form_state['values']['old_type'] : $type->type;
|
||||
|
||||
$type->description = $form_state['values']['description'];
|
||||
$type->help = $form_state['values']['help'];
|
||||
$type->min_word_count = $form_state['values']['min_word_count'];
|
||||
$type->title_label = $form_state['values']['title_label'];
|
||||
$type->body_label = $form_state['values']['body_label'];
|
||||
|
||||
// title_label is required in core; has_title will always be true, unless a
|
||||
// module alters the title field.
|
||||
$type->has_title = ($type->title_label != '');
|
||||
$type->has_body = ($type->body_label != '');
|
||||
|
||||
$type->module = !empty($form_state['values']['module']) ? $form_state['values']['module'] : 'node';
|
||||
$type->custom = $form_state['values']['custom'];
|
||||
$type->modified = TRUE;
|
||||
$type->locked = $form_state['values']['locked'];
|
||||
|
||||
if ($op == t('Reset to defaults')) {
|
||||
node_type_reset($type);
|
||||
}
|
||||
elseif ($op == t('Delete content type')) {
|
||||
$form_state['redirect'] = 'admin/content/node-type/'. str_replace('_', '-', $type->old_type) .'/delete';
|
||||
return;
|
||||
}
|
||||
|
||||
$status = node_type_save($type);
|
||||
|
||||
$variables = $form_state['values'];
|
||||
|
||||
// Remove everything that's been saved already - whatever's left is assumed
|
||||
// to be a persistent variable.
|
||||
foreach ($variables as $key => $value) {
|
||||
if (isset($type->$key)) {
|
||||
unset($variables[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
unset($variables['form_token'], $variables['op'], $variables['submit'], $variables['delete'], $variables['reset'], $variables['form_id']);
|
||||
|
||||
// Save or reset persistent variable values.
|
||||
foreach ($variables as $key => $value) {
|
||||
$variable_new = $key .'_'. $type->type;
|
||||
$variable_old = $key .'_'. $type->old_type;
|
||||
|
||||
if ($op == t('Reset to defaults')) {
|
||||
variable_del($variable_old);
|
||||
}
|
||||
else {
|
||||
if (is_array($value)) {
|
||||
$value = array_keys(array_filter($value));
|
||||
}
|
||||
variable_set($variable_new, $value);
|
||||
|
||||
if ($variable_new != $variable_old) {
|
||||
variable_del($variable_old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node_types_rebuild();
|
||||
menu_rebuild();
|
||||
$t_args = array('%name' => $type->name);
|
||||
|
||||
if ($op == t('Reset to defaults')) {
|
||||
drupal_set_message(t('The content type %name has been reset to its default values.', $t_args));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($status == SAVED_UPDATED) {
|
||||
drupal_set_message(t('The content type %name has been updated.', $t_args));
|
||||
}
|
||||
elseif ($status == SAVED_NEW) {
|
||||
drupal_set_message(t('The content type %name has been added.', $t_args));
|
||||
watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE, l(t('view'), 'admin/content/types'));
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'admin/content/types';
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_node_type().
|
||||
*/
|
||||
function node_node_type($op, $info) {
|
||||
if ($op != 'delete' && !empty($info->old_type) && $info->old_type != $info->type) {
|
||||
$update_count = node_type_update_nodes($info->old_type, $info->type);
|
||||
|
||||
if ($update_count) {
|
||||
drupal_set_message(format_plural($update_count, 'Changed the content type of 1 post from %old-type to %type.', 'Changed the content type of @count posts from %old-type to %type.', array('%old-type' => $info->old_type, '%type' => $info->type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all of the relevant fields of a module-defined node type to their
|
||||
* default values.
|
||||
*
|
||||
* @param &$type
|
||||
* The node type to reset. The node type is passed back by reference with its
|
||||
* resetted values. If there is no module-defined info for this node type,
|
||||
* then nothing happens.
|
||||
*/
|
||||
function node_type_reset(&$type) {
|
||||
$info_array = module_invoke_all('node_info');
|
||||
if (isset($info_array[$type->orig_type])) {
|
||||
$info_array[$type->orig_type]['type'] = $type->orig_type;
|
||||
$info = _node_type_set_defaults($info_array[$type->orig_type]);
|
||||
|
||||
foreach ($info as $field => $value) {
|
||||
$type->$field = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; delete a single content type.
|
||||
*/
|
||||
function node_type_delete_confirm(&$form_state, $type) {
|
||||
$form['type'] = array('#type' => 'value', '#value' => $type->type);
|
||||
$form['name'] = array('#type' => 'value', '#value' => $type->name);
|
||||
|
||||
$message = t('Are you sure you want to delete the content type %type?', array('%type' => $type->name));
|
||||
$caption = '';
|
||||
|
||||
$num_nodes = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = '%s'", $type->type));
|
||||
if ($num_nodes) {
|
||||
$caption .= '<p>'. format_plural($num_nodes, '<strong>Warning:</strong> there is currently 1 %type post on your site. It may not be able to be displayed or edited correctly, once you have removed this content type.', '<strong>Warning:</strong> there are currently @count %type posts on your site. They may not be able to be displayed or edited correctly, once you have removed this content type.', array('%type' => $type->name)) .'</p>';
|
||||
}
|
||||
|
||||
$caption .= '<p>'. t('This action cannot be undone.') .'</p>';
|
||||
|
||||
return confirm_form($form, $message, 'admin/content/types', $caption, t('Delete'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process content type delete confirm submissions.
|
||||
*/
|
||||
function node_type_delete_confirm_submit($form, &$form_state) {
|
||||
node_type_delete($form_state['values']['type']);
|
||||
|
||||
$t_args = array('%name' => $form_state['values']['name']);
|
||||
drupal_set_message(t('The content type %name has been deleted.', $t_args));
|
||||
watchdog('menu', 'Deleted content type %name.', $t_args, WATCHDOG_NOTICE);
|
||||
|
||||
node_types_rebuild();
|
||||
menu_rebuild();
|
||||
|
||||
$form_state['redirect'] = 'admin/content/types';
|
||||
return;
|
||||
}
|
7
modules/node/node-rtl.css
Normal file
7
modules/node/node-rtl.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
#node-admin-buttons {
|
||||
float: right;
|
||||
margin-left: 0;
|
||||
margin-right: 0.5em;
|
||||
clear: left;
|
||||
}
|
625
modules/node/node.admin.inc
Normal file
625
modules/node/node.admin.inc
Normal file
|
@ -0,0 +1,625 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Content administration and module settings UI.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Menu callback; presents general node configuration options.
|
||||
*/
|
||||
function node_configure() {
|
||||
$status = '<p>'. t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Possible causes for permission problems are disabling modules or configuration changes to permissions. Rebuilding will remove all privileges to posts, and replace them with permissions based on the current modules and settings.') .'</p>';
|
||||
$status .= '<p>'. t('Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed posts will automatically use the new permissions.') .'</p>';
|
||||
|
||||
$form['access'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Node access status'),
|
||||
);
|
||||
$form['access']['status'] = array('#value' => $status);
|
||||
$form['access']['rebuild'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Rebuild permissions'),
|
||||
'#submit' => array('node_configure_access_submit'),
|
||||
);
|
||||
|
||||
$form['default_nodes_main'] = array(
|
||||
'#type' => 'select', '#title' => t('Number of posts on main page'), '#default_value' => variable_get('default_nodes_main', 10),
|
||||
'#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)),
|
||||
'#description' => t('The default maximum number of posts to display per page on overview pages such as the main page.')
|
||||
);
|
||||
$form['teaser_length'] = array(
|
||||
'#type' => 'select', '#title' => t('Length of trimmed posts'), '#default_value' => variable_get('teaser_length', 600),
|
||||
'#options' => array(
|
||||
0 => t('Unlimited'),
|
||||
200 => t('200 characters'),
|
||||
400 => t('400 characters'),
|
||||
600 => t('600 characters'),
|
||||
800 => t('800 characters'),
|
||||
1000 => t('1000 characters'),
|
||||
1200 => t('1200 characters'),
|
||||
1400 => t('1400 characters'),
|
||||
1600 => t('1600 characters'),
|
||||
1800 => t('1800 characters'),
|
||||
2000 => t('2000 characters'),
|
||||
),
|
||||
'#description' => t("The maximum number of characters used in the trimmed version of a post. Drupal will use this setting to determine at which offset long posts should be trimmed. The trimmed version of a post is typically used as a teaser when displaying the post on the main page, in XML feeds, etc. To disable teasers, set to 'Unlimited'. Note that this setting will only affect new or updated content and will not affect existing teasers.")
|
||||
);
|
||||
|
||||
$form['node_preview'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Preview post'),
|
||||
'#default_value' => variable_get('node_preview', 0),
|
||||
'#options' => array(t('Optional'), t('Required')),
|
||||
'#description' => t('Must users preview posts before submitting?'),
|
||||
);
|
||||
|
||||
return system_settings_form($form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form button submit callback.
|
||||
*/
|
||||
function node_configure_access_submit($form, &$form_state) {
|
||||
$form_state['redirect'] = 'admin/content/node-settings/rebuild';
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: confirm rebuilding of permissions.
|
||||
*/
|
||||
function node_configure_rebuild_confirm() {
|
||||
return confirm_form(array(), t('Are you sure you want to rebuild the permissions on site content?'),
|
||||
'admin/content/node-settings', t('This action rebuilds all permissions on site content, and may be a lengthy process. This action cannot be undone.'), t('Rebuild permissions'), t('Cancel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for wipe confirmation
|
||||
*/
|
||||
function node_configure_rebuild_confirm_submit($form, &$form_state) {
|
||||
node_access_rebuild(TRUE);
|
||||
$form_state['redirect'] = 'admin/content/node-settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_node_operations().
|
||||
*/
|
||||
function node_node_operations() {
|
||||
$operations = array(
|
||||
'publish' => array(
|
||||
'label' => t('Publish'),
|
||||
'callback' => 'node_mass_update',
|
||||
'callback arguments' => array('updates' => array('status' => 1)),
|
||||
),
|
||||
'unpublish' => array(
|
||||
'label' => t('Unpublish'),
|
||||
'callback' => 'node_mass_update',
|
||||
'callback arguments' => array('updates' => array('status' => 0)),
|
||||
),
|
||||
'promote' => array(
|
||||
'label' => t('Promote to front page'),
|
||||
'callback' => 'node_mass_update',
|
||||
'callback arguments' => array('updates' => array('status' => 1, 'promote' => 1)),
|
||||
),
|
||||
'demote' => array(
|
||||
'label' => t('Demote from front page'),
|
||||
'callback' => 'node_mass_update',
|
||||
'callback arguments' => array('updates' => array('promote' => 0)),
|
||||
),
|
||||
'sticky' => array(
|
||||
'label' => t('Make sticky'),
|
||||
'callback' => 'node_mass_update',
|
||||
'callback arguments' => array('updates' => array('status' => 1, 'sticky' => 1)),
|
||||
),
|
||||
'unsticky' => array(
|
||||
'label' => t('Remove stickiness'),
|
||||
'callback' => 'node_mass_update',
|
||||
'callback arguments' => array('updates' => array('sticky' => 0)),
|
||||
),
|
||||
'delete' => array(
|
||||
'label' => t('Delete'),
|
||||
'callback' => NULL,
|
||||
),
|
||||
);
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* List node administration filters that can be applied.
|
||||
*/
|
||||
function node_filters() {
|
||||
// Regular filters
|
||||
$filters['status'] = array(
|
||||
'title' => t('status'),
|
||||
'options' => array(
|
||||
'status-1' => t('published'),
|
||||
'status-0' => t('not published'),
|
||||
'promote-1' => t('promoted'),
|
||||
'promote-0' => t('not promoted'),
|
||||
'sticky-1' => t('sticky'),
|
||||
'sticky-0' => t('not sticky'),
|
||||
),
|
||||
);
|
||||
// Include translation states if we have this module enabled
|
||||
if (module_exists('translation')) {
|
||||
$filters['status']['options'] += array(
|
||||
'translate-0' => t('Up to date translation'),
|
||||
'translate-1' => t('Outdated translation'),
|
||||
);
|
||||
}
|
||||
|
||||
$filters['type'] = array('title' => t('type'), 'options' => node_get_types('names'));
|
||||
|
||||
// The taxonomy filter
|
||||
if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
|
||||
$filters['category'] = array('title' => t('category'), 'options' => $taxonomy);
|
||||
}
|
||||
// Language filter if there is a list of languages
|
||||
if ($languages = module_invoke('locale', 'language_list')) {
|
||||
$languages = array('' => t('Language neutral')) + $languages;
|
||||
$filters['language'] = array('title' => t('language'), 'options' => $languages);
|
||||
}
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build query for node administration filters based on session.
|
||||
*/
|
||||
function node_build_filter_query() {
|
||||
$filters = node_filters();
|
||||
|
||||
// Build query
|
||||
$where = $args = array();
|
||||
$join = '';
|
||||
foreach ($_SESSION['node_overview_filter'] as $index => $filter) {
|
||||
list($key, $value) = $filter;
|
||||
switch ($key) {
|
||||
case 'status':
|
||||
// Note: no exploitable hole as $key/$value have already been checked when submitted
|
||||
list($key, $value) = explode('-', $value, 2);
|
||||
$where[] = 'n.'. $key .' = %d';
|
||||
break;
|
||||
case 'category':
|
||||
$table = "tn$index";
|
||||
$where[] = "$table.tid = %d";
|
||||
$join .= "INNER JOIN {term_node} $table ON n.vid = $table.vid ";
|
||||
break;
|
||||
case 'type':
|
||||
$where[] = "n.type = '%s'";
|
||||
break;
|
||||
case 'language':
|
||||
$where[] = "n.language = '%s'";
|
||||
break;
|
||||
}
|
||||
$args[] = $value;
|
||||
}
|
||||
$where = count($where) ? 'WHERE '. implode(' AND ', $where) : '';
|
||||
|
||||
return array('where' => $where, 'join' => $join, 'args' => $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return form for node administration filters.
|
||||
*/
|
||||
function node_filter_form() {
|
||||
$session = &$_SESSION['node_overview_filter'];
|
||||
$session = is_array($session) ? $session : array();
|
||||
$filters = node_filters();
|
||||
|
||||
$i = 0;
|
||||
$form['filters'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Show only items where'),
|
||||
'#theme' => 'node_filters',
|
||||
);
|
||||
$form['#submit'][] = 'node_filter_form_submit';
|
||||
foreach ($session as $filter) {
|
||||
list($type, $value) = $filter;
|
||||
if ($type == 'category') {
|
||||
// Load term name from DB rather than search and parse options array.
|
||||
$value = module_invoke('taxonomy', 'get_term', $value);
|
||||
$value = $value->name;
|
||||
}
|
||||
else if ($type == 'language') {
|
||||
$value = empty($value) ? t('Language neutral') : module_invoke('locale', 'language_name', $value);
|
||||
}
|
||||
else {
|
||||
$value = $filters[$type]['options'][$value];
|
||||
}
|
||||
if ($i++) {
|
||||
$form['filters']['current'][] = array('#value' => t('<em>and</em> where <strong>%a</strong> is <strong>%b</strong>', array('%a' => $filters[$type]['title'], '%b' => $value)));
|
||||
}
|
||||
else {
|
||||
$form['filters']['current'][] = array('#value' => t('<strong>%a</strong> is <strong>%b</strong>', array('%a' => $filters[$type]['title'], '%b' => $value)));
|
||||
}
|
||||
if (in_array($type, array('type', 'language'))) {
|
||||
// Remove the option if it is already being filtered on.
|
||||
unset($filters[$type]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($filters as $key => $filter) {
|
||||
$names[$key] = $filter['title'];
|
||||
$form['filters']['status'][$key] = array('#type' => 'select', '#options' => $filter['options']);
|
||||
}
|
||||
|
||||
$form['filters']['filter'] = array('#type' => 'radios', '#options' => $names, '#default_value' => 'status');
|
||||
$form['filters']['buttons']['submit'] = array('#type' => 'submit', '#value' => (count($session) ? t('Refine') : t('Filter')));
|
||||
if (count($session)) {
|
||||
$form['filters']['buttons']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
|
||||
$form['filters']['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
|
||||
}
|
||||
|
||||
drupal_add_js('misc/form.js', 'core');
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme node administration filter form.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_node_filter_form($form) {
|
||||
$output = '';
|
||||
$output .= '<div id="node-admin-filter">';
|
||||
$output .= drupal_render($form['filters']);
|
||||
$output .= '</div>';
|
||||
$output .= drupal_render($form);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme node administration filter selector.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_node_filters($form) {
|
||||
$output = '';
|
||||
$output .= '<ul class="clear-block">';
|
||||
if (!empty($form['current'])) {
|
||||
foreach (element_children($form['current']) as $key) {
|
||||
$output .= '<li>'. drupal_render($form['current'][$key]) .'</li>';
|
||||
}
|
||||
}
|
||||
|
||||
$output .= '<li><dl class="multiselect">'. (!empty($form['current']) ? '<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' : '') .'<dd class="a">';
|
||||
foreach (element_children($form['filter']) as $key) {
|
||||
$output .= drupal_render($form['filter'][$key]);
|
||||
}
|
||||
$output .= '</dd>';
|
||||
|
||||
$output .= '<dt>'. t('is') .'</dt><dd class="b">';
|
||||
|
||||
foreach (element_children($form['status']) as $key) {
|
||||
$output .= drupal_render($form['status'][$key]);
|
||||
}
|
||||
$output .= '</dd>';
|
||||
|
||||
$output .= '</dl>';
|
||||
$output .= '<div class="container-inline" id="node-admin-buttons">'. drupal_render($form['buttons']) .'</div>';
|
||||
$output .= '</li></ul>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process result from node administration filter form.
|
||||
*/
|
||||
function node_filter_form_submit($form, &$form_state) {
|
||||
$filters = node_filters();
|
||||
switch ($form_state['values']['op']) {
|
||||
case t('Filter'):
|
||||
case t('Refine'):
|
||||
if (isset($form_state['values']['filter'])) {
|
||||
$filter = $form_state['values']['filter'];
|
||||
|
||||
// Flatten the options array to accommodate hierarchical/nested options.
|
||||
$flat_options = form_options_flatten($filters[$filter]['options']);
|
||||
|
||||
if (isset($flat_options[$form_state['values'][$filter]])) {
|
||||
$_SESSION['node_overview_filter'][] = array($filter, $form_state['values'][$filter]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case t('Undo'):
|
||||
array_pop($_SESSION['node_overview_filter']);
|
||||
break;
|
||||
case t('Reset'):
|
||||
$_SESSION['node_overview_filter'] = array();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make mass update of nodes, changing all nodes in the $nodes array
|
||||
* to update them with the field values in $updates.
|
||||
*
|
||||
* IMPORTANT NOTE: This function is intended to work when called
|
||||
* from a form submit handler. Calling it outside of the form submission
|
||||
* process may not work correctly.
|
||||
*
|
||||
* @param array $nodes
|
||||
* Array of node nids to update.
|
||||
* @param array $updates
|
||||
* Array of key/value pairs with node field names and the
|
||||
* value to update that field to.
|
||||
*/
|
||||
function node_mass_update($nodes, $updates) {
|
||||
// We use batch processing to prevent timeout when updating a large number
|
||||
// of nodes.
|
||||
if (count($nodes) > 10) {
|
||||
$batch = array(
|
||||
'operations' => array(
|
||||
array('_node_mass_update_batch_process', array($nodes, $updates))
|
||||
),
|
||||
'finished' => '_node_mass_update_batch_finished',
|
||||
'title' => t('Processing'),
|
||||
// We use a single multi-pass operation, so the default
|
||||
// 'Remaining x of y operations' message will be confusing here.
|
||||
'progress_message' => '',
|
||||
'error_message' => t('The update has encountered an error.'),
|
||||
// The operations do not live in the .module file, so we need to
|
||||
// tell the batch engine which file to load before calling them.
|
||||
'file' => drupal_get_path('module', 'node') .'/node.admin.inc',
|
||||
);
|
||||
batch_set($batch);
|
||||
}
|
||||
else {
|
||||
foreach ($nodes as $nid) {
|
||||
_node_mass_update_helper($nid, $updates);
|
||||
}
|
||||
drupal_set_message(t('The update has been performed.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node Mass Update - helper function.
|
||||
*/
|
||||
function _node_mass_update_helper($nid, $updates) {
|
||||
$node = node_load($nid, NULL, TRUE);
|
||||
foreach ($updates as $name => $value) {
|
||||
$node->$name = $value;
|
||||
}
|
||||
node_save($node);
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Node Mass Update Batch operation
|
||||
*/
|
||||
function _node_mass_update_batch_process($nodes, $updates, &$context) {
|
||||
if (!isset($context['sandbox']['progress'])) {
|
||||
$context['sandbox']['progress'] = 0;
|
||||
$context['sandbox']['max'] = count($nodes);
|
||||
$context['sandbox']['nodes'] = $nodes;
|
||||
}
|
||||
|
||||
// Process nodes by groups of 5.
|
||||
$count = min(5, count($context['sandbox']['nodes']));
|
||||
for ($i = 1; $i <= $count; $i++) {
|
||||
// For each nid, load the node, reset the values, and save it.
|
||||
$nid = array_shift($context['sandbox']['nodes']);
|
||||
$node = _node_mass_update_helper($nid, $updates);
|
||||
|
||||
// Store result for post-processing in the finished callback.
|
||||
$context['results'][] = l($node->title, 'node/'. $node->nid);
|
||||
|
||||
// Update our progress information.
|
||||
$context['sandbox']['progress']++;
|
||||
}
|
||||
|
||||
// Inform the batch engine that we are not finished,
|
||||
// and provide an estimation of the completion level we reached.
|
||||
if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
|
||||
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node Mass Update Batch 'finished' callback.
|
||||
*/
|
||||
function _node_mass_update_batch_finished($success, $results, $operations) {
|
||||
if ($success) {
|
||||
drupal_set_message(t('The update has been performed.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
|
||||
$message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
|
||||
$message .= theme('item_list', $results);
|
||||
drupal_set_message($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: content administration.
|
||||
*/
|
||||
function node_admin_content($form_state) {
|
||||
if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
|
||||
return node_multiple_delete_confirm($form_state, array_filter($form_state['values']['nodes']));
|
||||
}
|
||||
$form = node_filter_form();
|
||||
|
||||
$form['#theme'] = 'node_filter_form';
|
||||
$form['admin'] = node_admin_nodes();
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder: Builds the node administration overview.
|
||||
*/
|
||||
function node_admin_nodes() {
|
||||
|
||||
$filter = node_build_filter_query();
|
||||
|
||||
$result = pager_query(db_rewrite_sql('SELECT n.*, u.name FROM {node} n '. $filter['join'] .' INNER JOIN {users} u ON n.uid = u.uid '. $filter['where'] .' ORDER BY n.changed DESC'), 50, 0, NULL, $filter['args']);
|
||||
|
||||
// Enable language column if locale is enabled or if we have any node with language
|
||||
$count = db_result(db_query("SELECT COUNT(*) FROM {node} n WHERE language != ''"));
|
||||
$multilanguage = (module_exists('locale') || $count);
|
||||
|
||||
$form['options'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Update options'),
|
||||
'#prefix' => '<div class="container-inline">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
$options = array();
|
||||
foreach (module_invoke_all('node_operations') as $operation => $array) {
|
||||
$options[$operation] = $array['label'];
|
||||
}
|
||||
$form['options']['operation'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
'#default_value' => 'approve',
|
||||
);
|
||||
$form['options']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Update'),
|
||||
'#submit' => array('node_admin_nodes_submit'),
|
||||
);
|
||||
|
||||
$languages = language_list();
|
||||
$destination = drupal_get_destination();
|
||||
$nodes = array();
|
||||
while ($node = db_fetch_object($result)) {
|
||||
$nodes[$node->nid] = '';
|
||||
$options = empty($node->language) ? array() : array('language' => $languages[$node->language]);
|
||||
$form['title'][$node->nid] = array('#value' => l($node->title, 'node/'. $node->nid, $options) .' '. theme('mark', node_mark($node->nid, $node->changed)));
|
||||
$form['name'][$node->nid] = array('#value' => check_plain(node_get_types('name', $node)));
|
||||
$form['username'][$node->nid] = array('#value' => theme('username', $node));
|
||||
$form['status'][$node->nid] = array('#value' => ($node->status ? t('published') : t('not published')));
|
||||
if ($multilanguage) {
|
||||
$form['language'][$node->nid] = array('#value' => empty($node->language) ? t('Language neutral') : t($languages[$node->language]->name));
|
||||
}
|
||||
$form['operations'][$node->nid] = array('#value' => l(t('edit'), 'node/'. $node->nid .'/edit', array('query' => $destination)));
|
||||
}
|
||||
$form['nodes'] = array('#type' => 'checkboxes', '#options' => $nodes);
|
||||
$form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
|
||||
$form['#theme'] = 'node_admin_nodes';
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate node_admin_nodes form submissions.
|
||||
*
|
||||
* Check if any nodes have been selected to perform the chosen
|
||||
* 'Update option' on.
|
||||
*/
|
||||
function node_admin_nodes_validate($form, &$form_state) {
|
||||
$nodes = array_filter($form_state['values']['nodes']);
|
||||
if (count($nodes) == 0) {
|
||||
form_set_error('', t('No items selected.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process node_admin_nodes form submissions.
|
||||
*
|
||||
* Execute the chosen 'Update option' on the selected nodes.
|
||||
*/
|
||||
function node_admin_nodes_submit($form, &$form_state) {
|
||||
$operations = module_invoke_all('node_operations');
|
||||
$operation = $operations[$form_state['values']['operation']];
|
||||
// Filter out unchecked nodes
|
||||
$nodes = array_filter($form_state['values']['nodes']);
|
||||
if ($function = $operation['callback']) {
|
||||
// Add in callback arguments if present.
|
||||
if (isset($operation['callback arguments'])) {
|
||||
$args = array_merge(array($nodes), $operation['callback arguments']);
|
||||
}
|
||||
else {
|
||||
$args = array($nodes);
|
||||
}
|
||||
call_user_func_array($function, $args);
|
||||
|
||||
cache_clear_all();
|
||||
}
|
||||
else {
|
||||
// We need to rebuild the form to go to a second step. For example, to
|
||||
// show the confirmation form for the deletion of nodes.
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Theme node administration overview.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_node_admin_nodes($form) {
|
||||
// If there are rows in this form, then $form['title'] contains a list of
|
||||
// the title form elements.
|
||||
$has_posts = isset($form['title']) && is_array($form['title']);
|
||||
$select_header = $has_posts ? theme('table_select_header_cell') : '';
|
||||
$header = array($select_header, t('Title'), t('Type'), t('Author'), t('Status'));
|
||||
if (isset($form['language'])) {
|
||||
$header[] = t('Language');
|
||||
}
|
||||
$header[] = t('Operations');
|
||||
$output = '';
|
||||
|
||||
$output .= drupal_render($form['options']);
|
||||
if ($has_posts) {
|
||||
foreach (element_children($form['title']) as $key) {
|
||||
$row = array();
|
||||
$row[] = drupal_render($form['nodes'][$key]);
|
||||
$row[] = drupal_render($form['title'][$key]);
|
||||
$row[] = drupal_render($form['name'][$key]);
|
||||
$row[] = drupal_render($form['username'][$key]);
|
||||
$row[] = drupal_render($form['status'][$key]);
|
||||
if (isset($form['language'])) {
|
||||
$row[] = drupal_render($form['language'][$key]);
|
||||
}
|
||||
$row[] = drupal_render($form['operations'][$key]);
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
$rows[] = array(array('data' => t('No posts available.'), 'colspan' => '6'));
|
||||
}
|
||||
|
||||
$output .= theme('table', $header, $rows);
|
||||
if ($form['pager']['#value']) {
|
||||
$output .= drupal_render($form['pager']);
|
||||
}
|
||||
|
||||
$output .= drupal_render($form);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function node_multiple_delete_confirm(&$form_state, $nodes) {
|
||||
|
||||
$form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
|
||||
// array_filter returns only elements with TRUE values
|
||||
foreach ($nodes as $nid => $value) {
|
||||
$title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
|
||||
$form['nodes'][$nid] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $nid,
|
||||
'#prefix' => '<li>',
|
||||
'#suffix' => check_plain($title) ."</li>\n",
|
||||
);
|
||||
}
|
||||
$form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
|
||||
$form['#submit'][] = 'node_multiple_delete_confirm_submit';
|
||||
return confirm_form($form,
|
||||
t('Are you sure you want to delete these items?'),
|
||||
'admin/content/node', t('This action cannot be undone.'),
|
||||
t('Delete all'), t('Cancel'));
|
||||
}
|
||||
|
||||
function node_multiple_delete_confirm_submit($form, &$form_state) {
|
||||
if ($form_state['values']['confirm']) {
|
||||
foreach ($form_state['values']['nodes'] as $nid => $value) {
|
||||
node_delete($nid);
|
||||
}
|
||||
drupal_set_message(t('The items have been deleted.'));
|
||||
}
|
||||
$form_state['redirect'] = 'admin/content/node';
|
||||
return;
|
||||
}
|
||||
|
43
modules/node/node.css
Normal file
43
modules/node/node.css
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
.node-unpublished {
|
||||
background-color: #fff4f4;
|
||||
}
|
||||
.preview .node {
|
||||
background-color: #ffffea;
|
||||
}
|
||||
#node-admin-filter ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
#node-admin-buttons {
|
||||
float: left; /* LTR */
|
||||
margin-left: 0.5em; /* LTR */
|
||||
clear: right; /* LTR */
|
||||
}
|
||||
td.revision-current {
|
||||
background: #ffc;
|
||||
}
|
||||
.node-form .form-text {
|
||||
display: block;
|
||||
width: 95%;
|
||||
}
|
||||
.node-form .container-inline .form-text {
|
||||
display: inline;
|
||||
width: auto;
|
||||
}
|
||||
.node-form .standard {
|
||||
clear: both;
|
||||
}
|
||||
.node-form textarea {
|
||||
display: block;
|
||||
width: 95%;
|
||||
}
|
||||
.node-form .attachments fieldset {
|
||||
float: none;
|
||||
display: block;
|
||||
}
|
||||
.terms-inline {
|
||||
display: inline;
|
||||
}
|
11
modules/node/node.info
Normal file
11
modules/node/node.info
Normal file
|
@ -0,0 +1,11 @@
|
|||
name = Node
|
||||
description = Allows content to be submitted to the site and displayed on pages.
|
||||
package = Core - required
|
||||
version = VERSION
|
||||
core = 6.x
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-24
|
||||
version = "6.38"
|
||||
project = "drupal"
|
||||
datestamp = "1456343372"
|
||||
|
334
modules/node/node.install
Normal file
334
modules/node/node.install
Normal file
|
@ -0,0 +1,334 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implementation of hook_schema().
|
||||
*/
|
||||
function node_schema() {
|
||||
$schema['node'] = array(
|
||||
'description' => 'The base table for nodes.',
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'description' => 'The primary identifier for a node.',
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE),
|
||||
'vid' => array(
|
||||
'description' => 'The current {node_revisions}.vid version identifier.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'type' => array(
|
||||
'description' => 'The {node_type}.type of this node.',
|
||||
'type' => 'varchar',
|
||||
'length' => 32,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'language' => array(
|
||||
'description' => 'The {languages}.language of this node.',
|
||||
'type' => 'varchar',
|
||||
'length' => 12,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'title' => array(
|
||||
'description' => 'The title of this node, always treated as non-markup plain text.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'uid' => array(
|
||||
'description' => 'The {users}.uid that owns this node; initially, this is the user that created it.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'status' => array(
|
||||
'description' => 'Boolean indicating whether the node is published (visible to non-administrators).',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 1),
|
||||
'created' => array(
|
||||
'description' => 'The Unix timestamp when the node was created.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'changed' => array(
|
||||
'description' => 'The Unix timestamp when the node was most recently saved.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'comment' => array(
|
||||
'description' => 'Whether comments are allowed on this node: 0 = no, 1 = read only, 2 = read/write.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'promote' => array(
|
||||
'description' => 'Boolean indicating whether the node should be displayed on the front page.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'moderate' => array(
|
||||
'description' => 'Previously, a boolean indicating whether the node was "in moderation"; mostly no longer used.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'sticky' => array(
|
||||
'description' => 'Boolean indicating whether the node should be displayed at the top of lists in which it appears.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'tnid' => array(
|
||||
'description' => 'The translation set id for this node, which equals the node id of the source post in each set.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'translate' => array(
|
||||
'description' => 'A boolean indicating whether this translation page needs to be updated.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
),
|
||||
'indexes' => array(
|
||||
'node_changed' => array('changed'),
|
||||
'node_created' => array('created'),
|
||||
'node_moderate' => array('moderate'),
|
||||
'node_promote_status' => array('promote', 'status'),
|
||||
'node_status_type' => array('status', 'type', 'nid'),
|
||||
'node_title_type' => array('title', array('type', 4)),
|
||||
'node_type' => array(array('type', 4)),
|
||||
'uid' => array('uid'),
|
||||
'tnid' => array('tnid'),
|
||||
'translate' => array('translate'),
|
||||
),
|
||||
'unique keys' => array(
|
||||
'vid' => array('vid')
|
||||
),
|
||||
'primary key' => array('nid'),
|
||||
);
|
||||
|
||||
$schema['node_access'] = array(
|
||||
'description' => 'Identifies which realm/grant pairs a user must possess in order to view, update, or delete specific nodes.',
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'description' => 'The {node}.nid this record affects.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'gid' => array(
|
||||
'description' => "The grant ID a user must possess in the specified realm to gain this row's privileges on the node.",
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'realm' => array(
|
||||
'description' => 'The realm in which the user must possess the grant ID. Each node access node can define one or more realms.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'grant_view' => array(
|
||||
'description' => 'Boolean indicating whether a user with the realm/grant pair can view this node.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny'),
|
||||
'grant_update' => array(
|
||||
'description' => 'Boolean indicating whether a user with the realm/grant pair can edit this node.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny'),
|
||||
'grant_delete' => array(
|
||||
'description' => 'Boolean indicating whether a user with the realm/grant pair can delete this node.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny')
|
||||
),
|
||||
'primary key' => array('nid', 'gid', 'realm'),
|
||||
);
|
||||
|
||||
$schema['node_counter'] = array(
|
||||
'description' => 'Access statistics for {node}s.',
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'description' => 'The {node}.nid for these statistics.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'totalcount' => array(
|
||||
'description' => 'The total number of times the {node} has been viewed.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'big'),
|
||||
'daycount' => array(
|
||||
'description' => 'The total number of times the {node} has been viewed today.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'medium'),
|
||||
'timestamp' => array(
|
||||
'description' => 'The most recent time the {node} has been viewed.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0)
|
||||
),
|
||||
'primary key' => array('nid'),
|
||||
);
|
||||
|
||||
$schema['node_revisions'] = array(
|
||||
'description' => 'Stores information about each saved version of a {node}.',
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'description' => 'The {node} this version belongs to.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'vid' => array(
|
||||
'description' => 'The primary identifier for this version.',
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE),
|
||||
'uid' => array(
|
||||
'description' => 'The {users}.uid that created this version.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'title' => array(
|
||||
'description' => 'The title of this version.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'body' => array(
|
||||
'description' => 'The body of this version.',
|
||||
'type' => 'text',
|
||||
'not null' => TRUE,
|
||||
'size' => 'big'),
|
||||
'teaser' => array(
|
||||
'description' => 'The teaser of this version.',
|
||||
'type' => 'text',
|
||||
'not null' => TRUE,
|
||||
'size' => 'big'),
|
||||
'log' => array(
|
||||
'description' => 'The log entry explaining the changes in this version.',
|
||||
'type' => 'text',
|
||||
'not null' => TRUE,
|
||||
'size' => 'big'),
|
||||
'timestamp' => array(
|
||||
'description' => 'A Unix timestamp indicating when this version was created.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0),
|
||||
'format' => array(
|
||||
'description' => "The input format used by this version's body.",
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0)
|
||||
),
|
||||
'indexes' => array(
|
||||
'nid' => array('nid'),
|
||||
'uid' => array('uid')
|
||||
),
|
||||
'primary key' => array('vid'),
|
||||
);
|
||||
|
||||
$schema['node_type'] = array(
|
||||
'description' => 'Stores information about all defined {node} types.',
|
||||
'fields' => array(
|
||||
'type' => array(
|
||||
'description' => 'The machine-readable name of this type.',
|
||||
'type' => 'varchar',
|
||||
'length' => 32,
|
||||
'not null' => TRUE),
|
||||
'name' => array(
|
||||
'description' => 'The human-readable name of this type.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'module' => array(
|
||||
'description' => 'The base string used to construct callbacks corresponding to this node type.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE),
|
||||
'description' => array(
|
||||
'description' => 'A brief description of this type.',
|
||||
'type' => 'text',
|
||||
'not null' => TRUE,
|
||||
'size' => 'medium'),
|
||||
'help' => array(
|
||||
'description' => 'Help information shown to the user when creating a {node} of this type.',
|
||||
'type' => 'text',
|
||||
'not null' => TRUE,
|
||||
'size' => 'medium'),
|
||||
'has_title' => array(
|
||||
'description' => 'Boolean indicating whether this type uses the {node}.title field.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'size' => 'tiny'),
|
||||
'title_label' => array(
|
||||
'description' => 'The label displayed for the title field on the edit form.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'has_body' => array(
|
||||
'description' => 'Boolean indicating whether this type uses the {node_revisions}.body field.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'size' => 'tiny'),
|
||||
'body_label' => array(
|
||||
'description' => 'The label displayed for the body field on the edit form.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => ''),
|
||||
'min_word_count' => array(
|
||||
'description' => 'The minimum number of words the body must contain.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'size' => 'small'),
|
||||
'custom' => array(
|
||||
'description' => 'A boolean indicating whether this type is defined by a module (FALSE) or by a user via a module like the Content Construction Kit (TRUE).',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny'),
|
||||
'modified' => array(
|
||||
'description' => 'A boolean indicating whether this type has been modified by an administrator; currently not used in any way.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny'),
|
||||
'locked' => array(
|
||||
'description' => 'A boolean indicating whether the administrator can change the machine name of this type.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny'),
|
||||
'orig_type' => array(
|
||||
'description' => 'The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '')
|
||||
),
|
||||
'primary key' => array('type'),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
2788
modules/node/node.module
Normal file
2788
modules/node/node.module
Normal file
File diff suppressed because it is too large
Load diff
609
modules/node/node.pages.inc
Normal file
609
modules/node/node.pages.inc
Normal file
|
@ -0,0 +1,609 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Page callbacks for adding, editing, deleting, and revisions management for content.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Menu callback; presents the node editing form, or redirects to delete confirmation.
|
||||
*/
|
||||
function node_page_edit($node) {
|
||||
drupal_set_title(check_plain($node->title));
|
||||
return drupal_get_form($node->type .'_node_form', $node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback: Displays add content links for available content types.
|
||||
*/
|
||||
function node_add_page() {
|
||||
$item = menu_get_item();
|
||||
$content = system_admin_menu_block($item);
|
||||
return theme('node_add_list', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of available node types for node creation.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_node_add_list($content) {
|
||||
$output = '';
|
||||
|
||||
if ($content) {
|
||||
$output = '<dl class="node-type-list">';
|
||||
foreach ($content as $item) {
|
||||
$output .= '<dt>'. l($item['title'], $item['href'], $item['localized_options']) .'</dt>';
|
||||
$output .= '<dd>'. filter_xss_admin($item['description']) .'</dd>';
|
||||
}
|
||||
$output .= '</dl>';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Present a node submission form or a set of links to such forms.
|
||||
*/
|
||||
function node_add($type) {
|
||||
global $user;
|
||||
|
||||
$types = node_get_types();
|
||||
$type = isset($type) ? str_replace('-', '_', $type) : NULL;
|
||||
// If a node type has been specified, validate its existence.
|
||||
if (isset($types[$type]) && node_access('create', $type)) {
|
||||
// Initialize settings:
|
||||
$node = array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'language' => '');
|
||||
|
||||
drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)));
|
||||
$output = drupal_get_form($type .'_node_form', $node);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function node_form_validate($form, &$form_state) {
|
||||
node_validate($form_state['values'], $form);
|
||||
}
|
||||
|
||||
function node_object_prepare(&$node) {
|
||||
// Set up default values, if required.
|
||||
$node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
|
||||
// If this is a new node, fill in the default values.
|
||||
if (!isset($node->nid)) {
|
||||
foreach (array('status', 'promote', 'sticky') as $key) {
|
||||
$node->$key = in_array($key, $node_options);
|
||||
}
|
||||
global $user;
|
||||
$node->uid = $user->uid;
|
||||
$node->created = time();
|
||||
}
|
||||
else {
|
||||
$node->date = format_date($node->created, 'custom', 'Y-m-d H:i:s O');
|
||||
// Remove the log message from the original node object.
|
||||
$node->log = NULL;
|
||||
}
|
||||
// Always use the default revision setting.
|
||||
$node->revision = in_array('revision', $node_options);
|
||||
|
||||
node_invoke($node, 'prepare');
|
||||
node_invoke_nodeapi($node, 'prepare');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the node add/edit form array.
|
||||
*/
|
||||
function node_form(&$form_state, $node) {
|
||||
global $user;
|
||||
|
||||
if (isset($form_state['node'])) {
|
||||
$node = $form_state['node'] + (array)$node;
|
||||
}
|
||||
if (isset($form_state['node_preview'])) {
|
||||
$form['#prefix'] = $form_state['node_preview'];
|
||||
}
|
||||
$node = (object)$node;
|
||||
foreach (array('body', 'title', 'format') as $key) {
|
||||
if (!isset($node->$key)) {
|
||||
$node->$key = NULL;
|
||||
}
|
||||
}
|
||||
if (!isset($form_state['node_preview'])) {
|
||||
node_object_prepare($node);
|
||||
}
|
||||
else {
|
||||
$node->build_mode = NODE_BUILD_PREVIEW;
|
||||
}
|
||||
|
||||
// Set the id of the top-level form tag
|
||||
$form['#id'] = 'node-form';
|
||||
|
||||
// Basic node information.
|
||||
// These elements are just values so they are not even sent to the client.
|
||||
foreach (array('nid', 'vid', 'uid', 'created', 'type', 'language') as $key) {
|
||||
$form[$key] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => isset($node->$key) ? $node->$key : NULL,
|
||||
);
|
||||
}
|
||||
|
||||
// Changed must be sent to the client, for later overwrite error checking.
|
||||
$form['changed'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#default_value' => isset($node->changed) ? $node->changed : NULL,
|
||||
);
|
||||
// Get the node-specific bits.
|
||||
if ($extra = node_invoke($node, 'form', $form_state)) {
|
||||
$form = array_merge_recursive($form, $extra);
|
||||
}
|
||||
if (!isset($form['title']['#weight'])) {
|
||||
$form['title']['#weight'] = -5;
|
||||
}
|
||||
|
||||
$form['#node'] = $node;
|
||||
|
||||
// Add a log field if the "Create new revision" option is checked, or if the
|
||||
// current user has the ability to check that option.
|
||||
if (!empty($node->revision) || user_access('administer nodes')) {
|
||||
$form['revision_information'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Revision information'),
|
||||
'#collapsible' => TRUE,
|
||||
// Collapsed by default when "Create new revision" is unchecked
|
||||
'#collapsed' => !$node->revision,
|
||||
'#weight' => 20,
|
||||
);
|
||||
$form['revision_information']['revision'] = array(
|
||||
'#access' => user_access('administer nodes'),
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Create new revision'),
|
||||
'#default_value' => $node->revision,
|
||||
);
|
||||
$form['revision_information']['log'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Log message'),
|
||||
'#default_value' => (isset($node->log) ? $node->log : ''),
|
||||
'#rows' => 2,
|
||||
'#description' => t('An explanation of the additions or updates being made to help other authors understand your motivations.'),
|
||||
);
|
||||
}
|
||||
|
||||
// Node author information for administrators
|
||||
$form['author'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#access' => user_access('administer nodes'),
|
||||
'#title' => t('Authoring information'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#weight' => 20,
|
||||
);
|
||||
$form['author']['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Authored by'),
|
||||
'#maxlength' => 60,
|
||||
'#autocomplete_path' => 'user/autocomplete',
|
||||
'#default_value' => $node->name ? $node->name : '',
|
||||
'#weight' => -1,
|
||||
'#description' => t('Leave blank for %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous')))),
|
||||
);
|
||||
$form['author']['date'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Authored on'),
|
||||
'#maxlength' => 25,
|
||||
'#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'))),
|
||||
);
|
||||
|
||||
if (isset($node->date)) {
|
||||
$form['author']['date']['#default_value'] = $node->date;
|
||||
}
|
||||
|
||||
// Node options for administrators
|
||||
$form['options'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#access' => user_access('administer nodes'),
|
||||
'#title' => t('Publishing options'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#weight' => 25,
|
||||
);
|
||||
$form['options']['status'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Published'),
|
||||
'#default_value' => $node->status,
|
||||
);
|
||||
$form['options']['promote'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Promoted to front page'),
|
||||
'#default_value' => $node->promote,
|
||||
);
|
||||
$form['options']['sticky'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Sticky at top of lists'),
|
||||
'#default_value' => $node->sticky,
|
||||
);
|
||||
|
||||
// These values are used when the user has no administrator access.
|
||||
foreach (array('uid', 'created') as $key) {
|
||||
$form[$key] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $node->$key,
|
||||
);
|
||||
}
|
||||
|
||||
// Add the buttons.
|
||||
$form['buttons'] = array();
|
||||
$form['buttons']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#access' => !variable_get('node_preview', 0) || (!form_get_errors() && isset($form_state['node_preview'])),
|
||||
'#value' => t('Save'),
|
||||
'#weight' => 5,
|
||||
'#submit' => array('node_form_submit'),
|
||||
);
|
||||
$form['buttons']['preview'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Preview'),
|
||||
'#weight' => 10,
|
||||
'#submit' => array('node_form_build_preview'),
|
||||
);
|
||||
if (!empty($node->nid) && node_access('delete', $node)) {
|
||||
$form['buttons']['delete'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Delete'),
|
||||
'#weight' => 15,
|
||||
'#submit' => array('node_form_delete_submit'),
|
||||
);
|
||||
}
|
||||
$form['#validate'][] = 'node_form_validate';
|
||||
$form['#theme'] = array($node->type .'_node_form', 'node_form');
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a node body field, with format and teaser.
|
||||
*/
|
||||
function node_body_field(&$node, $label, $word_count) {
|
||||
|
||||
// Check if we need to restore the teaser at the beginning of the body.
|
||||
$include = !isset($node->teaser) || ($node->teaser == substr($node->body, 0, strlen($node->teaser)));
|
||||
|
||||
$form = array(
|
||||
'#after_build' => array('node_teaser_js', 'node_teaser_include_verify'));
|
||||
|
||||
$form['#prefix'] = '<div class="body-field-wrapper">';
|
||||
$form['#suffix'] = '</div>';
|
||||
|
||||
$form['teaser_js'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 10,
|
||||
'#teaser' => 'edit-body',
|
||||
'#teaser_checkbox' => 'edit-teaser-include',
|
||||
'#disabled' => TRUE,
|
||||
);
|
||||
|
||||
$form['teaser_include'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Show summary in full view'),
|
||||
'#default_value' => $include,
|
||||
'#prefix' => '<div class="teaser-checkbox">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
$form['body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => check_plain($label),
|
||||
'#default_value' => $include ? $node->body : ($node->teaser . $node->body),
|
||||
'#rows' => 20,
|
||||
'#required' => ($word_count > 0),
|
||||
);
|
||||
|
||||
$form['format'] = filter_form($node->format);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Button sumit function: handle the 'Delete' button on the node form.
|
||||
*/
|
||||
function node_form_delete_submit($form, &$form_state) {
|
||||
$destination = '';
|
||||
if (isset($_REQUEST['destination'])) {
|
||||
$destination = drupal_get_destination();
|
||||
unset($_REQUEST['destination']);
|
||||
}
|
||||
$node = $form['#node'];
|
||||
$form_state['redirect'] = array('node/'. $node->nid .'/delete', $destination);
|
||||
}
|
||||
|
||||
|
||||
function node_form_build_preview($form, &$form_state) {
|
||||
$node = node_form_submit_build_node($form, $form_state);
|
||||
$form_state['node_preview'] = node_preview($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Present a node submission form.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_node_form($form) {
|
||||
$output = "\n<div class=\"node-form\">\n";
|
||||
|
||||
// Admin form fields and submit buttons must be rendered first, because
|
||||
// they need to go to the bottom of the form, and so should not be part of
|
||||
// the catch-all call to drupal_render().
|
||||
$admin = '';
|
||||
if (isset($form['author'])) {
|
||||
$admin .= " <div class=\"authored\">\n";
|
||||
$admin .= drupal_render($form['author']);
|
||||
$admin .= " </div>\n";
|
||||
}
|
||||
if (isset($form['options'])) {
|
||||
$admin .= " <div class=\"options\">\n";
|
||||
$admin .= drupal_render($form['options']);
|
||||
$admin .= " </div>\n";
|
||||
}
|
||||
$buttons = drupal_render($form['buttons']);
|
||||
|
||||
// Everything else gets rendered here, and is displayed before the admin form
|
||||
// field and the submit buttons.
|
||||
$output .= " <div class=\"standard\">\n";
|
||||
$output .= drupal_render($form);
|
||||
$output .= " </div>\n";
|
||||
|
||||
if (!empty($admin)) {
|
||||
$output .= " <div class=\"admin\">\n";
|
||||
$output .= $admin;
|
||||
$output .= " </div>\n";
|
||||
}
|
||||
$output .= $buttons;
|
||||
$output .= "</div>\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a node preview.
|
||||
*/
|
||||
function node_preview($node) {
|
||||
if (node_access('create', $node) || node_access('update', $node)) {
|
||||
// Load the user's name when needed.
|
||||
if (isset($node->name)) {
|
||||
// The use of isset() is mandatory in the context of user IDs, because
|
||||
// user ID 0 denotes the anonymous user.
|
||||
if ($user = user_load(array('name' => $node->name))) {
|
||||
$node->uid = $user->uid;
|
||||
$node->picture = $user->picture;
|
||||
}
|
||||
else {
|
||||
$node->uid = 0; // anonymous user
|
||||
}
|
||||
}
|
||||
else if ($node->uid) {
|
||||
$user = user_load(array('uid' => $node->uid));
|
||||
$node->name = $user->name;
|
||||
$node->picture = $user->picture;
|
||||
}
|
||||
|
||||
$node->changed = time();
|
||||
|
||||
// Extract a teaser, if it hasn't been set (e.g. by a module-provided
|
||||
// 'teaser' form item).
|
||||
if (!isset($node->teaser)) {
|
||||
$node->teaser = empty($node->body) ? '' : node_teaser($node->body, $node->format);
|
||||
// Chop off the teaser from the body if needed.
|
||||
if (!$node->teaser_include && $node->teaser == substr($node->body, 0, strlen($node->teaser))) {
|
||||
$node->body = substr($node->body, strlen($node->teaser));
|
||||
}
|
||||
}
|
||||
|
||||
// Display a preview of the node.
|
||||
// Previewing alters $node so it needs to be cloned.
|
||||
if (!form_get_errors()) {
|
||||
$cloned_node = drupal_clone($node);
|
||||
$cloned_node->build_mode = NODE_BUILD_PREVIEW;
|
||||
$output = theme('node_preview', $cloned_node);
|
||||
}
|
||||
drupal_set_title(t('Preview'));
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a node preview for display during node creation and editing.
|
||||
*
|
||||
* @param $node
|
||||
* The node object which is being previewed.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_node_preview($node) {
|
||||
$output = '<div class="preview">';
|
||||
|
||||
$preview_trimmed_version = FALSE;
|
||||
// Do we need to preview trimmed version of post as well as full version?
|
||||
if (isset($node->teaser) && isset($node->body)) {
|
||||
$teaser = trim($node->teaser);
|
||||
$body = trim(str_replace('<!--break-->', '', $node->body));
|
||||
|
||||
// Preview trimmed version if teaser and body will appear different;
|
||||
// also (edge case) if both teaser and body have been specified by the user
|
||||
// and are actually the same.
|
||||
if ($teaser != $body || ($body && strpos($node->body, '<!--break-->') === 0)) {
|
||||
$preview_trimmed_version = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($preview_trimmed_version) {
|
||||
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 "<!--break-->" (without the quotes) to fine-tune where your post gets split.</span>'));
|
||||
$output .= '<h3>'. t('Preview trimmed version') .'</h3>';
|
||||
$output .= node_view(drupal_clone($node), 1, FALSE, 0);
|
||||
$output .= '<h3>'. t('Preview full version') .'</h3>';
|
||||
$output .= node_view($node, 0, FALSE, 0);
|
||||
}
|
||||
else {
|
||||
$output .= node_view($node, 0, FALSE, 0);
|
||||
}
|
||||
$output .= "</div>\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function node_form_submit($form, &$form_state) {
|
||||
global $user;
|
||||
|
||||
$node = node_form_submit_build_node($form, $form_state);
|
||||
$insert = empty($node->nid);
|
||||
node_save($node);
|
||||
$node_link = l(t('view'), 'node/'. $node->nid);
|
||||
$watchdog_args = array('@type' => $node->type, '%title' => $node->title);
|
||||
$t_args = array('@type' => node_get_types('name', $node), '%title' => $node->title);
|
||||
|
||||
if ($insert) {
|
||||
watchdog('content', '@type: added %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link);
|
||||
drupal_set_message(t('@type %title has been created.', $t_args));
|
||||
}
|
||||
else {
|
||||
watchdog('content', '@type: updated %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link);
|
||||
drupal_set_message(t('@type %title has been updated.', $t_args));
|
||||
}
|
||||
if ($node->nid) {
|
||||
unset($form_state['rebuild']);
|
||||
$form_state['nid'] = $node->nid;
|
||||
$form_state['redirect'] = 'node/'. $node->nid;
|
||||
}
|
||||
else {
|
||||
// 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');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a node by processing submitted form values and prepare for a form rebuild.
|
||||
*/
|
||||
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($form_state['values']);
|
||||
$form_state['node'] = (array)$node;
|
||||
$form_state['rebuild'] = TRUE;
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback -- ask for confirmation of node deletion
|
||||
*/
|
||||
function node_delete_confirm(&$form_state, $node) {
|
||||
$form['nid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $node->nid,
|
||||
);
|
||||
|
||||
return confirm_form($form,
|
||||
t('Are you sure you want to delete %title?', array('%title' => $node->title)),
|
||||
isset($_GET['destination']) ? $_GET['destination'] : 'node/'. $node->nid,
|
||||
t('This action cannot be undone.'),
|
||||
t('Delete'),
|
||||
t('Cancel')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute node deletion
|
||||
*/
|
||||
function node_delete_confirm_submit($form, &$form_state) {
|
||||
if ($form_state['values']['confirm']) {
|
||||
node_delete($form_state['values']['nid']);
|
||||
}
|
||||
|
||||
$form_state['redirect'] = '<front>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an overview table of older revisions of a node.
|
||||
*/
|
||||
function node_revision_overview($node) {
|
||||
drupal_set_title(t('Revisions for %title', array('%title' => $node->title)));
|
||||
|
||||
$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;
|
||||
if ((user_access('delete revisions') || user_access('administer nodes')) && node_access('delete', $node)) {
|
||||
$delete_permission = TRUE;
|
||||
}
|
||||
foreach ($revisions as $revision) {
|
||||
$row = array();
|
||||
$operations = array();
|
||||
|
||||
if ($revision->current_vid > 0) {
|
||||
$row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'small'), "node/$node->nid"), '!username' => theme('username', $revision)))
|
||||
. (($revision->log != '') ? '<p class="revision-log">'. filter_xss($revision->log) .'</p>' : ''),
|
||||
'class' => 'revision-current');
|
||||
$operations[] = array('data' => theme('placeholder', t('current revision')), 'class' => 'revision-current', 'colspan' => 2);
|
||||
}
|
||||
else {
|
||||
$row[] = t('!date by !username', array('!date' => l(format_date($revision->timestamp, 'small'), "node/$node->nid/revisions/$revision->vid/view"), '!username' => theme('username', $revision)))
|
||||
. (($revision->log != '') ? '<p class="revision-log">'. filter_xss($revision->log) .'</p>' : '');
|
||||
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);
|
||||
}
|
||||
|
||||
return theme('table', $header, $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for confirmation of the reversion to prevent against CSRF attacks.
|
||||
*/
|
||||
function node_revision_revert_confirm($form_state, $node_revision) {
|
||||
$form['#node_revision'] = $node_revision;
|
||||
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'));
|
||||
}
|
||||
|
||||
function node_revision_revert_confirm_submit($form, &$form_state) {
|
||||
$node_revision = $form['#node_revision'];
|
||||
$node_revision->revision = 1;
|
||||
$node_revision->log = t('Copy of the revision from %date.', array('%date' => format_date($node_revision->revision_timestamp)));
|
||||
if (module_exists('taxonomy')) {
|
||||
$node_revision->taxonomy = array_keys($node_revision->taxonomy);
|
||||
}
|
||||
|
||||
node_save($node_revision);
|
||||
|
||||
watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%revision' => $node_revision->vid));
|
||||
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))));
|
||||
$form_state['redirect'] = 'node/'. $node_revision->nid .'/revisions';
|
||||
}
|
||||
|
||||
function node_revision_delete_confirm($form_state, $node_revision) {
|
||||
$form['#node_revision'] = $node_revision;
|
||||
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'));
|
||||
}
|
||||
|
||||
function node_revision_delete_confirm_submit($form, &$form_state) {
|
||||
$node_revision = $form['#node_revision'];
|
||||
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $node_revision->nid, $node_revision->vid);
|
||||
node_invoke_nodeapi($node_revision, 'delete revision');
|
||||
watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node_revision->type, '%title' => $node_revision->title, '%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_get_types('name', $node_revision), '%title' => $node_revision->title)));
|
||||
$form_state['redirect'] = 'node/'. $node_revision->nid;
|
||||
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node_revision->nid)) > 1) {
|
||||
$form_state['redirect'] .= '/revisions';
|
||||
}
|
||||
}
|
73
modules/node/node.tpl.php
Normal file
73
modules/node/node.tpl.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file node.tpl.php
|
||||
*
|
||||
* Theme implementation to display a node.
|
||||
*
|
||||
* Available variables:
|
||||
* - $title: the (sanitized) title of the node.
|
||||
* - $content: Node body or teaser depending on $teaser flag.
|
||||
* - $picture: The authors picture of the node output from
|
||||
* theme_user_picture().
|
||||
* - $date: Formatted creation date (use $created to reformat with
|
||||
* format_date()).
|
||||
* - $links: Themed links like "Read more", "Add new comment", etc. output
|
||||
* from theme_links().
|
||||
* - $name: Themed username of node author output from theme_username().
|
||||
* - $node_url: Direct URL of the current node.
|
||||
* - $terms: the themed list of taxonomy term links output from theme_links().
|
||||
* - $submitted: themed submission information output from
|
||||
* theme_node_submitted().
|
||||
*
|
||||
* Other variables:
|
||||
* - $node: Full node object. Contains data that may not be safe.
|
||||
* - $type: Node type, i.e. story, page, blog, etc.
|
||||
* - $comment_count: Number of comments attached to the node.
|
||||
* - $uid: User ID of the node author.
|
||||
* - $created: Time the node was published formatted in Unix timestamp.
|
||||
* - $zebra: Outputs either "even" or "odd". Useful for zebra striping in
|
||||
* teaser listings.
|
||||
* - $id: Position of the node. Increments each time it's output.
|
||||
*
|
||||
* Node status variables:
|
||||
* - $teaser: Flag for the teaser state.
|
||||
* - $page: Flag for the full page state.
|
||||
* - $promote: Flag for front page promotion state.
|
||||
* - $sticky: Flags for sticky post setting.
|
||||
* - $status: Flag for published status.
|
||||
* - $comment: State of comment settings for the node.
|
||||
* - $readmore: Flags true if the teaser content of the node cannot hold the
|
||||
* main body content.
|
||||
* - $is_front: Flags true when presented in the front page.
|
||||
* - $logged_in: Flags true when the current user is a logged-in member.
|
||||
* - $is_admin: Flags true when the current user is an administrator.
|
||||
*
|
||||
* @see template_preprocess()
|
||||
* @see template_preprocess_node()
|
||||
*/
|
||||
?>
|
||||
<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clear-block">
|
||||
|
||||
<?php print $picture ?>
|
||||
|
||||
<?php if (!$page): ?>
|
||||
<h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="meta">
|
||||
<?php if ($submitted): ?>
|
||||
<span class="submitted"><?php print $submitted ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($terms): ?>
|
||||
<div class="terms terms-inline"><?php print $terms ?></div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<?php print $content ?>
|
||||
</div>
|
||||
|
||||
<?php print $links; ?>
|
||||
</div>
|
Reference in a new issue