]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/RecentChanges.php
Normalize header
[SourceForge/phpwiki.git] / lib / plugin / RecentChanges.php
1 <?php // -*-php-*-
2 rcs_id('$Id$');
3 /**
4  * Copyright 1999,2000,2001,2002,2007 $ThePhpWikiProgrammingTeam
5  * Copyright 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
6  *
7  * This file is part of PhpWiki.
8  *
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with PhpWiki; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 include_once("lib/WikiPlugin.php");
25
26 class _RecentChanges_Formatter
27 {
28     var $_absurls = false;
29     var $action = "RecentChanges";
30
31     function _RecentChanges_Formatter ($rc_args) {
32         $this->_args = $rc_args;
33         $this->_diffargs = array('action' => 'diff');
34
35         if ($rc_args['show_minor'] || !$rc_args['show_major'])
36             $this->_diffargs['previous'] = 'minor';
37
38         // PageHistoryPlugin doesn't have a 'daylist' arg.
39         if (!isset($this->_args['daylist']))
40             $this->_args['daylist'] = false;
41     }
42
43     function title () {
44         global $request;
45         extract($this->_args);
46         if ($author) {
47             $title = $author;
48             if ($title == '[]') {
49                 $title = $request->_user->getID();
50             }
51             $title = _("UserContribs").": $title";
52         } elseif ($owner) {
53             $title = $owner;
54             if ($title == '[]') {
55                 $title = $request->_user->getID();
56             }
57             $title = _("UserContribs").": $title";
58         } elseif ($only_new) {
59             $title = _("RecentNewPages");
60         } elseif ($show_minor) {
61             $title = _("RecentEdits");
62         } else $title = _("RecentChanges");
63
64         if (!empty($category))
65             $title = $category;
66         elseif (!empty($pagematch))
67             $title .= ":$pagematch";
68         return $title;
69     }
70
71     function include_versions_in_URLs() {
72         return (bool) $this->_args['show_all'];
73     }
74
75     function date ($rev) {
76         global $WikiTheme;
77         return $WikiTheme->getDay($rev->get('mtime'));
78     }
79
80     function time ($rev) {
81         global $WikiTheme;
82         return $WikiTheme->formatTime($rev->get('mtime'));
83     }
84
85     function diffURL ($rev) {
86         $args = $this->_diffargs;
87         if ($this->include_versions_in_URLs())
88             $args['version'] = $rev->getVersion();
89         $page = $rev->getPage();
90         return WikiURL($page->getName(), $args, $this->_absurls);
91     }
92
93     function historyURL ($rev) {
94         $page = $rev->getPage();
95         return WikiURL($page, array('action' => _("PageHistory")),
96                        $this->_absurls);
97     }
98
99     function pageURL ($rev) {
100         return WikiURL($this->include_versions_in_URLs() ? $rev : $rev->getPage(),
101                        '', $this->_absurls);
102     }
103
104     function authorHasPage ($author) {
105         global $WikiNameRegexp, $request;
106         $dbi = $request->getDbh();
107         return isWikiWord($author) && $dbi->isWikiPage($author);
108     }
109
110     function authorURL ($author) {
111         return $this->authorHasPage() ? WikiURL($author) : false;
112     }
113
114
115     function status ($rev) {
116         if ($rev->hasDefaultContents())
117             return 'deleted';
118         $page = $rev->getPage();
119         $prev = $page->getRevisionBefore($rev->getVersion());
120         if ($prev->hasDefaultContents())
121             return 'new';
122         return 'updated';
123     }
124
125     function importance ($rev) {
126         return $rev->get('is_minor_edit') ? 'minor' : 'major';
127     }
128
129     function summary($rev) {
130         if ( ($summary = $rev->get('summary')) )
131             return $summary;
132
133         switch ($this->status($rev)) {
134             case 'deleted':
135                 return _("Deleted");
136             case 'new':
137                 return _("New page");
138             default:
139                 return '';
140         }
141     }
142
143     function setValidators($most_recent_rev) {
144         $rev = $most_recent_rev;
145         $validators = array('RecentChanges-top' =>
146                             array($rev->getPageName(), $rev->getVersion()),
147                             '%mtime' => $rev->get('mtime'));
148         global $request;
149         $request->appendValidators($validators);
150     }
151 }
152
153 class _RecentChanges_HtmlFormatter
154 extends _RecentChanges_Formatter
155 {
156     function diffLink ($rev) {
157         global $WikiTheme;
158         $button = $WikiTheme->makeButton(_("diff"), $this->diffURL($rev), 'wiki-rc-action');
159         $button->setAttr('rel', 'nofollow');
160         return HTML("(",$button,")");
161     }
162
163     /* deletions: red, additions: green */
164     function diffSummary ($rev) {
165         $html = $this->diffURL($rev);
166         return '';
167     }
168
169     function historyLink ($rev) {
170         global $WikiTheme;
171         $button = $WikiTheme->makeButton(_("hist"), $this->historyURL($rev), 'wiki-rc-action');
172         $button->setAttr('rel', 'nofollow');
173         return HTML("(",$button,")");
174     }
175
176     function pageLink ($rev, $link_text=false) {
177
178         return WikiLink($this->include_versions_in_URLs() ? $rev : $rev->getPage(),
179                         'auto', $link_text);
180         /*
181         $page = $rev->getPage();
182         global $WikiTheme;
183         if ($this->include_versions_in_URLs()) {
184             $version = $rev->getVersion();
185             if ($rev->isCurrent())
186                 $version = false;
187             $exists = !$rev->hasDefaultContents();
188         }
189         else {
190             $version = false;
191             $cur = $page->getCurrentRevision();
192             $exists = !$cur->hasDefaultContents();
193         }
194         if ($exists)
195             return $WikiTheme->linkExistingWikiWord($page->getName(), $link_text, $version);
196         else
197             return $WikiTheme->linkUnknownWikiWord($page->getName(), $link_text);
198         */
199     }
200
201     function authorLink ($rev) {
202         return WikiLink($rev->get('author'), 'if_known');
203     }
204
205     /* Link to all users contributions (contribs and owns) */
206     function authorContribs ($rev) {
207         $author = $rev->get('author');
208         if (preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $author)) return '';
209         return HTML('(',
210                     Button(array('action' => _("RecentChanges"), 
211                                  'format' => 'contribs',
212                                  'author' => $author,
213                                  'days' => 360),
214                            _("contribs"),
215                            $author),
216                     ' | ',
217                     Button(array('action' => _("RecentChanges"), 
218                                  'format' => 'contribs',
219                                  'owner' => $author,
220                                  'days' => 360),
221                            _("new pages"),
222                            $author),
223                     ')');
224     }
225
226     function summaryAsHTML ($rev) {
227         if ( !($summary = $this->summary($rev)) )
228             return '';
229         return  HTML::span( array('class' => 'wiki-summary'),
230                             "(",
231                             TransformLinks($summary, $rev->get('markup'), $rev->getPageName()),
232                             ")");
233     }
234
235     function format_icon ($format, $filter = array()) {
236         global $request, $WikiTheme;
237         $args = $this->_args;
238         // remove links not used for those formats
239         unset($args['daylist']);
240         unset($args['difflinks']);
241         unset($args['historylinks']);
242         $rss_url = $request->getURLtoSelf
243                 (array_merge($args,
244                              array('action' => $this->action, 'format' => $format), 
245                              $filter));
246         return $WikiTheme->makeButton($format, $rss_url, 'rssicon');
247     }
248
249     function rss_icon ($args=array())  { return $this->format_icon("rss", $args); }
250     function rss2_icon ($args=array()) { return $this->format_icon("rss2", $args); }
251     function atom_icon ($args=array()) { return $this->format_icon("atom", $args); }
252     function rdf_icon ($args=array())  { return DEBUG ? $this->format_icon("rdf", $args) : ''; }
253     function rdfs_icon ($args=array()) { return DEBUG ? $this->format_icon("rdfs", $args) : ''; }
254     function owl_icon ($args=array())  { return DEBUG ? $this->format_icon("owl", $args) : ''; }
255
256     function grazr_icon ($args = array()) {
257         global $request, $WikiTheme;
258         if (is_localhost()) return '';
259         if (SERVER_PROTOCOL == "https") return '';
260         $our_url = WikiURL($request->getArg('pagename'),
261                     array_merge(array('action' => $this->action, 'format' => 'rss2'), $args), 
262                     true);
263         $rss_url = 'http://grazr.com/gzpanel.html?' . $our_url;
264         return $WikiTheme->makeButton("grazr", $rss_url, 'rssicon');
265     }
266
267     function pre_description () {
268         extract($this->_args);
269         // FIXME: say something about show_all.
270         if ($show_major && $show_minor)
271             $edits = _("edits");
272         elseif ($show_major)
273             $edits = _("major edits");
274         else
275             $edits = _("minor edits");
276         if (isset($caption) and $caption == _("Recent Comments"))
277             $edits = _("comments");
278         if (!empty($only_new)) {
279             $edits = _("created new pages");
280         }
281         if (!empty($author)) {
282             global $request;
283             if ($author == '[]')
284                 $author = $request->_user->getID();
285             $edits .= sprintf(_(" for pages changed by %s"), $author);
286         }
287         if (!empty($owner)) {
288             global $request;
289             if ($owner == '[]')
290                 $owner = $request->_user->getID();
291             $edits .= sprintf(_(" for pages owned by %s"), $owner);
292         }
293         if (!empty($category)) {
294             $edits .= sprintf(_(" for all pages linking to %s"), $category);
295         }
296         if (!empty($pagematch)) {
297             $edits .= sprintf(_(" for all pages matching '%s'"), $pagematch);
298         }
299         if ($timespan = $days > 0) {
300             if (intval($days) != $days)
301                 $days = sprintf("%.1f", $days);
302         }
303         $lmt = abs($limit);
304         /**
305          * Depending how this text is split up it can be tricky or
306          * impossible to translate with good grammar. So the seperate
307          * strings for 1 day and %s days are necessary in this case
308          * for translating to multiple languages, due to differing
309          * overlapping ideal word cutting points.
310          *
311          * en: day/days "The %d most recent %s [during (the past] day) are listed below."
312          * de: 1 Tag    "Die %d jüngste %s [innerhalb (von des letzten] Tages) sind unten aufgelistet."
313          * de: %s days  "Die %d jüngste %s [innerhalb (von] %s Tagen) sind unten aufgelistet."
314          *
315          * en: day/days "The %d most recent %s during [the past] (day) are listed below."
316          * fr: 1 jour   "Les %d %s les plus récentes pendant [le dernier (d'une] jour) sont Ã©numérées ci-dessous."
317          * fr: %s jours "Les %d %s les plus récentes pendant [les derniers (%s] jours) sont Ã©numérées ci-dessous."
318          */
319         if ($limit > 0) {
320             if ($timespan) {
321                 if (intval($days) == 1)
322                     $desc = fmt("The %d most recent %s during the past day are listed below.",
323                                 $limit, $edits);
324                 else
325                     $desc = fmt("The %d most recent %s during the past %s days are listed below.",
326                                 $limit, $edits, $days);
327             } else
328                 $desc = fmt("The %d most recent %s are listed below.",
329                             $limit, $edits);
330         }
331         elseif ($limit < 0) {  //$limit < 0 means we want oldest pages
332             if ($timespan) {
333                 if (intval($days) == 1)
334                     $desc = fmt("The %d oldest %s during the past day are listed below.",
335                                 $lmt, $edits);
336                 else
337                     $desc = fmt("The %d oldest %s during the past %s days are listed below.",
338                                 $lmt, $edits, $days);
339             } else
340                 $desc = fmt("The %d oldest %s are listed below.",
341                             $lmt, $edits);
342         }
343
344         else {
345             if ($timespan) {
346                 if (intval($days) == 1)
347                     $desc = fmt("The most recent %s during the past day are listed below.",
348                                 $edits);
349                 else
350                     $desc = fmt("The most recent %s during the past %s days are listed below.",
351                                 $edits, $days);
352             } else
353                 $desc = fmt("All %s are listed below.", $edits);
354         }
355         return $desc;
356     }    
357
358     function description() {
359         return HTML::p(false, $this->pre_description());
360     }
361
362     /* was title */
363     function headline () {
364         extract($this->_args);
365         return array($this->title(),
366                      ' ',
367                      $this->rss_icon(), 
368                      $this->rss2_icon(),
369                      $this->atom_icon(),
370                      $this->rdf_icon(),
371                      /*$this->rdfs_icon(),
372                        $this->owl_icon(),*/
373                      $this->grazr_icon(),
374                      $this->sidebar_link());
375     }
376
377     function empty_message() {
378         if (isset($this->_args['caption']) and $this->_args['caption'] == _("Recent Comments"))
379             return _("No comments found");
380         else 
381             return _("No changes found");
382     }
383         
384     function sidebar_link() {
385         extract($this->_args);
386         $pagetitle = $show_minor ? _("RecentEdits") : _("RecentChanges");
387
388         global $request;
389         $sidebarurl = WikiURL($pagetitle, array('format' => 'sidebar'), 'absurl');
390
391         $addsidebarjsfunc =
392             "function addPanel() {\n"
393             ."    window.sidebar.addPanel (\"" . sprintf("%s - %s", WIKI_NAME, $pagetitle) . "\",\n"
394             ."       \"$sidebarurl\",\"\");\n"
395             ."}\n";
396         $jsf = JavaScript($addsidebarjsfunc);
397
398         global $WikiTheme;
399         $sidebar_button = $WikiTheme->makeButton("sidebar", 'javascript:addPanel();', 'sidebaricon', 
400                                                  array('title' => _("Click to add this feed to your sidebar"),
401                                                        'style' => 'font-size:9pt;font-weight:normal; vertical-align:middle;'));
402         $addsidebarjsclick = asXML($sidebar_button);
403         $jsc = JavaScript("if ((typeof window.sidebar == 'object') &&\n"
404                                 ."    (typeof window.sidebar.addPanel == 'function'))\n"
405                                 ."   {\n"
406                                 ."       document.write('$addsidebarjsclick');\n"
407                                 ."   }\n"
408                                 );
409         return HTML(new RawXML("\n"), $jsf, new RawXML("\n"), $jsc);
410     }
411
412     function format ($changes) {
413         include_once('lib/InlineParser.php');
414         
415         $html = HTML(HTML::h2(false, $this->headline()));
416         if (($desc = $this->description()))
417             $html->pushContent($desc);
418         
419         if ($this->_args['daylist']) {
420             $html->pushContent(new OptionsButtonBars($this->_args));
421         }
422
423         $last_date = '';
424         $lines = false;
425         $first = true;
426
427         while ($rev = $changes->next()) {
428             if (($date = $this->date($rev)) != $last_date) {
429                 if ($lines)
430                     $html->pushContent($lines);
431                 // for user contributions no extra date line
432                 $html->pushContent(HTML::h3($date));
433                 $lines = HTML::ul();
434                 $last_date = $date;
435
436             }
437             // enforce view permission
438             if (mayAccessPage('view', $rev->_pagename)) {
439                 $lines->pushContent($this->format_revision($rev));
440                 if ($first)
441                     $this->setValidators($rev);
442                 $first = false;
443             }
444         }
445         if ($lines)
446             $html->pushContent($lines);
447         if ($first) {
448             if ($this->_args['daylist'])
449                 $html->pushContent // force display of OptionsButtonBars
450                     (JavaScript
451                      ("document.getElementById('rc-action-body').style.display='block';"));
452             $html->pushContent(HTML::p(array('class' => 'rc-empty'),
453                                        $this->empty_message()));
454         }
455         
456         return $html;
457     }
458
459     function format_revision ($rev) {
460         global $WikiTheme;
461         $args = &$this->_args;
462
463         $class = 'rc-' . $this->importance($rev);
464
465         $time = $this->time($rev);
466         if ($rev->get('is_minor_edit')) {
467             $minor_flag = HTML(" ",
468                                HTML::span(array('class' => 'pageinfo-minoredit'),
469                                           "(" . _("minor edit") . ")"));
470         } else {
471             $time = HTML::span(array('class' => 'pageinfo-majoredit'), $time);
472             $minor_flag = '';
473         }
474
475         $line = HTML::li(array('class' => $class));
476
477         if ($args['difflinks'])
478             $line->pushContent($this->diffLink($rev), ' ');
479
480         if ($args['historylinks'])
481             $line->pushContent($this->historyLink($rev), ' ');
482
483         // Do not display a link for a deleted page, just the page name
484         if ($rev->hasDefaultContents()) {
485             $linkorname = $rev->_pagename;
486         } else {
487             $linkorname = $this->pageLink($rev);
488         }
489
490         if ((isa($WikiTheme, 'WikiTheme_MonoBook')) or (isa($WikiTheme, 'WikiTheme_gforge'))) {
491             $line->pushContent(
492                                $args['historylinks'] ? '' : $this->historyLink($rev),
493                                ' . . ', $linkorname, '; ',
494                                $time, ' . . ',
495                                $this->authorLink($rev),' ',
496                                $this->authorContribs($rev),' ',
497                                $this->summaryAsHTML($rev),' ',
498                                $minor_flag);
499         } else {
500             $line->pushContent($linkorname, ' ',
501                                $time, ' ',
502                                $this->summaryAsHTML($rev),
503                                ' ... ',
504                                $this->authorLink($rev));
505         }
506         return $line;
507     }
508
509 }
510
511 /* format=contribs: no seperation into extra dates
512  * 14:41, 3 December 2006 (hist) (diff) Talk:PhpWiki (added diff link)  (top)
513  */
514 class _RecentChanges_UserContribsFormatter
515 extends _RecentChanges_HtmlFormatter
516 {
517     function headline () {
518         global $request;
519         extract($this->_args);
520         if ($author == '[]') $author = $request->_user->getID();
521         if ($owner  == '[]') $owner = $request->_user->getID();
522         $author_args = $owner
523             ? array('owner' => $owner)
524             : array('author' => $author);
525         return array(_("UserContribs"),":",$owner ? $owner : $author,
526                      ' ',
527                      $this->rss_icon($author_args), 
528                      $this->rss2_icon($author_args),
529                      $this->atom_icon($author_args),
530                      $this->rdf_icon($author_args),
531                      $this->grazr_icon($author_args));
532     }
533
534     function format ($changes) {
535         include_once('lib/InlineParser.php');
536         
537         $html = HTML(HTML::h2(false, $this->headline()));
538         $lines = HTML::ol();
539         $first = true; $count = 0;
540         while ($rev = $changes->next()) {
541             if (mayAccessPage('view', $rev->_pagename)) {
542                 $lines->pushContent($this->format_revision($rev));
543                 if ($first)
544                     $this->setValidators($rev);
545                 $first = false;
546             }
547             $count++;
548         }
549         $this->_args['limit'] = $count;
550         if (($desc = $this->description()))
551             $html->pushContent($desc);
552         if ($this->_args['daylist']) {
553             $html->pushContent(new OptionsButtonBars($this->_args));
554         }
555         if ($first)
556             $html->pushContent(HTML::p(array('class' => 'rc-empty'),
557                                        $this->empty_message()));
558         else                               
559             $html->pushContent($lines);
560         
561         return $html;
562     }
563
564     function format_revision ($rev) {
565         $args = &$this->_args;
566         $class = 'rc-' . $this->importance($rev);
567         $time = $this->time($rev);
568         if (! $rev->get('is_minor_edit'))
569             $time = HTML::span(array('class' => 'pageinfo-majoredit'), $time);
570
571         $line = HTML::li(array('class' => $class));
572
573         $line->pushContent($this->time($rev),", ");
574         $line->pushContent($this->date($rev)," ");
575         $line->pushContent($this->diffLink($rev), ' ');
576         $line->pushContent($this->historyLink($rev), ' ');
577         $line->pushContent($this->pageLink($rev), ' ',
578                            $this->summaryAsHTML($rev));
579         return $line;
580     }
581 }
582
583 class _RecentChanges_SideBarFormatter
584 extends _RecentChanges_HtmlFormatter
585 {
586     function rss_icon () {
587         //omit rssicon
588     }
589     function rss2_icon () { }
590     function headline () {
591         //title click opens the normal RC or RE page in the main browser frame
592         extract($this->_args);
593         $titlelink = WikiLink($this->title());
594         $titlelink->setAttr('target', '_content');
595         return HTML($this->logo(), $titlelink);
596     }
597     function logo () {
598         //logo click opens the HomePage in the main browser frame
599         global $WikiTheme;
600         $img = HTML::img(array('src' => $WikiTheme->getImageURL('logo'),
601                                'border' => 0,
602                                'align' => 'right',
603                                'style' => 'height:2.5ex'
604                                ));
605         $linkurl = WikiLink(HOME_PAGE, false, $img);
606         $linkurl->setAttr('target', '_content');
607         return $linkurl;
608     }
609
610     function authorLink ($rev) {
611         $author = $rev->get('author');
612         if ( $this->authorHasPage($author) ) {
613             $linkurl = WikiLink($author);
614             $linkurl->setAttr('target', '_content'); // way to do this using parent::authorLink ??
615             return $linkurl;
616         } else
617             return $author;
618     }
619
620     function diffLink ($rev) {
621         $linkurl = parent::diffLink($rev);
622         $linkurl->setAttr('target', '_content');
623         $linkurl->setAttr('rel', 'nofollow');
624         // FIXME: Smelly hack to get smaller diff buttons in sidebar
625         $linkurl = new RawXML(str_replace('<img ', '<img style="height:2ex" ', asXML($linkurl)));
626         return $linkurl;
627     }
628     function historyLink ($rev) {
629         $linkurl = parent::historyLink($rev);
630         $linkurl->setAttr('target', '_content');
631         // FIXME: Smelly hack to get smaller history buttons in sidebar
632         $linkurl = new RawXML(str_replace('<img ', '<img style="height:2ex" ', asXML($linkurl)));
633         return $linkurl;
634     }
635     function pageLink ($rev) {
636         $linkurl = parent::pageLink($rev);
637         $linkurl->setAttr('target', '_content');
638         return $linkurl;
639     }
640     // Overriding summaryAsHTML, because there is no way yet to
641     // return summary as transformed text with
642     // links setAttr('target', '_content') in Mozilla sidebar.
643     // So for now don't create clickable links inside summary
644     // in the sidebar, or else they target the sidebar and not the
645     // main content window.
646     function summaryAsHTML ($rev) {
647         if ( !($summary = $this->summary($rev)) )
648             return '';
649         return HTML::span(array('class' => 'wiki-summary'),
650                           "[",
651                           /*TransformLinks(*/$summary,/* $rev->get('markup')),*/
652                           "]");
653     }
654
655
656     function format ($changes) {
657         $this->_args['daylist'] = false; //don't show day buttons in Mozilla sidebar
658         $html = _RecentChanges_HtmlFormatter::format ($changes);
659         $html = HTML::div(array('class' => 'wikitext'), $html);
660         global $request;
661         $request->discardOutput();
662         
663         printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", $GLOBALS['charset']);
664         printf('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"');
665         printf('  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
666         printf('<html xmlns="http://www.w3.org/1999/xhtml">');
667
668         printf("<head>\n");
669         extract($this->_args);
670         if (!empty($category))
671             $title = $category;
672         elseif (!empty($pagematch))
673             $title = $pagematch;
674         else
675             $title = WIKI_NAME . $show_minor ? _("RecentEdits") : _("RecentChanges");
676         printf("<title>" . $title . "</title>\n");
677         global $WikiTheme;
678         $css = $WikiTheme->getCSS();
679         $css->PrintXML();
680         printf("</head>\n");
681
682         printf("<body class=\"sidebar\">\n");
683         $html->PrintXML();
684         echo '<a href="http://www.feedvalidator.org/check.cgi?url=http://phpwiki.org/RecentChanges?format=rss"><img src="themes/default/buttons/valid-rss.png" alt="[Valid RSS]" title="Validate the RSS feed" width="44" height="15" /></a>';
685         printf("\n</body>\n");
686         printf("</html>\n");
687
688         $request->finish(); // cut rest of page processing short
689     }
690 }
691
692 class _RecentChanges_BoxFormatter
693 extends _RecentChanges_HtmlFormatter
694 {
695     function rss_icon () {
696     }
697     function rss2_icon () {
698     }
699     function headline () {
700     }
701     function authorLink ($rev) {
702     }
703     function diffLink ($rev) {
704     }
705     function historyLink ($rev) {
706     }
707     function summaryAsHTML ($rev) {
708     }
709     function description () {
710     }
711     function format ($changes) {
712         include_once('lib/InlineParser.php');
713         $last_date = '';
714         $first = true;
715         $html = HTML();
716         $counter = 1;
717         $sp = HTML::Raw("\n&nbsp;&middot;&nbsp;");
718         while ($rev = $changes->next()) {
719             // enforce view permission
720             if (mayAccessPage('view',$rev->_pagename)) {
721                 if ($link = $this->pageLink($rev)) // some entries may be empty 
722                                                    // (/Blog/.. interim pages)
723                     $html->pushContent($sp, $link, HTML::br());
724                 if ($first)
725                     $this->setValidators($rev);
726                 $first = false;
727             }
728         }
729         if ($first)
730             $html->pushContent(HTML::p(array('class' => 'rc-empty'),
731                                        $this->empty_message()));
732         return $html;
733     }
734 }
735
736 class _RecentChanges_RssFormatter
737 extends _RecentChanges_Formatter
738 {
739     var $_absurls = true;
740
741     function time ($rev) {
742         return Iso8601DateTime($rev->get('mtime'));
743     }
744
745     function pageURI ($rev) {
746         return WikiURL($rev, '', 'absurl');
747     }
748
749     function format ($changes) {
750         
751         include_once('lib/RssWriter.php');
752         $rss = new RssWriter;
753         $rss->channel($this->channel_properties());
754
755         if (($props = $this->image_properties()))
756             $rss->image($props);
757         if (($props = $this->textinput_properties()))
758             $rss->textinput($props);
759
760         $first = true;
761         while ($rev = $changes->next()) {
762             // enforce view permission
763             if (mayAccessPage('view', $rev->_pagename)) {
764                 $rss->addItem($this->item_properties($rev),
765                               $this->pageURI($rev));
766                 if ($first)
767                     $this->setValidators($rev);
768                 $first = false;
769             }
770         }
771
772         global $request;
773         $request->discardOutput();
774         $rss->finish();
775         //header("Content-Type: application/rss+xml; charset=" . $GLOBALS['charset']);
776         printf("\n<!-- Generated by PhpWiki-%s:\n%s-->\n", PHPWIKI_VERSION, $GLOBALS['RCS_IDS']);
777
778         // Flush errors in comment, otherwise it's invalid XML.
779         global $ErrorManager;
780         if (($errors = $ErrorManager->getPostponedErrorsAsHTML()))
781             printf("\n<!-- PHP Warnings:\n%s-->\n", AsXML($errors));
782
783         $request->finish();     // NORETURN!!!!
784     }
785
786     function image_properties () {
787         global $WikiTheme;
788
789         $img_url = AbsoluteURL($WikiTheme->getImageURL('logo'));
790         if (!$img_url)
791             return false;
792
793         return array('title' => WIKI_NAME,
794                      'link' => WikiURL(HOME_PAGE, false, 'absurl'),
795                      'url' => $img_url);
796     }
797
798     function textinput_properties () {
799         return array('title' => _("Search"),
800                      'description' => _("Title Search"),
801                      'name' => 's',
802                      'link' => WikiURL(_("TitleSearch"), false, 'absurl'));
803     }
804
805     function channel_properties () {
806         global $request;
807
808         $rc_url = WikiURL($request->getArg('pagename'), false, 'absurl');
809         extract($this->_args);
810         $title = WIKI_NAME;
811         $description = $this->title();
812         if ($category)
813             $title = $category;
814         elseif ($pagematch)
815             $title = $pagematch;
816         return array('title' => $title,
817                      'link' => $rc_url,
818                      'description' => $description,
819                      'dc:date' => Iso8601DateTime(time()),
820                      'dc:language' => $GLOBALS['LANG']);
821
822         /* FIXME: other things one might like in <channel>:
823          * sy:updateFrequency
824          * sy:updatePeriod
825          * sy:updateBase
826          * dc:subject
827          * dc:publisher
828          * dc:language
829          * dc:rights
830          * rss091:language
831          * rss091:managingEditor
832          * rss091:webmaster
833          * rss091:lastBuildDate
834          * rss091:copyright
835          */
836     }
837
838     function item_properties ($rev) {
839         $page = $rev->getPage();
840         $pagename = $page->getName();
841
842         return array( 'title'           => SplitPagename($pagename),
843                       'description'     => $this->summary($rev),
844                       'link'            => $this->pageURL($rev),
845                       'dc:date'         => $this->time($rev),
846                       'dc:contributor'  => $rev->get('author'),
847                       'wiki:version'    => $rev->getVersion(),
848                       'wiki:importance' => $this->importance($rev),
849                       'wiki:status'     => $this->status($rev),
850                       'wiki:diff'       => $this->diffURL($rev),
851                       'wiki:history'    => $this->historyURL($rev)
852                       );
853     }
854 }
855
856 /** explicit application/rss+xml Content-Type,
857  * simplified xml structure (no namespace),
858  * support for xml-rpc cloud registerProcedure (not yet)
859  */
860 class _RecentChanges_Rss2Formatter
861 extends _RecentChanges_RssFormatter {
862
863     function format ($changes) {
864         include_once('lib/RssWriter2.php');
865         $rss = new RssWriter2;
866
867         $rss->channel($this->channel_properties());
868         if (($props = $this->cloud_properties()))
869             $rss->cloud($props);
870         if (($props = $this->image_properties()))
871             $rss->image($props);
872         if (($props = $this->textinput_properties()))
873             $rss->textinput($props);
874         $first = true;
875         while ($rev = $changes->next()) {
876             // enforce view permission
877             if (mayAccessPage('view', $rev->_pagename)) {
878                 $rss->addItem($this->item_properties($rev),
879                               $this->pageURI($rev));
880                 if ($first)
881                     $this->setValidators($rev);
882                 $first = false;
883             }
884         }
885
886         global $request;
887         $request->discardOutput();
888         $rss->finish();
889         //header("Content-Type: application/rss+xml; charset=" . $GLOBALS['charset']);
890         printf("\n<!-- Generated by PhpWiki-%s:\n%s-->\n", PHPWIKI_VERSION, $GLOBALS['RCS_IDS']);
891         // Flush errors in comment, otherwise it's invalid XML.
892         global $ErrorManager;
893         if (($errors = $ErrorManager->getPostponedErrorsAsHTML()))
894             printf("\n<!-- PHP Warnings:\n%s-->\n", AsXML($errors));
895
896         $request->finish();     // NORETURN!!!!
897     }
898
899     function channel_properties () {
900         $chann_10 = parent::channel_properties();
901         return array_merge($chann_10,
902                            array('generator' => 'PhpWiki-'.PHPWIKI_VERSION,
903                                  //<pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>
904                                  //<lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
905                                  //<docs>http://blogs.law.harvard.edu/tech/rss</docs>
906                                  'copyright' => COPYRIGHTPAGE_URL
907                                  ));
908     }
909
910     // xml-rpc registerProcedure not yet implemented
911     function cloud_properties () { return false; } 
912     function cloud_properties_test () {
913         return array('protocol' => 'xml-rpc', // xml-rpc or soap or http-post
914                      'registerProcedure' => 'wiki.rssPleaseNotify',
915                      'path' => DATA_PATH.'/RPC2.php',
916                      'port' => !SERVER_PORT ? '80' : (SERVER_PROTOCOL == 'https' ? '443' : '80'),
917                      'domain' => SERVER_NAME);
918     }
919 }
920
921 /** Explicit application/atom+xml Content-Type
922  *  A weird, questionable format
923  */
924 class _RecentChanges_AtomFormatter
925 extends _RecentChanges_RssFormatter {
926
927     function format ($changes) {
928         global $request;
929         include_once('lib/RssWriter.php');
930         $rss = new AtomFeed;
931
932         // "channel" is called "feed" in atom
933         $rc_url = WikiURL($request->getArg('pagename'), false, 'absurl');
934         extract($this->_args);
935         $title = WIKI_NAME;
936         $description = $this->title();
937         if ($category)
938             $title = $category;
939         elseif ($pagematch)
940             $title = $pagematch;
941         $feed_props = array('title' => $description,
942                             'link' => array('rel'=>"alternate",
943                                             'type'=>"text/html",
944                                             'href' => $rc_url),
945                             'id' => md5($rc_url),                
946                             'modified' => Iso8601DateTime(time()),
947                             'generator' => 'PhpWiki-'.PHPWIKI_VERSION,
948                             'tagline' => '');
949         $rss->feed($feed_props);
950         $first = true;
951         while ($rev = $changes->next()) {
952             // enforce view permission
953             if (mayAccessPage('view', $rev->_pagename)) {
954                 $props = $this->item_properties($rev);
955                 $rss->addItem($props,
956                               false,
957                               $this->pageURI($rev));
958                 if ($first)
959                     $this->setValidators($rev);
960                 $first = false;
961             }
962         }
963
964         $request->discardOutput();
965         $rss->finish();
966         //header("Content-Type: application/atom; charset=" . $GLOBALS['charset']);
967         printf("\n<!-- Generated by PhpWiki-%s:\n%s-->\n", PHPWIKI_VERSION, $GLOBALS['RCS_IDS']);
968         // Flush errors in comment, otherwise it's invalid XML.
969         global $ErrorManager;
970         if (($errors = $ErrorManager->getPostponedErrorsAsHTML()))
971             printf("\n<!-- PHP Warnings:\n%s-->\n", AsXML($errors));
972
973         $request->finish();     // NORETURN!!!!
974     }
975
976     function item_properties ($rev) {
977         $page = $rev->getPage();
978         $pagename = $page->getName();
979         return array( 'title'           => $pagename,
980                       'link'            => array('rel' => 'alternate',
981                                                  'type' => 'text/html',
982                                                  'href' => $this->pageURL($rev)),
983                       'summary'         => $this->summary($rev),
984                       'modified'        => $this->time($rev)."Z",
985                       'issued'          => $this->time($rev),
986                       'created'         => $this->time($rev)."Z",
987                       'author'          => new XmlElement('author', new XmlElement('name', $rev->get('author')))
988                       );
989     }
990 }
991
992 /**
993  * Filter by non-empty
994  */
995 class NonDeletedRevisionIterator extends WikiDB_PageRevisionIterator
996 {
997     /** Constructor
998      *
999      * @param $revisions object a WikiDB_PageRevisionIterator.
1000      */
1001     function NonDeletedRevisionIterator ($revisions, $check_current_revision = true) {
1002         $this->_revisions = $revisions;
1003         $this->_check_current_revision = $check_current_revision;
1004     }
1005
1006     function next () {
1007         while (($rev = $this->_revisions->next())) {
1008             if ($this->_check_current_revision) {
1009                 $page = $rev->getPage();
1010                 $check_rev = $page->getCurrentRevision();
1011             }
1012             else {
1013                 $check_rev = $rev;
1014             }
1015             if (! $check_rev->hasDefaultContents())
1016                 return $rev;
1017         }
1018         $this->free();
1019         return false;
1020     }
1021
1022 }
1023
1024 /**
1025  * Filter by only_new.
1026  * Only new created pages
1027  */
1028 class NewPageRevisionIterator extends WikiDB_PageRevisionIterator
1029 {
1030     /** Constructor
1031      *
1032      * @param $revisions object a WikiDB_PageRevisionIterator.
1033      */
1034     function NewPageRevisionIterator ($revisions) {
1035         $this->_revisions = $revisions;
1036     }
1037
1038     function next () {
1039         while (($rev = $this->_revisions->next())) {
1040             if ($rev->getVersion() == 1)
1041                 return $rev;
1042         }
1043         $this->free();
1044         return false;
1045     }
1046 }
1047
1048 /**
1049  * Only pages with links to a certain category
1050  */
1051 class LinkRevisionIterator extends WikiDB_PageRevisionIterator
1052 {
1053     function LinkRevisionIterator ($revisions, $category) {
1054         $this->_revisions = $revisions;
1055         if (preg_match("/[\?\.\*]/", $category)) {
1056           $backlinkiter = $this->_revisions->_wikidb->linkSearch
1057             (new TextSearchQuery("*", true), 
1058              new TextSearchQuery($category, true), 
1059              "linkfrom");
1060         } else {
1061           $basepage = $GLOBALS['request']->getPage($category);
1062           $backlinkiter = $basepage->getBackLinks(true);
1063         }
1064         $this->links = array();
1065         foreach ($backlinkiter->asArray() as $p) {
1066             if (is_object($p)) $this->links[] = $p->getName();
1067             elseif (is_array($p)) $this->links[] = $p['pagename'];
1068             else $this->links[] = $p;
1069         }
1070         $backlinkiter->free();
1071         sort($this->links);
1072     }
1073
1074     function next () {
1075         while (($rev = $this->_revisions->next())) {
1076             if (binary_search($rev->getName(), $this->links) != false)
1077                 return $rev;
1078         }
1079         $this->free();
1080         return false;
1081     }
1082
1083     function free () {
1084         unset ($this->links);
1085     }
1086 }
1087
1088 class PageMatchRevisionIterator extends WikiDB_PageRevisionIterator
1089 {
1090     function PageMatchRevisionIterator ($revisions, $match) {
1091         $this->_revisions = $revisions;
1092         $this->search = new TextSearchQuery($match, true);
1093     }
1094
1095     function next () {
1096         while (($rev = $this->_revisions->next())) {
1097             if ($this->search->match($rev->getName()))
1098                 return $rev;
1099         }
1100         $this->free();
1101         return false;
1102     }
1103
1104     function free () {
1105         unset ($this->search);
1106     }
1107 }
1108
1109 /**
1110  * Filter by author
1111  */
1112 class AuthorPageRevisionIterator extends WikiDB_PageRevisionIterator
1113 {
1114     function AuthorPageRevisionIterator ($revisions, $author) {
1115         $this->_revisions = $revisions;
1116         $this->_author = $author;
1117     }
1118
1119     function next () {
1120         while (($rev = $this->_revisions->next())) {
1121             if ($rev->get('author_id') == $this->_author)
1122                 return $rev;
1123         }
1124         $this->free();
1125         return false;
1126     }
1127 }
1128
1129 /**
1130  * Filter by owner
1131  */
1132 class OwnerPageRevisionIterator extends WikiDB_PageRevisionIterator
1133 {
1134     function OwnerPageRevisionIterator ($revisions, $owner) {
1135         $this->_revisions = $revisions;
1136         $this->_owner = $owner;
1137     }
1138
1139     function next () {
1140         while (($rev = $this->_revisions->next())) {
1141             $page = $rev->getPage();
1142             if ($page->getOwner() == $this->_owner)
1143                 return $rev;
1144         }
1145         $this->free();
1146         return false;
1147     }
1148 }
1149
1150 class WikiPlugin_RecentChanges
1151 extends WikiPlugin
1152 {
1153     function getName () {
1154         return _("RecentChanges");
1155     }
1156
1157     function getDescription () {
1158         return _("List all recent changes in this wiki.");
1159     }
1160
1161     function getVersion() {
1162         return preg_replace("/[Revision: $]/", '',
1163                             "\$Revision$");
1164     }
1165
1166     function managesValidators() {
1167         // Note that this is a bit of a fig.
1168         // We set validators based on the most recently changed page,
1169         // but this fails when the most-recent page is deleted.
1170         // (Consider that the Last-Modified time will decrease
1171         // when this happens.)
1172
1173         // We might be better off, leaving this as false (and junking
1174         // the validator logic above) and just falling back to the
1175         // default behavior (handled by WikiPlugin) of just using
1176         // the WikiDB global timestamp as the mtime.
1177
1178         // Nevertheless, for now, I leave this here, mostly as an
1179         // example for how to use appendValidators() and managesValidators().
1180         
1181         return true;
1182     }
1183             
1184     function getDefaultArguments() {
1185         return array('days'         => 2,
1186                      'show_minor'   => false,
1187                      'show_major'   => true,
1188                      'show_all'     => false,
1189                      'show_deleted' => 'sometimes',
1190                      'only_new'     => false,
1191                      'author'       => false,
1192                      'owner'        => false,
1193                      'limit'        => false,
1194                      'format'       => false,
1195                      'daylist'      => false,
1196                      'difflinks'    => true,
1197                      'historylinks' => false,
1198                      'caption'      => '',
1199                      'category'     => '',
1200                      'pagematch'    => ''
1201                      );
1202     }
1203
1204     function getArgs ($argstr, $request, $defaults = false) {
1205         if (!$defaults) $defaults = $this->getDefaultArguments();
1206         $args = WikiPlugin::getArgs($argstr, $request, $defaults);
1207
1208         $action = $request->getArg('action');
1209         if ($action != 'browse' && ! $request->isActionPage($action))
1210             $args['format'] = false; // default -> HTML
1211
1212         if ($args['format'] == 'rss' && empty($args['limit']))
1213             $args['limit'] = 15; // Fix default value for RSS.
1214         if ($args['format'] == 'rss2' && empty($args['limit']))
1215             $args['limit'] = 15; // Fix default value for RSS2.
1216
1217         if ($args['format'] == 'sidebar' && empty($args['limit']))
1218             $args['limit'] = 10; // Fix default value for sidebar.
1219
1220         return $args;
1221     }
1222
1223     function getMostRecentParams (&$args) {
1224         $show_all = false; $show_minor = false; $show_major = false;
1225         $limit = false;
1226         extract($args);
1227
1228         $params = array('include_minor_revisions' => $show_minor,
1229                         'exclude_major_revisions' => !$show_major,
1230                         'include_all_revisions' => !empty($show_all));
1231         if ($limit != 0)
1232             $params['limit'] = $limit;
1233         if (!empty($args['author'])) {
1234             global $request;
1235             if ($args['author'] == '[]')
1236                 $args['author'] = $request->_user->getID();
1237             $params['author'] = $args['author'];
1238         }
1239         if (!empty($args['owner'])) {
1240             global $request;
1241             if ($args['owner'] == '[]')
1242                 $args['owner'] = $request->_user->getID();
1243             $params['owner'] = $args['owner'];
1244         }
1245         if (!empty($days)) {
1246           if ($days > 0.0)
1247             $params['since'] = time() - 24 * 3600 * $days;
1248           elseif ($days < 0.0)
1249             $params['since'] = 24 * 3600 * $days - time();
1250         }
1251
1252         return $params;
1253     }
1254
1255     function getChanges ($dbi, $args) {
1256         $changes = $dbi->mostRecent($this->getMostRecentParams($args));
1257
1258         $show_deleted = @$args['show_deleted'];
1259         $show_all = @$args['show_all'];
1260         if ($show_deleted == 'sometimes')
1261             $show_deleted = @$args['show_minor'];
1262
1263         // only pages (e.g. PageHistory of subpages)
1264         if (!empty($args['pagematch'])) {
1265             require_once("lib/TextSearchQuery.php");
1266             $changes = new PageMatchRevisionIterator($changes, $args['pagematch']);
1267         }
1268         if (!empty($args['category'])) {
1269             require_once("lib/TextSearchQuery.php");
1270             $changes = new LinkRevisionIterator($changes, $args['category']);
1271         }
1272         if (!empty($args['only_new']))
1273             $changes = new NewPageRevisionIterator($changes);
1274         if (!empty($args['author']))
1275             $changes = new AuthorPageRevisionIterator($changes, $args['author']);
1276         if (!empty($args['owner']))
1277             $changes = new OwnerPageRevisionIterator($changes, $args['owner']);
1278         if (!$show_deleted)
1279             $changes = new NonDeletedRevisionIterator($changes, !$show_all);
1280
1281         return $changes;
1282     }
1283
1284     function format ($changes, $args) {
1285         global $WikiTheme;
1286         $format = $args['format'];
1287
1288         $fmt_class = $WikiTheme->getFormatter('RecentChanges', $format);
1289         if (!$fmt_class) {
1290             if ($format == 'rss')
1291                 $fmt_class = '_RecentChanges_RssFormatter';
1292             elseif ($format == 'rss2')
1293                 $fmt_class = '_RecentChanges_Rss2Formatter';
1294             elseif ($format == 'atom')
1295                 $fmt_class = '_RecentChanges_AtomFormatter';
1296             elseif ($format == 'rss091') {
1297                 include_once "lib/RSSWriter091.php";
1298                 $fmt_class = '_RecentChanges_RssFormatter091';
1299             }
1300             elseif ($format == 'sidebar')
1301                 $fmt_class = '_RecentChanges_SideBarFormatter';
1302             elseif ($format == 'box')
1303                 $fmt_class = '_RecentChanges_BoxFormatter';
1304             elseif ($format == 'contribs')
1305                 $fmt_class = '_RecentChanges_UserContribsFormatter';
1306             else
1307                 $fmt_class = '_RecentChanges_HtmlFormatter';
1308         }
1309
1310         $fmt = new $fmt_class($args);
1311         return $fmt->format($changes);
1312     }
1313
1314     function run($dbi, $argstr, &$request, $basepage) {
1315         $args = $this->getArgs($argstr, $request);
1316
1317         // HACKish: fix for SF bug #622784  (1000 years of RecentChanges ought
1318         // to be enough for anyone.)
1319         $args['days'] = min($args['days'], 365000);
1320
1321         // Within Categories just display Category Backlinks
1322         if (empty($args['category']) and empty($args['pagematch'])
1323             and preg_match("/^Category/", $request->getArg('pagename'))) 
1324         {
1325             $args['category'] = $request->getArg('pagename');
1326         }
1327         
1328         // Hack alert: format() is a NORETURN for rss formatters.
1329         return $this->format($this->getChanges($dbi, $args), $args);
1330     }
1331
1332     // box is used to display a fixed-width, narrow version with common header.
1333     // just a numbered list of limit pagenames, without date.
1334     function box($args = false, $request = false, $basepage = false) {
1335         if (!$request) $request =& $GLOBALS['request'];
1336         if (!isset($args['limit'])) $args['limit'] = 15;
1337         $args['format'] = 'box';
1338         $args['show_minor'] = false;
1339         $args['show_major'] = true;
1340         $args['show_deleted'] = 'sometimes';
1341         $args['show_all'] = false;
1342         $args['days'] = 90;
1343         return $this->makeBox(WikiLink($this->getName(),'',
1344                                        SplitPagename($this->getName())),
1345                               $this->format
1346                               ($this->getChanges($request->_dbi, $args), $args));
1347     }
1348
1349 };
1350
1351 class OptionsButtonBars extends HtmlElement {
1352
1353     function OptionsButtonBars ($plugin_args) {
1354         $this->__construct('fieldset', array('class' => 'wiki-rc-action'));
1355
1356         // Add ShowHideFolder button
1357         $icon = $GLOBALS['WikiTheme']->_findData('images/folderArrowOpen.png');
1358         $img = HTML::img(array('id' => 'rc-action-img',
1359                                'src' => $icon,
1360                                'onclick' => "showHideFolder('rc-action')",
1361                                'alt'  => _("Click to hide/show"),
1362                                'title'  => _("Click to hide/show")));
1363
1364         // Display selection buttons
1365         extract($plugin_args);
1366
1367         // Custom caption
1368         if (! $caption) {
1369             $caption = _("Show changes for:");
1370         }
1371
1372         $this->pushContent(HTML::legend($caption,' ',$img));
1373         $table = HTML::table(array('id' => 'rc-action-body',
1374                                    'style' => 'display:block'));
1375
1376         $tr = HTML::tr();
1377         foreach (explode(",", $daylist) as $days_button) {
1378             $tr->pushContent($this->_makeDayButton($days_button, $days));
1379         }
1380         $table->pushContent($tr);
1381
1382         $tr = HTML::tr();
1383         $tr->pushContent($this->_makeUsersButton(0));
1384         $tr->pushContent($this->_makeUsersButton(1));
1385         $table->pushContent($tr);
1386
1387         $tr = HTML::tr();
1388         $tr->pushContent($this->_makePagesButton(0));
1389         $tr->pushContent($this->_makePagesButton(1));
1390         $table->pushContent($tr);
1391
1392         $tr = HTML::tr();
1393         $tr->pushContent($this->_makeMinorButton(1, $show_minor));
1394         $tr->pushContent($this->_makeMinorButton(0, $show_minor));
1395         $table->pushContent($tr);
1396
1397         $tr = HTML::tr();
1398         $tr->pushContent($this->_makeShowAllButton(1, $show_all));
1399         $tr->pushContent($this->_makeShowAllButton(0, $show_all));
1400         $table->pushContent($tr);
1401
1402         $tr = HTML::tr();
1403         $tr->pushContent($this->_makeNewPagesButton(0, $only_new));
1404         $tr->pushContent($this->_makeNewPagesButton(1, $only_new));
1405         $table->pushContent($tr);
1406
1407         $this->pushContent($table);
1408     }
1409
1410     function _makeDayButton ($days_button, $days) {
1411         global $request;
1412
1413         $url = $request->getURLtoSelf(array('action' => $request->getArg('action'), 'days' => $days_button));
1414         if ($days_button == 1) {
1415             $label = _("1 day");
1416         } elseif ($days_button < 1) {
1417             $label = _("All time");
1418         } else {
1419             $label = sprintf(_("%s days"), abs($days_button));
1420         }
1421         $selected = HTML::td(array('class'=>'tdselected'), $label);
1422         $unselected = HTML::td(array('class'=>'tdunselected'),
1423                       HTML::a(array('href'  => $url, 'class' => 'wiki-rc-action'), $label));
1424         return ($days_button == $days) ? $selected : $unselected;
1425     }
1426
1427     function _makeUsersButton ($users) {
1428         global $request;
1429
1430         if ($users == 0) {
1431             $label = _("All users");
1432             $author = "";
1433         } else {
1434             $label = _("My modifications only");
1435             $author = "[]";
1436         }
1437
1438         $selfurl = $request->getURLtoSelf(array('action' => $request->getArg('action')));
1439         $url = $request->getURLtoSelf(array('action' => $request->getArg('action'), 'author' => $author));
1440         if ($url == $selfurl) {
1441             return HTML::td(array('colspan'=>3, 'class'=>'tdselected'), $label);
1442         }
1443         return HTML::td(array('colspan'=>3, 'class'=>'tdunselected'), 
1444                         HTML::a(array('href'  => $url, 'class' => 'wiki-rc-action'), $label));
1445     }
1446
1447     function _makePagesButton ($pages) {
1448         global $request;
1449
1450         if ($pages == 0) {
1451             $label = _("All pages");
1452             $owner = "";
1453         } else {
1454             $label = _("My pages only");
1455             $owner = "[]";
1456         }
1457
1458         $selfurl = $request->getURLtoSelf(array('action' => $request->getArg('action')));
1459         $url = $request->getURLtoSelf(array('action' => $request->getArg('action'), 'owner' => $owner));
1460         if ($url == $selfurl) {
1461             return HTML::td(array('colspan'=>3, 'class'=>'tdselected'), $label);
1462         }
1463         return HTML::td(array('colspan'=>3, 'class'=>'tdunselected'),
1464                         HTML::a(array('href'  => $url, 'class' => 'wiki-rc-action'), $label));
1465     }
1466
1467     function _makeMinorButton ($minor_button, $show_minor) {
1468         global $request;
1469
1470         $url = $request->getURLtoSelf(array('action' => $request->getArg('action'), 'show_minor' => $minor_button));
1471         $label = ($minor_button == 0) ? _("Major modifications only") : _("All modifications");
1472         $selected = HTML::td(array('colspan'=>3, 'class'=>'tdselected'), $label);
1473         $unselected = HTML::td(array('colspan'=>3, 'class'=>'tdunselected'),
1474                       HTML::a(array('href'  => $url, 'class' => 'wiki-rc-action'), $label));
1475         return ($minor_button == $show_minor) ? $selected : $unselected;
1476     }
1477
1478     function _makeShowAllButton ($showall_button, $show_all) {
1479         global $request;
1480
1481         $url = $request->getURLtoSelf(array('action' => $request->getArg('action'), 'show_all' => $showall_button));
1482         $label = ($showall_button == 0) ? _("Page once only") : _("Full changes");
1483         $selected = HTML::td(array('colspan'=>3, 'class'=>'tdselected'), $label);
1484         $unselected = HTML::td(array('colspan'=>3, 'class'=>'tdunselected'),
1485                       HTML::a(array('href'  => $url, 'class' => 'wiki-rc-action'), $label));
1486         return ($showall_button == $show_all) ? $selected : $unselected;
1487     }
1488
1489     function _makeNewPagesButton ($newpages_button, $only_new) {
1490         global $request;
1491
1492         $url = $request->getURLtoSelf(array('action' => $request->getArg('action'), 'only_new' => $newpages_button));
1493         $label = ($newpages_button == 0) ? _("Old and new pages") : _("New pages only");
1494         $selected = HTML::td(array('colspan'=>3, 'class'=>'tdselected'), $label);
1495         $unselected = HTML::td(array('colspan'=>3, 'class'=>'tdunselected'),
1496                       HTML::a(array('href'  => $url, 'class' => 'wiki-rc-action'), $label));
1497         return ($newpages_button == $only_new) ? $selected : $unselected;
1498     }
1499 }
1500
1501 // (c-file-style: "gnu")
1502 // Local Variables:
1503 // mode: php
1504 // tab-width: 8
1505 // c-basic-offset: 4
1506 // c-hanging-comment-ender-p: nil
1507 // indent-tabs-mode: nil
1508 // End:
1509 ?>