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