]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/diff.php
Fix Carsten's example translation problem using new __sprintf() function.
[SourceForge/phpwiki.git] / lib / diff.php
1 <?php
2 rcs_id('$Id: diff.php,v 1.23 2001-12-19 05:07:14 dairiki Exp $');
3 // diff.php
4 //
5 // PhpWiki diff output code.
6 //
7 // Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
8 // You may copy this code freely under the conditions of the GPL.
9 //
10
11 require_once('lib/difflib.php');
12
13 /**
14  * HTML unified diff formatter.
15  *
16  * This class formats a diff into a CSS-based
17  * unified diff format.
18  *
19  * Within groups of changed lines, diffs are highlit
20  * at the character-diff level.
21  */
22 class HtmlUnifiedDiffFormatter extends UnifiedDiffFormatter
23 {
24     function HtmlUnifiedDiffFormatter($context_lines = 4) {
25         $this->UnifiedDiffFormatter($context_lines);
26     }
27
28     function _start_diff() {
29         echo "<div class='diff'>\n";
30     }
31     function _end_diff() {
32         echo "</div>\n";
33     }
34     
35     function _start_block($header) {
36         echo "<div class='block'>\n";
37         echo QElement('tt', $header);
38     }
39
40     function _end_block() {
41         echo "</div>\n";
42     }
43
44     function _lines($lines, $class, $prefix = '&nbsp;', $elem = false) {
45         foreach ($lines as $line) {
46             if ($elem)
47                 $line = QElement($elem, $line);
48                     
49             echo Element('div', array('class' => $class),
50                          Element('tt', array('class' => 'prefix'), $prefix)
51                          . " $line&nbsp;") . "\n";
52         }
53     }
54
55     function _context($lines) {
56         $this->_lines($lines, 'context');
57     }
58     function _deleted($lines) {
59         $this->_lines($lines, 'deleted', '-', 'del');
60     }
61
62     function _added($lines) {
63         $this->_lines($lines, 'added', '+', 'ins');
64     }
65
66     function _pack($bits, $tag) {
67         $packed = htmlspecialchars(implode("", $bits));
68         return "<$tag>"
69             . str_replace("\n", "<tt>&nbsp;</tt></$tag>\n<$tag>",
70                           $packed)
71             . "</$tag>";
72     }
73
74     function _split($lines) {
75         preg_match_all('/ ( [^\S\n]+ | [[:alnum:]]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
76                        implode("\n", $lines),
77                        $m);
78         return array($m[0], $m[1]);
79     }
80     
81     function _changed($orig, $final) {
82         list ($orig_words, $orig_stripped) = $this->_split($orig);
83         list ($final_words, $final_stripped) = $this->_split($final);
84         
85         // Compute character-wise diff in changed region.
86         $diff = new MappedDiff($orig_words, $final_words,
87                                $orig_stripped, $final_stripped);
88
89         $orig = $final = '';
90         foreach ($diff->edits as $edit) {
91             if ($edit->type == 'copy') {
92                 $orig .= implode('', $edit->orig);
93                 $final .= implode('', $edit->final);
94             }
95             else {
96                 if ($edit->orig)
97                     $orig .= $this->_pack($edit->orig, 'del');
98                 if ($edit->final)
99                     $final .= $this->_pack($edit->final, 'ins');
100             }
101         }
102
103         $this->_lines(explode("\n", $orig),  'original', '-');
104         $this->_lines(explode("\n", $final), 'final', '+');
105     }
106 }
107
108 /**
109  * HTML table-based unified diff formatter.
110  *
111  * This class formats a diff into a table-based
112  * unified diff format.  (Similar to what was produced
113  * by previous versions of PhpWiki.)
114  *
115  * Within groups of changed lines, diffs are highlit
116  * at the character-diff level.
117  */
118 class TableUnifiedDiffFormatter extends HtmlUnifiedDiffFormatter
119 {
120     function TableUnifiedDiffFormatter($context_lines = 4) {
121         $this->HtmlUnifiedDiffFormatter($context_lines);
122     }
123
124     function _start_diff() {
125         echo "\n<table width='100%' class='diff'";
126         echo " cellspacing='1' cellpadding='1' border='1'>\n";
127     }
128     function _end_diff() {
129         echo "</table>\n";
130     }
131     
132     function _start_block($header) {
133         echo "<tr><td><table width='100%' class='block'";
134         echo " cellspacing='0' cellpadding='1' border='0'>\n";
135         echo Element('tr',
136                      Element('td', array('colspan' => 2),
137                              QElement('tt', $header))) . "\n";
138     }
139
140     function _end_block() {
141         echo "</table></td></tr>\n";
142     }
143
144     function _lines($lines, $class, $prefix = '&nbsp;', $elem = false) {
145         $prefix = Element('td', array('class' => 'prefix', 'width' => "1%"), $prefix);
146         foreach ($lines as $line) {
147             if (! trim($line))
148                 $line = '&nbsp';
149             elseif ($elem)
150                 $line = QElement($elem, $line);
151
152             echo Element('tr', array('valign' => 'top'), 
153                          $prefix . Element('td', array('class' => $class),
154                                            $line)) . "\n";
155         }
156     }
157 }
158
159     
160 /////////////////////////////////////////////////////////////////
161
162 function PageInfoRow ($pagename, $label, $rev)
163 {
164    global $datetimeformat;
165    
166    $cols = QElement('td', array('align' => 'right'), $label);
167    
168    if ($rev) {
169        $url = WikiURL($pagename, array('version' => $rev->getVersion()));
170        $linked_version = QElement('a', array('href' => $url), $rev->getVersion());
171        $cols .= Element('td',
172                         _("version") . " " . $linked_version);
173
174        $cols .= QElement('td',
175                          sprintf(_("last modified on %s"),
176                                  strftime($datetimeformat, $rev->get('mtime'))));
177        $cols .= QElement('td',
178                          sprintf(_("by %s"), $rev->get('author')));
179    } else {
180        $cols .= QElement('td', array('colspan' => '3'), _("None"));
181    }
182    return Element('tr', $cols);
183 }
184
185 function showDiff ($dbi, $request) {
186     $pagename = $request->getArg('pagename');
187     if (is_array($versions = $request->getArg('versions'))) {
188         // Version selection from pageinfo.php display:
189         rsort($versions);
190         list ($version, $previous) = $versions;
191     }
192     else {
193         $version = $request->getArg('version');
194         $previous = $request->getArg('previous');
195     }
196     
197     $page = $dbi->getPage($pagename);
198     if ($version) {
199         if (!($new = $page->getRevision($version)))
200             NoSuchRevision($page, $version);
201         $new_version = sprintf(_("version %d"), $version);
202     }
203     else {
204         $new = $page->getCurrentRevision();
205         $new_version = _("current version");
206     }
207
208     if (preg_match('/^\d+$/', $previous)) {
209         if ( !($old = $page->getRevision($previous)) )
210             NoSuchRevision($page, $previous);
211         $old_version = sprintf(_("version %d"), $previous);
212         $others = array('major', 'minor', 'author');
213     }
214     else {
215         switch ($previous) {
216         case 'major':
217             $old = $new;
218             while ($old = $page->getRevisionBefore($old)) {
219                 if (! $old->get('is_minor_edit'))
220                     break;
221             }
222             $old_version = _("previous major revision");
223             $others = array('minor', 'author');
224             break;
225         case 'author':
226             $old = $new;
227             while ($old = $page->getRevisionBefore($old)) {
228                 if ($old->get('author') != $new->get('author'))
229                     break;
230             }
231             $old_version = _("revision by previous author");
232             $others = array('major', 'minor');
233             break;
234         case 'minor':
235         default:
236             $previous='minor';
237             $old = $page->getRevisionBefore($new);
238             $old_version = _("previous revision");
239             $others = array('major', 'author');
240             break;
241         }
242     }
243
244     $new_url = WikiURL($pagename, array('version' => $new->getVersion()));
245     $new_link = QElement('a', array('href' => $new_url), $new_version);
246     $old_url = WikiURL($pagename, array('version' => $old ? $old->getVersion() : 0));
247     $old_link = QElement('a', array('href' => $old_url), $old_version);
248     $page_link = LinkExistingWikiWord($pagename);
249     
250     $html = Element('p',
251                     __sprintf("Differences between %s and %s of %s.",
252                               $new_link, $old_link, $page_link));
253
254     $otherdiffs='';
255     $label = array('major' => _("Previous Major Revision"),
256                    'minor' => _("Previous Revision"),
257                    'author'=> _("Previous Author"));
258     foreach ($others as $other) {
259         $args = array('action' => 'diff', 'previous' => $other);
260         if ($version)
261             $args['version'] = $version;
262         $otherdiffs .= ', ' . QElement('a', array('href' => WikiURL($pagename, $args),
263                                                  'class' => 'wikiaction'),
264                                       $label[$other]);
265     }
266     $html .= Element('p',
267                      htmlspecialchars(_("Other diffs:"))
268                      . $otherdiffs . '.');
269             
270             
271     if ($old and $old->getVersion() == 0)
272         $old = false;
273     
274     $html .= Element('table',
275                     PageInfoRow($pagename, _("Newer page:"), $new)
276                     . PageInfoRow($pagename, _("Older page:"), $old));
277
278
279     if ($new && $old) {
280         $diff = new Diff($old->getContent(), $new->getContent());
281         
282         if ($diff->isEmpty()) {
283             $html .= Element('hr');
284             $html .= QElement('p', '[' . _("Versions are identical") . ']');
285         }
286         else {
287             // New CSS formatted unified diffs (ugly in NS4).
288             $fmt = new HtmlUnifiedDiffFormatter;
289
290             // Use this for old table-formatted diffs.
291             //$fmt = new TableUnifiedDiffFormatter;
292             $html .= $fmt->format($diff);
293         }
294     }
295     
296     include_once('lib/Template.php');
297     echo GeneratePage('MESSAGE', $html,
298                       sprintf(_("Diff: %s"), $pagename));
299 }
300   
301 // Local Variables:
302 // mode: php
303 // tab-width: 8
304 // c-basic-offset: 4
305 // c-hanging-comment-ender-p: nil
306 // indent-tabs-mode: nil
307 // End:   
308 ?>