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