' . t('The Diff module replaces the normal Revisions node tab. Diff enhances the listing of revisions with an option to view the differences between any two content revisions. Access to this feature is controlled with the View revisions permission. The feature can be disabled for an entire content type on the content type configuration page. Diff also provides an optional View changes button while editing a node.') . '
'; return $output; case 'node/%/revisions/%/view': // The translated strings should match node_help('node/%/revisions'). return '' . t('Revisions allow you to track differences between multiple versions of your content, and revert back to older versions.') . '
'; case 'node/%/revisions/view/%/%': return '' . t('Comparing two revisions:') . '
'; } } /** * The various states that are available. */ function diff_available_states($entity_type = NULL) { $states = array( 'raw' => t('Standard'), 'raw_plain' => t('Marked down'), ); return $states; } /** * Implements hook_menu(). * * @todo: Review this. */ function diff_menu() { /* * By using MENU_LOCAL_TASK (and 'tab_parent') we can get the various * revision-views to show the View|Edit|Revision-tabs of the node on top, * and have the Revisions-tab open. To avoid creating/showing any extra tabs * or sub-tabs (tasks below top level) for the various paths (i.e. "Diff", * "Show latest" and "Show a specific revision") that need a revision-id (vid) * parameter, we make sure to set 'tab_parent' a bit odd. This solution may * not be the prettiest one, but by avoiding having two _LOCAL_TASKs sharing * a parent that can be accessed by its full path, it seems to work as * desired. Breadcrumbs work decently, at least the node link is among the * crumbs. For some reason any breadcrumbs "before/above" the node is only * seen at 'node/%node/revisions/%/view'. */ // Not used directly, but was created to get the other menu items to work. $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' => 'Compare revisions', '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 difference', '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', ); // Administrative settings. $items['admin/config/content/diff'] = array( 'title' => 'Diff', 'description' => 'Diff settings.', 'file' => 'diff.admin.inc', 'page callback' => 'drupal_get_form', 'page arguments' => array('diff_admin_settings'), 'access arguments' => array('administer site configuration'), ); $items['admin/config/content/diff/settings'] = array( 'title' => 'Settings', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items['admin/config/content/diff/fields'] = array( 'title' => 'Fields', 'description' => 'Field support and settings overview.', 'file' => 'diff.admin.inc', 'page callback' => 'diff_admin_field_overview', 'access arguments' => array('administer site configuration'), 'type' => MENU_LOCAL_TASK, ); $items['admin/config/content/diff/fields/%'] = array( 'title' => 'Global field settings', 'page callback' => 'drupal_get_form', 'page arguments' => array('diff_admin_global_field_settings', 5), 'access arguments' => array('administer site configuration'), 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'diff.admin.inc', ); $items['admin/config/content/diff/entities'] = array( 'title' => 'Entities', 'description' => 'Entity settings.', 'file' => 'diff.admin.inc', 'page callback' => 'drupal_get_form', 'page arguments' => array('diff_admin_global_entity_settings', 'node'), 'access arguments' => array('administer site configuration'), 'type' => MENU_LOCAL_TASK, ); $items['admin/config/content/diff/entities/node'] = array( 'title' => 'Node', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); return $items; } /** * Implements hook_menu_alter(). */ function diff_menu_alter(&$callbacks) { // Overwrite the default 'Revisions' page. $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'; } /** * Implements hook_admin_paths_alter(). */ function diff_admin_paths_alter(&$paths) { // By default, treat all diff pages as administrative. if (variable_get('diff_admin_path_node', 1)) { $paths['node/*/revisions/view/*/*'] = TRUE; } } /** * Access callback for the node revisions page. */ function diff_node_revision_access($node, $op = 'view') { $may_revision_this_type = variable_get('diff_enable_revisions_page_node_' . $node->type, TRUE) || user_access('administer nodes'); return $may_revision_this_type && _node_revision_access($node, $op); } /** * Implements hook_hook_info(). */ function diff_hook_info() { $hooks['entity_diff'] = array( 'group' => 'diff', ); $hooks['diff'] = array( 'group' => 'diff', ); $hooks['field_diff_view_prepare_alter'] = array( 'group' => 'diff', ); $hooks['field_diff_view_alter'] = array( 'group' => 'diff', ); return $hooks; } /** * Implements hook_entity_info_alter(). * * Although the module only provides an UI for comparing nodes, it has an * extendable API for any entity, so we supply two view modes for all entities. * - diff_standard: This view mode is used to tell the module how to compare * individual fields. This is used on the revisions page. */ function diff_entity_info_alter(&$entity_info) { foreach (array_keys($entity_info) as $entity_type) { if (!empty($entity_info[$entity_type]['view modes'])) { $entity_info[$entity_type]['view modes'] += array( 'diff_standard' => array( 'label' => t('Revision comparison'), 'custom settings' => FALSE, ), ); } } } /** * Implements hook_block_info(). */ function diff_block_info() { return array( 'inline' => array( 'info' => t('Inline differences'), ), ); } /** * Implements hook_block_configure(). */ function diff_block_configure($delta = '') { $form = array(); switch ($delta) { case 'inline': $form['bundles'] = array( '#type' => 'checkboxes', '#title' => t('Enabled content types'), '#default_value' => variable_get('diff_show_diff_inline_node_bundles', array()), '#options' => node_type_get_names(), '#description' => t('Show this block only on pages that display content of the given type(s).'), ); break; } return $form; } /** * Implements hook_block_save(). */ function diff_block_save($delta = '', $edit = array()) { switch ($delta) { case 'inline': variable_set('diff_show_diff_inline_node_bundles', $edit['bundles']); break; } } /** * Implements hook_block_view(). */ function diff_block_view($delta) { if ($delta === 'inline' && user_access('view revisions') && ($node = menu_get_object()) && arg(2) !== 'edit') { $enabled_types = variable_get('diff_show_diff_inline_node_bundles', array()); if (!empty($enabled_types[$node->type])) { $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; } } } /** * Implements hook_node_view_alter(). */ function diff_node_view_alter(&$build) { $node = $build['#node']; if (user_access('view revisions') && in_array($node->type, variable_get('diff_show_diff_inline_node_bundles', array()))) { // Ugly but cheap way to check that we are viewing a node's revision page. 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']) ? "