? 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),
+ ),
);
}