View source
<?php
define('REVISION_LIST_SIZE', 50);
function diff_help($path, $arg) {
switch ($path) {
case 'admin/help#diff':
$output = '<p>' . t('The diff module overwrites the normal revisions view. The revisions table is enhanced with a possibility to view the difference between two node revisions. Users with the %view_revisions permission will also be able to view the changes between any two selected revisions. You may disable this for individual content types on the content type configuration page. This module also provides a nifty %preview_changes button while editing a post.', array(
'%preview_changes' => t('View changes'),
'%view_revisions' => t('view revisions'),
)) . '</p>';
return $output;
case 'node/%/revisions/%/view':
return '<p>' . t('The revisions let you track differences between multiple versions of a post.') . '</p>';
case 'node/%/revisions/view/%/%':
return '<p>' . t('Comparing two revisions:') . '</p>';
}
}
function diff_menu() {
$items = array();
$items['node/%node/revisions/list'] = array(
'title' => 'List revisions',
'page callback' => 'diff_diffs_overview',
'type' => MENU_DEFAULT_LOCAL_TASK,
'access callback' => 'diff_node_revision_access',
'access arguments' => array(
1,
),
'file' => 'diff.pages.inc',
);
$items['node/%node/revisions/view'] = array(
'title' => 'Diff',
'page callback' => 'diff_diffs_show',
'page arguments' => array(
1,
4,
5,
6,
),
'type' => MENU_LOCAL_TASK,
'access callback' => 'diff_node_revision_access',
'access arguments' => array(
1,
),
'tab_parent' => 'node/%/revisions/list',
'file' => 'diff.pages.inc',
);
$items['node/%node/revisions/view/latest'] = array(
'title' => 'Show latest diff',
'page callback' => 'diff_latest',
'page arguments' => array(
1,
),
'type' => MENU_LOCAL_TASK,
'access callback' => 'diff_node_revision_access',
'access arguments' => array(
1,
),
'tab_parent' => 'node/%/revisions/view',
'file' => 'diff.pages.inc',
);
return $items;
}
function diff_menu_alter(&$callbacks) {
$callbacks['node/%node/revisions']['page callback'] = 'diff_diffs_overview';
$callbacks['node/%node/revisions']['module'] = 'diff';
$callbacks['node/%node/revisions']['file'] = 'diff.pages.inc';
$callbacks['node/%node/revisions/%/view']['tab_parent'] = 'node/%/revisions/list';
$callbacks['node/%node/revisions/%/revert']['tab_parent'] = 'node/%/revisions/%/view';
$callbacks['node/%node/revisions/%/delete']['tab_parent'] = 'node/%/revisions/%/view';
$callbacks['node/%node/revisions']['access callback'] = $callbacks['node/%node/revisions/%/view']['access callback'] = $callbacks['node/%node/revisions/%/revert']['access callback'] = $callbacks['node/%node/revisions/%/delete']['access callback'] = 'diff_node_revision_access';
return;
}
function diff_admin_paths_alter(&$paths) {
$paths['node/*/revisions/view/*/*'] = TRUE;
}
function diff_node_revision_access($node, $op = 'view') {
$may_revision_this_type = variable_get('enable_revisions_page_' . $node->type, TRUE) || user_access('administer nodes');
return $may_revision_this_type && _node_revision_access($node, $op);
}
function diff_block_info() {
return array(
'inline' => array(
'info' => t('Inline diff'),
),
);
}
function diff_block_view($delta) {
if ($delta === 'inline' && user_access('view revisions') && ($node = menu_get_object())) {
$block = array();
$revisions = node_revision_list($node);
if (count($revisions) > 1) {
$block['subject'] = t('Highlight changes');
$block['content'] = drupal_get_form('diff_inline_form', $node, $revisions);
}
return $block;
}
}
function diff_node_view_alter(&$build) {
$node = $build['#node'];
if (user_access('view revisions') && variable_get('show_diff_inline_' . $node->type, FALSE)) {
if (arg(2) === 'revisions' && arg(3) === $node->vid) {
module_load_include('inc', 'diff', 'diff.pages');
$old_vid = _diff_get_previous_vid(node_revision_list($node), $node->vid);
$build = array(
'#markup' => diff_inline_show($node, $old_vid),
);
}
$build['#prefix'] = isset($build['#prefix']) ? "<div id='diff-inline-{$node->nid}'>" . $build['#prefix'] : "<div id='diff-inline-{$node->nid}'>";
$build['#suffix'] = isset($build['#suffix']) ? $build['#suffix'] . "</div>" : "</div>";
}
}
function diff_form_alter(&$form, &$form_state, $form_id) {
if (!empty($form['#node_edit_form'])) {
if (variable_get('show_preview_changes_' . $form['type']['#value'], TRUE) && $form['nid']['#value'] > 0) {
$form['actions']['preview_changes'] = array(
'#type' => 'submit',
'#value' => t('View changes'),
'#weight' => 12,
'#submit' => array(
'diff_node_form_build_preview_changes',
),
);
}
}
}
function diff_form_node_type_form_alter(&$form, $form_state) {
if (isset($form['type'])) {
$form['diff'] = array(
'#title' => t('Diff'),
'#type' => 'fieldset',
'#group' => 'additional_settings',
'#tree' => FALSE,
);
$form['diff']['show_preview_changes'] = array(
'#type' => 'checkbox',
'#title' => t('Show %preview_changes button on node edit form', array(
'%preview_changes' => t('View changes'),
)),
'#weight' => 10,
'#default_value' => variable_get('show_preview_changes_' . $form['#node_type']->type, TRUE),
);
$form['diff']['remove_markup_default'] = array(
'#type' => 'checkbox',
'#title' => t('Remove markup by default when comparing body text'),
'#weight' => 10,
'#default_value' => variable_get('remove_markup_default_' . $form['#node_type']->type, FALSE),
);
$form['diff']['show_diff_inline'] = array(
'#type' => 'checkbox',
'#title' => t('Show diffs inline for this content type'),
'#description' => t("You must enable the 'Inline diff' block to use this feature"),
'#weight' => 10,
'#default_value' => variable_get('show_diff_inline_' . $form['#node_type']->type, FALSE),
);
$form['diff']['enable_revisions_page'] = array(
'#type' => 'checkbox',
'#title' => t('Enable the %revisions page for this content type', array(
'%revisions' => t('Revisions'),
)),
'#weight' => 11,
'#default_value' => variable_get('enable_revisions_page_' . $form['#node_type']->type, TRUE),
);
}
}
function diff_node_form_build_preview_changes($form, &$form_state) {
module_load_include('inc', 'diff', 'diff.pages');
$old_node = clone node_load($form_state['values']['nid']);
$node = node_form_submit_build_node($form, $form_state);
$rows = _diff_body_rows($old_node, $node, variable_get('remove_markup_default_' . $node->type, FALSE));
$cols = _diff_default_cols();
$header = _diff_default_header();
$changes = theme('diff_table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'class' => 'diff',
),
'cols' => $cols,
));
$form_state['node_preview'] = $changes;
$form_state['rebuild'] = TRUE;
}
function diff_theme() {
return array(
'diff_node_revisions' => array(
'render element' => 'form',
'file' => 'diff.theme.inc',
),
'diff_table' => array(
'arguments' => array(
'header' => NULL,
'rows' => NULL,
'attributes' => array(),
'caption' => NULL,
'cols' => array(),
),
'file' => 'diff.theme.inc',
),
'diff_header_line' => array(
'arguments' => array(
'lineno' => NULL,
),
'file' => 'diff.theme.inc',
),
'diff_content_line' => array(
'arguments' => array(
'line' => NULL,
),
'file' => 'diff.theme.inc',
),
'diff_empty_line' => array(
'arguments' => array(
'line' => NULL,
),
'file' => 'diff.theme.inc',
),
'diff_inline_form' => array(
'render element' => 'form',
'file' => 'diff.theme.inc',
),
'diff_inline_metadata' => array(
'arguments' => array(
'node' => NULL,
),
'file' => 'diff.theme.inc',
),
'diff_inline_chunk' => array(
'arguments' => array(
'text' => '',
'type' => NULL,
),
'file' => 'diff.theme.inc',
),
);
}
function diff_get_rows($a, $b, $show_header = FALSE) {
$a = is_array($a) ? $a : explode("\n", $a);
$b = is_array($b) ? $b : explode("\n", $b);
module_load_include('php', 'diff', 'DiffEngine');
$formatter = new DrupalDiffFormatter();
$formatter->show_header = $show_header;
$diff = new Diff($a, $b);
return $formatter
->format($diff);
}
function diff_get_inline($a, $b) {
module_load_include('php', 'diff', 'DiffEngine');
$diff = new DrupalDiffInline($a, $b);
return $diff
->render();
}
function diff_inline_form($form, $form_state, $node, $revisions) {
$form = array();
$form['node'] = array(
'#type' => 'value',
'#value' => $node,
);
$form['revision'] = array(
'#type' => 'select',
'#options' => array(
0 => '< ' . t('No highlighting') . ' >',
),
'#default_value' => arg(2) === 'revisions' && arg(3) === $node->vid ? $node->vid : 0,
'#ajax' => array(
'callback' => 'diff_inline_ajax',
'wrapper' => "node-{$node->nid}",
'method' => 'replace',
),
);
foreach ($revisions as $revision) {
$form['revision']['#options'][$revision->vid] = t('@revision by @name', array(
'@revision' => format_date($revision->timestamp, 'short'),
'@name' => $revision->name,
));
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('View'),
'#submit' => array(
'diff_inline_form_submit',
),
'#attributes' => array(
'class' => array(
'diff-js-hidden',
),
),
);
return $form;
}
function diff_inline_ajax($form, $form_state) {
module_load_include('inc', 'diff', 'diff.pages');
$node = $form['node']['#value'];
$vid = isset($form_state['values']['revision']) ? $form_state['values']['revision'] : 0;
return "<div id='node-{$node->nid}'>" . diff_inline_show($node, $vid) . "</div>";
}
function diff_inline_form_submit(&$form, &$form_state) {
if (isset($form_state['values']['revision'], $form_state['values']['node'])) {
$node = $form_state['values']['node'];
$vid = $form_state['values']['revision'];
$form_state['redirect'] = "node/{$node->nid}/revisions/{$vid}/view";
}
}