| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: diff.module,v 1.23.2.3.2.20 2010/08/12 16:34:08 yhahn Exp $ 3 4 /** 5 * @file 6 * Provides functionality to show a diff between two node revisions. 7 */ 8 9 /** 10 * Number of items on one page of the revision list. 11 */ 12 define('REVISION_LIST_SIZE', 50); 13 14 /** 15 * Implementation of hook_help(). 16 */ 17 function diff_help($path, $arg) { 18 switch ($path) { 19 case 'admin/help#diff': 20 $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>'; 21 return $output; 22 case 'node/%/revisions/%/view': 23 // the following string is copied from string copied from node_help('node/%/revisions') 24 return '<p>'. t('The revisions let you track differences between multiple versions of a post.') .'</p>'; 25 case 'node/%/revisions/view/%/%': 26 return '<p>'. t('Comparing two revisions:') .'</p>'; 27 } 28 } 29 30 /** 31 * Implementation of hook_menu(). 32 */ 33 function diff_menu() { 34 $items = array(); 35 36 /** 37 * By using MENU_LOCAL_TASK (and 'tab_parent') we can get the various revision-views to 38 * show the View|Edit|Revision-tabs of the node on top, and have the Revisions-tab open. 39 * To avoid creating/showing any extra tabs or sub-tabs (tasks below top level) for the 40 * various paths (i.e. "Diff", "Show latest" and "Show a specific revision") that need 41 * a revision-id (vid) parameter, we make sure to set 'tab_parent' a bit odd. 42 * This solution may not be the prettiest one, but by avoiding having two _LOCAL_TASKs 43 * sharing a parent that can be accessed by its full path, it seems to work as desired. 44 * Breadcrumbs work decently, at least the node link is among the crumbs. For some reason 45 * any breadcrumbs "before/above" the node is only seen at 'node/%node/revisions/%/view'. 46 */ 47 $items['node/%node/revisions/list'] = array( 48 // Not used directly, but was created to get the other menu items to work well 49 'title' => 'List revisions', 50 'page callback' => 'diff_diffs_overview', 51 'type' => MENU_DEFAULT_LOCAL_TASK, 52 'access callback' => 'diff_node_revision_access', 53 'access arguments' => array(1), 54 'file' => 'diff.pages.inc', 55 ); 56 $items['node/%node/revisions/view/%/%'] = array( 57 'title' => 'Diff', 58 'page callback' => 'diff_diffs_show', 59 'page arguments' => array(1, 4, 5), 60 'type' => MENU_LOCAL_TASK, 61 'access callback' => 'diff_node_revision_access', 62 'access arguments' => array(1), 63 'tab_parent' => 'node/%/revisions/list', 64 'file' => 'diff.pages.inc', 65 ); 66 $items['node/%node/revisions/view/latest'] = array( 67 'title' => 'Show latest diff', 68 'page callback' => 'diff_latest', 69 'page arguments' => array(1), 70 'type' => MENU_LOCAL_TASK, 71 'access callback' => 'diff_node_revision_access', 72 'access arguments' => array(1), 73 'tab_parent' => 'node/%/revisions/view', 74 'file' => 'diff.pages.inc', 75 ); 76 $items['node/%node/revisions/diff-inline'] = array( 77 'page callback' => 'diff_inline_ahah', 78 'page arguments' => array(1), 79 'type' => MENU_CALLBACK, 80 'access callback' => 'diff_node_revision_access', 81 'access arguments' => array(1), 82 'file' => 'diff.pages.inc', 83 ); 84 return $items; 85 } 86 87 /** 88 * Implementation of hook_menu_alter(). 89 */ 90 function diff_menu_alter(&$callbacks) { 91 // Overwrite the default 'Revisions' page 92 $callbacks['node/%node/revisions']['page callback'] = 'diff_diffs_overview'; 93 $callbacks['node/%node/revisions']['module'] = 'diff'; 94 $callbacks['node/%node/revisions']['file'] = 'diff.pages.inc'; 95 96 $callbacks['node/%node/revisions/%/view']['tab_parent'] = 'node/%/revisions/list'; 97 $callbacks['node/%node/revisions/%/revert']['tab_parent'] = 'node/%/revisions/%/view'; 98 $callbacks['node/%node/revisions/%/delete']['tab_parent'] = 'node/%/revisions/%/view'; 99 100 $callbacks['node/%node/revisions']['access callback'] = 101 $callbacks['node/%node/revisions/%/view']['access callback'] = 102 $callbacks['node/%node/revisions/%/revert']['access callback'] = 103 $callbacks['node/%node/revisions/%/delete']['access callback'] = 'diff_node_revision_access'; 104 return; 105 } 106 107 /** 108 * Access callback for the node revisions page. 109 */ 110 function diff_node_revision_access($node, $op = 'view') { 111 $may_revision_this_type = variable_get('enable_revisions_page_'. $node->type, TRUE) || user_access('administer nodes'); 112 return $may_revision_this_type && _node_revision_access($node, $op); 113 } 114 115 /** 116 * Implementation of hook_block(). 117 */ 118 function diff_block($op = 'list', $delta = 0, $edit = array()) { 119 if ($op === 'list') { 120 return array('inline' => array('info' => t('Inline diff'))); 121 } 122 elseif ($op === 'view' && $delta === 'inline' && user_access('view revisions') && $node = menu_get_object()) { 123 $block = array(); 124 $revisions = node_revision_list($node); 125 if (count($revisions) > 1) { 126 $block['subject'] = t('Highlight changes'); 127 $block['content'] = drupal_get_form('diff_inline_form', $node, $revisions); 128 } 129 return $block; 130 } 131 } 132 133 /** 134 * Implementation of hook_nodeapi(). 135 */ 136 function diff_nodeapi(&$node, $op, $teaser, $page) { 137 if ($page && $op == 'view' && user_access('view revisions') && variable_get('show_diff_inline_'. $node->type, FALSE)) { 138 // Ugly but cheap way to check that we are viewing a node's revision page. 139 if (arg(2) === 'revisions' && arg(3) === $node->vid) { 140 module_load_include('inc', 'diff', 'diff.pages'); 141 $old_vid = _diff_get_previous_vid(node_revision_list($node), $node->vid); 142 $node->content = array('#value' => diff_inline_show($node, $old_vid)); 143 } 144 $node->content['#prefix'] = isset($node->content['#prefix']) ? "<div id='diff-inline-{$node->nid}'>" . $node->content['#prefix'] : "<div id='diff-inline-{$node->nid}'>"; 145 $node->content['#suffix'] = isset($node->content['#suffix']) ? $node->content['#suffix'] . "</div>" : "</div>"; 146 } 147 } 148 149 /** 150 * Implementation of hook_form_alter(). 151 */ 152 function diff_form_alter(&$form, $form_state, $form_id) { 153 if (isset($form['type']['#value']) && $form['type']['#value'] .'_node_form' == $form_id) { 154 // Add a 'View changes' button on the node edit form. 155 if (variable_get('show_preview_changes_'. $form['type']['#value'], TRUE) && $form['nid']['#value'] > 0) { 156 $form['buttons']['preview_changes'] = array( 157 '#type' => 'submit', 158 '#value' => t('View changes'), 159 '#weight' => 12, 160 '#submit' => array('diff_node_form_build_preview_changes') 161 ); 162 } 163 } 164 elseif ($form_id == 'node_type_form' && isset($form['identity']['type'])) { 165 // Node type edit form. 166 // Add checkbox to activate 'View changes' button per node type. 167 $form['workflow']['diff'] = array( 168 '#title' => t('Diff'), 169 '#type' => 'item', 170 '#tree' => FALSE, 171 ); 172 $form['workflow']['diff']['show_preview_changes'] = array( 173 '#type' => 'checkbox', 174 '#title' => t('Show %preview_changes button on node edit form', array('%preview_changes' => t('View changes'))), 175 '#weight' => 10, 176 '#default_value' => variable_get('show_preview_changes_'. $form['#node_type']->type, TRUE), 177 ); 178 $form['workflow']['diff']['show_diff_inline'] = array( 179 '#type' => 'checkbox', 180 '#title' => t('Show diffs inline for this content type'), 181 '#description' => t("You must enable the 'Inline diff' block to use this feature"), 182 '#weight' => 10, 183 '#default_value' => variable_get('show_diff_inline_'. $form['#node_type']->type, FALSE), 184 ); 185 $form['workflow']['diff']['enable_revisions_page'] = array( 186 '#type' => 'checkbox', 187 '#title' => t('Enable the %revisions page for this content type', array('%revisions' => t('Revisions'))), 188 '#weight' => 11, 189 '#default_value' => variable_get('enable_revisions_page_'. $form['#node_type']->type, TRUE), 190 ); 191 } 192 } 193 194 /** 195 * Callback if 'View changes' is pressed. 196 */ 197 function diff_node_form_build_preview_changes($form, &$form_state) { 198 module_load_include('inc', 'diff', 'diff.pages'); 199 $node = node_form_submit_build_node($form, $form_state); 200 201 // Create diff of old node and edited node 202 $rows = _diff_body_rows(node_load($form_state['values']['nid']), $node); 203 $cols = _diff_default_cols(); 204 $header = _diff_default_header(); 205 $changes = theme('diff_table', $header, $rows, array('class' => 'diff'), NULL, $cols); 206 207 // Prepend diff to edit form 208 $form_state['node_preview'] = isset($form_state['node_preview']) ? $changes . $form_state['node_preview'] : $changes; 209 } 210 211 /** 212 * Implementation of hook_theme(). 213 */ 214 function diff_theme() { 215 return array( 216 'diff_node_revisions' => array( 217 'arguments' => array('form' => NULL), 218 'file' => 'diff.theme.inc', 219 ), 220 'diff_table' => array( 221 'arguments' => array('header' => NULL, 'rows' => NULL, 'attributes' => array(), 'caption' => NULL, 'cols' => array()), 222 'file' => 'diff.theme.inc', 223 ), 224 'diff_header_line' => array( 225 'arguments' => array('lineno' => NULL), 226 'file' => 'diff.theme.inc', 227 ), 228 'diff_content_line' => array( 229 'arguments' => array('line' => NULL), 230 'file' => 'diff.theme.inc', 231 ), 232 'diff_empty_line' => array( 233 'arguments' => array('line' => NULL), 234 'file' => 'diff.theme.inc', 235 ), 236 'diff_inline_form' => array( 237 'arguments' => array('form' => array()), 238 'file' => 'diff.theme.inc', 239 ), 240 'diff_inline_metadata' => array( 241 'arguments' => array(), 242 'file' => 'diff.theme.inc', 243 ), 244 'diff_inline_chunk' => array( 245 'arguments' => array('text' => '', 'type' => NULL), 246 'file' => 'diff.theme.inc', 247 ), 248 ); 249 } 250 251 /** 252 * Render a diff of two strings to a $rows array suitable for use with 253 * theme('table') or theme('diff_table'). 254 * 255 * @param string $a 256 * The source string to compare from. 257 * @param string $b 258 * The target string to compare to. 259 * @param boolean $show_header 260 * Display diff context headers, e.g. "Line x". 261 * @return 262 * Array of rows usable with theme('table'). 263 */ 264 function diff_get_rows($a, $b, $show_header = FALSE) { 265 module_load_include('php', 'diff', 'DiffEngine'); 266 $formatter = new DrupalDiffFormatter(); 267 $formatter->show_header = $show_header; 268 $diff = new Diff($a, $b); 269 return $formatter->format($diff); 270 } 271 272 /** 273 * Render a diff of two strings into HTML markup indicating additions, changes 274 * and deletions. 275 * 276 * @param string $a 277 * The source string to compare from. 278 * @param string $b 279 * The target string to compare to. 280 * @return 281 * String containing HTML markup. 282 */ 283 function diff_get_inline($a, $b) { 284 module_load_include('php', 'diff', 'DiffEngine'); 285 $diff = new DrupalDiffInline($a, $b); 286 return $diff->render(); 287 } 288 289 /** 290 * Form builder: Inline diff controls. 291 */ 292 function diff_inline_form($form_state, $node, $revisions) { 293 $form = array(); 294 $form['node'] = array( 295 '#type' => 'value', 296 '#value' => $node 297 ); 298 $form['revision'] = array( 299 '#type' => 'select', 300 '#options' => array(0 => '< '. t('No highlighting') . ' >'), 301 '#default_value' => (arg(2) === 'revisions' && arg(3) === $node->vid) ? $node->vid : 0, 302 '#ahah' => array( 303 'path' => "node/{$node->nid}/revisions/diff-inline", 304 'wrapper' => "diff-inline-{$node->nid}", 305 'method' => 'replace', 306 ), 307 ); 308 foreach ($revisions as $revision) { 309 $form['revision']['#options'][$revision->vid] = t('@revision by @name', array( 310 '@revision' => format_date($revision->timestamp, 'small'), 311 '@name' => $revision->name, 312 )); 313 } 314 $form['submit'] = array( 315 '#type' => 'submit', 316 '#value' => t('View'), 317 '#submit' => array('diff_inline_form_submit'), 318 '#attributes' => array('class' => 'diff-js-hidden'), 319 ); 320 return $form; 321 } 322 323 /** 324 * Form submission handler for diff_inline_form() for JS-disabled clients. 325 */ 326 function diff_inline_form_submit(&$form, &$form_state) { 327 if (isset($form_state['values']['revision'], $form_state['values']['node'])) { 328 $node = $form_state['values']['node']; 329 $vid = $form_state['values']['revision']; 330 $form_state['redirect'] = "node/{$node->nid}/revisions/{$vid}/view"; 331 } 332 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |