2 rcs_id('$Id: diff.php,v 1.18 2001-12-13 18:29:24 dairiki Exp $');
5 // PhpWiki diff output code.
7 // Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
8 // You may copy this code freely under the conditions of the GPL.
11 require_once('lib/difflib.php');
13 class HtmlUnifiedDiffFormatter extends UnifiedDiffFormatter
15 function HtmlUnifiedDiffFormatter($context_lines = 4) {
16 $this->UnifiedDiffFormatter($context_lines);
19 function _start_diff() {
20 echo "<div class='diff'>\n";
22 function _end_diff() {
26 function _start_block($header) {
27 echo "<div class='block'>\n";
28 echo QElement('tt', $header);
31 function _end_block() {
35 function _lines($lines, $class, $prefix = ' ', $elem = false) {
36 foreach ($lines as $line) {
40 $line = QElement($elem, $line);
42 echo Element('div', array('class' => $class),
43 Element('tt', array('class' => 'prefix'), $prefix)
48 function _context($lines) {
49 $this->_lines($lines, 'context');
51 function _deleted($lines) {
52 $this->_lines($lines, 'deleted', '-', 'del');
54 function _added($lines) {
55 $this->_lines($lines, 'added', '+', 'ins');
58 function _pack_in_span($chars, $elem) {
61 foreach ($chars as $c) {
68 $end_span = "</$elem>";
70 $packed .= htmlspecialchars($c);
72 return $packed . $end_span;
75 function _split_to_chars($lines) {
76 // Split into characters --- there must be a better way ...
77 $joined = implode("\n", $lines);
79 for ($i = 0; $i < strlen($joined); $i++)
80 $split[$i] = $joined[$i];
85 function _changed($orig, $final) {
86 // Compute character-wise diff in changed region.
87 $diff = new Diff($this->_split_to_chars($orig),
88 $this->_split_to_chars($final));
91 foreach ($diff->edits as $edit) {
92 switch ($edit->type) {
94 $packed = implode('', $edit->orig);
99 $final .= $this->_pack_in_span($edit->final, 'ins');
102 $orig .= $this->_pack_in_span($edit->orig, 'del');
105 $orig .= $this->_pack_in_span($edit->orig, 'del');
106 $final .= $this->_pack_in_span($edit->final, 'ins');
111 $this->_lines(explode("\n", $orig), 'changed', '-');
112 $this->_lines(explode("\n", $final), 'changed', '+');
116 class TableUnifiedDiffFormatter extends HtmlUnifiedDiffFormatter
118 function TableUnifiedDiffFormatter($context_lines = 4) {
119 $this->HtmlUnifiedDiffFormatter($context_lines);
122 function _start_diff() {
123 echo "\n<table width='100%' class='diff'";
124 echo " cellspacing='1' cellpadding='1' border='1'>\n";
126 function _end_diff() {
130 function _start_block($header) {
131 echo "<tr><td><table width='100%' class='block'";
132 echo " cellspacing='0' cellpadding='1' border='0'>\n";
134 Element('td', array('colspan' => 2),
135 QElement('tt', $header))) . "\n";
138 function _end_block() {
139 echo "</table></td></tr>\n";
142 function _lines($lines, $class, $prefix = ' ', $elem = false) {
143 $prefix = Element('td', array('class' => 'prefix', 'width' => "1%"), $prefix);
144 foreach ($lines as $line) {
148 $line = QElement($elem, $line);
150 echo Element('tr', array('valign' => 'top'),
151 $prefix . Element('td', array('class' => $class),
158 /////////////////////////////////////////////////////////////////
160 function PageInfoRow ($pagename, $label, $rev)
162 global $datetimeformat;
164 $cols = QElement('td', array('align' => 'right'), $label);
167 $url = WikiURL($pagename, array('version' => $rev->getVersion()));
168 $linked_version = QElement('a', array('href' => $url), $rev->getVersion());
169 $cols .= Element('td',
170 gettext("version") . " " . $linked_version);
172 $cols .= QElement('td',
173 sprintf(gettext ("last modified on %s"),
174 strftime($datetimeformat, $rev->get('mtime'))));
175 $cols .= QElement('td',
176 sprintf(gettext ("by %s"), $rev->get('author')));
178 $cols .= QElement('td', array('colspan' => '3'),
181 return Element('tr', $cols);
184 function showDiff ($dbi, $request) {
185 $pagename = $request->getArg('pagename');
186 if (is_array($versions = $request->getArg('versions'))) {
187 // Version selection from pageinfo.php display:
189 list ($version, $previous) = $versions;
192 $version = $request->getArg('version');
193 $previous = $request->getArg('previous');
196 $page = $dbi->getPage($pagename);
198 if (!($new = $page->getRevision($version)))
199 NoSuchRevision($page, $version);
200 $new_version = sprintf(gettext("version %d"), $version);
203 $new = $page->getCurrentRevision();
204 $new_version = gettext('current version');
207 if (preg_match('/^\d+$/', $previous)) {
208 if ( !($old = $page->getRevision($previous)) )
209 NoSuchRevision($page, $previous);
210 $old_version = sprintf(gettext("version %d"), $previous);
211 $others = array('major', 'minor', 'author');
217 while ($old = $page->getRevisionBefore($old)) {
218 if (! $old->get('is_minor_edit'))
221 $old_version = gettext("previous major revision");
222 $others = array('minor', 'author');
226 while ($old = $page->getRevisionBefore($old)) {
227 if ($old->get('author') != $new->get('author'))
230 $old_version = gettext("revision by previous author");
231 $others = array('major', 'minor');
236 $old = $page->getRevisionBefore($new);
237 $old_version = gettext("previous revision");
238 $others = array('major', 'author');
243 $new_url = WikiURL($pagename, array('version' => $new->getVersion()));
244 $new_link = QElement('a', array('href' => $new_url), $new_version);
245 $old_url = WikiURL($pagename, array('version' => $old ? $old->getVersion() : 0));
246 $old_link = QElement('a', array('href' => $old_url), $old_version);
247 $page_link = LinkExistingWikiWord($pagename);
250 sprintf(htmlspecialchars(gettext("Differences between %s and %s of %s.")),
251 $new_link, $old_link, $page_link));
254 $label = array('major' => gettext("Previous Major Revision"),
255 'minor' => gettext("Previous Revision"),
256 'author'=> gettext("Previous Author"));
257 foreach ($others as $other) {
258 $args = array('action' => 'diff', 'previous' => $other);
260 $args['version'] = $version;
261 $otherdiffs .= ' ' . QElement('a', array('href' => WikiURL($pagename, $args),
262 'class' => 'wikiaction'),
265 $html .= Element('p',
266 htmlspecialchars(gettext("Other diffs:"))
270 if ($old and $old->getVersion() == 0)
273 $html .= Element('table',
274 PageInfoRow($pagename, gettext ("Newer page:"), $new)
275 . PageInfoRow($pagename, gettext ("Older page:"), $old));
279 $diff = new Diff($old->getContent(), $new->getContent());
281 if ($diff->isEmpty()) {
282 $html .= Element('hr');
283 $html .= QElement('p', '[' . gettext ("Versions are identical") . ']');
286 // New CSS formatted unified diffs (ugly in NS4).
287 $fmt = new HtmlUnifiedDiffFormatter;
289 // Use this for old table-formatted diffs.
290 //$fmt = new TableUnifiedDiffFormatter;
291 $html .= $fmt->format($diff);
295 include_once('lib/Template.php');
296 echo GeneratePage('MESSAGE', $html,
297 sprintf(gettext ("Diff: %s"), $pagename));
304 // c-hanging-comment-ender-p: nil
305 // indent-tabs-mode: nil