? diff_inline.patch.txt Index: diff.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/diff/diff.css,v retrieving revision 1.7 diff -u -p -r1.7 diff.css --- diff.css 30 Jan 2008 18:34:13 -0000 1.7 +++ diff.css 25 Jan 2009 17:50:13 -0000 @@ -1,5 +1,41 @@ /* $Id: diff.css,v 1.7 2008/01/30 18:34:13 weitzman Exp $ */ +/** + * Inline form theming + */ +div.diff-inline-form { + margin:10px 0px; + background:#f4f4f4; + padding:5px; + } + +div.diff-inline-form div.form-item { + float:left; + margin:0px 10px 0px 0px; + } + +div.diff-inline-form div.form-item * { + vertical-align:middle; + } + +div.diff-inline-form input.form-submit { + float:right; + } + +/** + * Inline diff markup + */ +span.diff-deleted { + color:#ccc; + } + +span.diff-changed { + background:#ffb; + } + +/** + * Traditional split diff theming + */ table.diff { border-spacing: 4px; margin-bottom: 20px; Index: diff.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/diff/diff.module,v retrieving revision 1.23.2.3.2.7 diff -u -p -r1.23.2.3.2.7 diff.module --- diff.module 31 Aug 2008 20:32:18 -0000 1.23.2.3.2.7 +++ diff.module 25 Jan 2009 17:50:13 -0000 @@ -65,6 +65,139 @@ function diff_menu_alter(&$callbacks) { } /** + * Form for selecting two consecutive revisions for inline diff'ing. + */ +function diff_inline_form($form_state, $node, $revisions) { + $form = array(); + + $rev = count($revisions); + $pad_length = strlen($rev); + + // Build list of revisions. Label using sequential numbers instead of vids + // for easier reading. + $options = array(); + foreach ($revisions as $r) { + $options[$r->vid] = t("#!num by !name", array('!num' => str_pad($rev, $pad_length, '0', STR_PAD_LEFT), '!date' => format_date($r->timestamp, 'small'), '!name' => $r->name)); + $rev--; + } + + $form['nid'] = array( + '#type' => 'value', + '#value' => $node->nid, + ); + $form['vid'] = array( + '#type' => 'select', + '#options' => $options, + '#default_value' => $node->vid, + ); + $form['hilight'] = array( + '#title' => t('Hilight changes'), + '#type' => 'checkbox', + '#default_value' => !empty($_SESSION['diff_inline_hilight']) ? TRUE : FALSE, + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('View revision'), + '#submit' => array('diff_inline_form_submit'), + ); + $form['#theme'] = 'diff_inline_form'; + + return $form; +} + +/** + * Diff inline form submit handler. Retrieves node/revision information and + * directs user to the correct node revision page. + */ +function diff_inline_form_submit(&$form, &$form_state) { + $_SESSION['diff_inline_hilight'] = $form_state['values']['hilight']; + $form_state['redirect'] = "node/{$form_state['values']['nid']}/revisions/{$form_state['values']['vid']}/view"; +} + +/** + * Theme function for diff inline forms. + */ +function theme_diff_inline_form($form) { + $output = "
". drupal_render($form) ."
"; + return $output; +} + +/** + * Implementation of hook_nodeapi(). + */ +function diff_nodeapi(&$node, $op, $teaser, $page) { + switch ($op) { + case 'view': + if ($page && user_access('view revisions') && variable_get('show_diff_inline_'. $node->type, FALSE)) { + $revisions = node_revision_list($node); + + // Only render the form if there are multiple revisions + if (count($revisions) > 1) { + drupal_add_css(drupal_get_path('module', 'diff') .'/diff.css', 'module', 'all', FALSE); + $node->content['diff_inline'] = array( + '#value' => drupal_get_form('diff_inline_form', $node, $revisions), + '#weight' => -100, + ); + + $vids = array_keys($revisions); + $position = array_search($node->vid, $vids) + 1; + $old = isset($vids[$position]) ? $vids[$position] : NULL; + + // Only hilight changes if inline hilighting is enabled & there + // is actually an older revision to diff against. + if ($old && (!isset($_SESSION['diff_inline_hilight']) || !empty($_SESSION['diff_inline_hilight']))) { + module_load_include('php', 'diff', 'DiffEngine'); + $new = drupal_clone($node); + + // We could use a node_load() / node_prepare() combo here but for now + // we would rather save queries... + $old = db_fetch_object(db_query("SELECT body, format FROM {node_revisions} WHERE nid = %d AND vid = %d", $node->nid, $old)); + $old->body = check_markup($old->body, $old->format, FALSE); + + $new = preg_split('/(<[^>]+?>)/', $new->body, -1, PREG_SPLIT_DELIM_CAPTURE); + $old = preg_split('/(<[^>]+?>)/', $old->body, -1, PREG_SPLIT_DELIM_CAPTURE); + + $diff = new Diff($old, $new); + + // Assemble hilighted output + $output = ''; + foreach ($diff->edits as $chunk) { + switch ($chunk->type) { + case 'copy': + $output .= implode("", $chunk->closing); + break; + case 'add': + case 'change': + foreach ($chunk->closing as $i =>$piece) { + if (strpos($piece, '<') === 0 && substr($piece, strlen($piece) - 1) === '>') { + $output .= $piece; + } + else { + $output .= "{$piece}"; + } + } + break; + default: + foreach ($chunk->orig as $i =>$piece) { + if (strpos($piece, '<') === 0 && substr($piece, strlen($piece) - 1) === '>') { + $output .= $piece; + } + else { + $output .= "{$piece}"; + } + } + break; + } + } + $node->content['body']['#value'] = $output; + } + } + } + break; + } +} + +/** * Generate an overview table of older revisions of a node and provide * an input form to select two revisions for a comparison. */ @@ -480,6 +613,14 @@ function diff_form_alter(&$form, $form_s '#weight' => 10, '#default_value' => variable_get('show_preview_changes_'. $form['#node_type']->type, TRUE), ); + // Add checkbox to present inline diff forms and hilighting to users. + $form['workflow']['show_diff_inline'] = array( + '#type' => 'checkbox', + '#title' => t('Show diffs inline for this content type'), + '#weight' => 10, + '#prefix' => "". t('Inline diffs') ."", + '#default_value' => variable_get('show_diff_inline_'. $form['#node_type']->type, FALSE), + ); } } @@ -739,6 +880,9 @@ function diff_theme() { 'diff_empty_line' => array( 'arguments' => array('line' => NULL), ), + 'diff_inline_form' => array( + 'arguments' => array('form' => NULL), + ), ); }