_args = $rc_args; $this->_diffargs = array('action' => 'diff'); if ($rc_args['show_minor'] || !$rc_args['show_major']) $this->_diffargs['previous'] = 'minor'; // PageHistoryPlugin doesn't have a 'daylist' arg. if (!isset($this->_args['daylist'])) $this->_args['daylist'] = false; } function include_versions_in_URLs() { return (bool) $this->_args['show_all']; } function date ($rev) { global $Theme; return $Theme->getDay($rev->get('mtime')); } function time ($rev) { global $Theme; return $Theme->formatTime($rev->get('mtime')); } function diffURL ($rev) { $args = $this->_diffargs; if ($this->include_versions_in_URLs()) $args['version'] = $rev->getVersion(); $page = $rev->getPage(); return WikiURL($page->getName(), $args, $this->_absurls); } function historyURL ($rev) { $page = $rev->getPage(); return WikiURL($page, array('action' => _("PageHistory")), $this->_absurls); } function pageURL ($rev) { return WikiURL($this->include_versions_in_URLs() ? $rev : $rev->getPage(), '', $this->_absurls); } function authorHasPage ($author) { global $WikiNameRegexp, $request; $dbi = $request->getDbh(); return isWikiWord($author) && $dbi->isWikiPage($author); } function authorURL ($author) { return $this->authorHasPage() ? WikiURL($author) : false; } function status ($rev) { if ($rev->hasDefaultContents()) return 'deleted'; $page = $rev->getPage(); $prev = $page->getRevisionBefore($rev->getVersion()); if ($prev->hasDefaultContents()) return 'new'; return 'updated'; } function importance ($rev) { return $rev->get('is_minor_edit') ? 'minor' : 'major'; } function summary($rev) { if ( ($summary = $rev->get('summary')) ) return $summary; switch ($this->status($rev)) { case 'deleted': return _("Deleted."); case 'new': return _("New page."); default: return ''; } } function setValidators($most_recent_rev) { $rev = $most_recent_rev; $validators = array('RecentChanges-top' => array($rev->getPageName(), $rev->getVersion()), '%mtime' => $rev->get('mtime')); global $request; $request->appendValidators($validators); } } class _RecentChanges_HtmlFormatter extends _RecentChanges_Formatter { function diffLink ($rev) { global $Theme; return $Theme->makeButton(_("(diff)"), $this->diffURL($rev), 'wiki-rc-action'); } function historyLink ($rev) { global $Theme; return $Theme->makeButton(_("(hist)"), $this->historyURL($rev), 'wiki-rc-action'); } function pageLink ($rev, $link_text=false) { $page = $rev->getPage(); global $Theme; if ($this->include_versions_in_URLs()) { $version = $rev->getVersion(); $exists = !$rev->hasDefaultContents(); } else { $version = false; $cur = $page->getCurrentRevision(); $exists = !$cur->hasDefaultContents(); } if ($exists) return $Theme->linkExistingWikiWord($page->getName(), $link_text, $version); else return $Theme->linkUnknownWikiWord($page->getName(), $link_text); } function authorLink ($rev) { $author = $rev->get('author'); if ( $this->authorHasPage($author) ) { return WikiLink($author); } else return $author; } function summaryAsHTML ($rev) { if ( !($summary = $this->summary($rev)) ) return ''; return HTML::strong( array('class' => 'wiki-summary'), "[", TransformLinks($summary, $rev->get('markup'), $rev->getPageName()), "]"); } function rss_icon () { global $request, $Theme; $rss_url = $request->getURLtoSelf(array('format' => 'rss')); return HTML::small(array('style' => 'font-weight:normal;vertical-align:middle;'), $Theme->makeButton("RSS", $rss_url, 'rssicon')); } function description () { extract($this->_args); // FIXME: say something about show_all. if ($show_major && $show_minor) $edits = _("edits"); elseif ($show_major) $edits = _("major edits"); else $edits = _("minor edits"); if ($timespan = $days > 0) { if (intval($days) != $days) $days = sprintf("%.1f", $days); } $lmt = abs($limit); /** * Depending how this text is split up it can be tricky or * impossible to translate with good grammar. So the seperate * strings for 1 day and %s days are necessary in this case * for translating to multiple languages, due to differing * overlapping ideal word cutting points. * * en: day/days "The %d most recent %s [during (the past] day) are listed below." * de: 1 Tag "Die %d jüngste %s [innerhalb (von des letzten] Tages) sind unten aufgelistet." * de: %s days "Die %d jüngste %s [innerhalb (von] %s Tagen) sind unten aufgelistet." * * en: day/days "The %d most recent %s during [the past] (day) are listed below." * fr: 1 jour "Les %d %s les plus récentes pendant [le dernier (d'une] jour) sont énumérées ci-dessous." * fr: %s jours "Les %d %s les plus récentes pendant [les derniers (%s] jours) sont énumérées ci-dessous." */ if ($limit > 0) { if ($timespan) { if (intval($days) == 1) $desc = fmt("The %d most recent %s during the past day are listed below.", $limit, $edits); else $desc = fmt("The %d most recent %s during the past %s days are listed below.", $limit, $edits, $days); } else $desc = fmt("The %d most recent %s are listed below.", $limit, $edits); } elseif ($limit < 0) { //$limit < 0 means we want oldest pages if ($timespan) { if (intval($days) == 1) $desc = fmt("The %d oldest %s during the past day are listed below.", $lmt, $edits); else $desc = fmt("The %d oldest %s during the past %s days are listed below.", $lmt, $edits, $days); } else $desc = fmt("The %d oldest %s are listed below.", $lmt, $edits); } else { if ($timespan) { if (intval($days) == 1) $desc = fmt("The most recent %s during the past day are listed below.", $edits); else $desc = fmt("The most recent %s during the past %s days are listed below.", $edits, $days); } else $desc = fmt("All %s are listed below.", $edits); } return HTML::p(false, $desc); } function title () { extract($this->_args); return array($show_minor ? _("RecentEdits") : _("RecentChanges"), ' ', $this->rss_icon(), $this->sidebar_link()); } function empty_message () { return _("No changes found"); } function sidebar_link() { extract($this->_args); $pagetitle = $show_minor ? _("RecentEdits") : _("RecentChanges"); global $request; $sidebarurl = WikiURL($pagetitle, array('format' => 'sidebar'), 'absurl'); $addsidebarjsfunc = "function addPanel() {\n" ." window.sidebar.addPanel (\"" . sprintf("%s - %s", WIKI_NAME, $pagetitle) . "\",\n" ." \"$sidebarurl\",\"\");\n" ."}\n"; $jsf = JavaScript($addsidebarjsfunc); global $Theme; $sidebar_button = $Theme->makeButton("sidebar", 'javascript:addPanel();', 'sidebaricon'); $addsidebarjsclick = asXML(HTML::small(array('style' => 'font-weight:normal;vertical-align:middle;'), $sidebar_button)); $jsc = JavaScript("if ((typeof window.sidebar == 'object') &&\n" ." (typeof window.sidebar.addPanel == 'function'))\n" ." {\n" ." document.write('$addsidebarjsclick');\n" ." }\n" ); return HTML(new RawXML("\n"), $jsf, new RawXML("\n"), $jsc); } function format ($changes) { include_once('lib/InlineParser.php'); $html = HTML(HTML::h2(false, $this->title())); if (($desc = $this->description())) $html->pushContent($desc); if ($this->_args['daylist']) $html->pushContent(new DayButtonBar($this->_args)); $last_date = ''; $lines = false; $first = true; while ($rev = $changes->next()) { if (($date = $this->date($rev)) != $last_date) { if ($lines) $html->pushContent($lines); $html->pushContent(HTML::h3($date)); $lines = HTML::ul(); $last_date = $date; } $lines->pushContent($this->format_revision($rev)); if ($first) $this->setValidators($rev); $first = false; } if ($lines) $html->pushContent($lines); if ($first) $html->pushContent(HTML::p(array('class' => 'rc-empty'), $this->empty_message())); return $html; } function format_revision ($rev) { $args = &$this->_args; $class = 'rc-' . $this->importance($rev); $time = $this->time($rev); if (! $rev->get('is_minor_edit')) $time = HTML::strong(array('class' => 'pageinfo-majoredit'), $time); $line = HTML::li(array('class' => $class)); if ($args['difflinks']) $line->pushContent($this->diffLink($rev), ' '); if ($args['historylinks']) $line->pushContent($this->historyLink($rev), ' '); $line->pushContent($this->pageLink($rev), ' ', $time, ' ', $this->summaryAsHTML($rev), ' ... ', $this->authorLink($rev)); return $line; } } class _RecentChanges_SideBarFormatter extends _RecentChanges_HtmlFormatter { function rss_icon () { //omit rssicon } function title () { //title click opens the normal RC or RE page in the main browser frame extract($this->_args); $titlelink = WikiLink($show_minor ? _("RecentEdits") : _("RecentChanges")); $titlelink->setAttr('target', '_content'); return HTML($this->logo(), $titlelink); } function logo () { //logo click opens the HomePage in the main browser frame global $Theme; $img = HTML::img(array('src' => $Theme->getImageURL('logo'), 'border' => 0, 'align' => 'right', 'style' => 'height:2.5ex' )); $linkurl = WikiLink(HOME_PAGE, false, $img); $linkurl->setAttr('target', '_content'); return $linkurl; } function authorLink ($rev) { $author = $rev->get('author'); if ( $this->authorHasPage($author) ) { $linkurl = WikiLink($author); $linkurl->setAttr('target', '_content'); // way to do this using parent::authorLink ?? return $linkurl; } else return $author; } function diffLink ($rev) { $linkurl = parent::diffLink($rev); $linkurl->setAttr('target', '_content'); // FIXME: Smelly hack to get smaller diff buttons in sidebar $linkurl = new RawXML(str_replace('setAttr('target', '_content'); // FIXME: Smelly hack to get smaller history buttons in sidebar $linkurl = new RawXML(str_replace('setAttr('target', '_content'); return $linkurl; } // Overriding summaryAsHTML, because there is no way yet to // return summary as transformed text with // links setAttr('target', '_content') in Mozilla sidebar. // So for now don't create clickable links inside summary // in the sidebar, or else they target the sidebar and not the // main content window. function summaryAsHTML ($rev) { if ( !($summary = $this->summary($rev)) ) return ''; return HTML::strong(array('class' => 'wiki-summary'), "[", /*TransformLinks(*/$summary,/* $rev->get('markup')),*/ "]"); } function format ($changes) { $this->_args['daylist'] = false; //don't show day buttons in Mozilla sidebar $html = _RecentChanges_HtmlFormatter::format ($changes); $html = HTML::div(array('class' => 'wikitext'), $html); global $request; $request->discardOutput(); printf("\n", CHARSET); printf(''); printf(''); printf("\n"); extract($this->_args); $title = WIKI_NAME . $show_minor ? _("RecentEdits") : _("RecentChanges"); printf("" . $title . "\n"); global $Theme; $css = $Theme->getCSS(); $css->PrintXML(); printf("\n"); printf("\n"); $html->PrintXML(); printf("\n\n"); printf("\n"); $request->finish(); // cut rest of page processing short } } class _RecentChanges_RssFormatter extends _RecentChanges_Formatter { var $_absurls = true; function time ($rev) { return Iso8601DateTime($rev->get('mtime')); } function pageURI ($rev) { return WikiURL($rev, '', 'absurl'); } function format ($changes) { include_once('lib/RssWriter.php'); $rss = new RssWriter; $rss->channel($this->channel_properties()); if (($props = $this->image_properties())) $rss->image($props); if (($props = $this->textinput_properties())) $rss->textinput($props); $first = true; while ($rev = $changes->next()) { $rss->addItem($this->item_properties($rev), $this->pageURI($rev)); if ($first) $this->setValidators($rev); $first = false; } global $request; $request->discardOutput(); $rss->finish(); printf("\n\n", $GLOBALS['RCS_IDS']); // Flush errors in comment, otherwise it's invalid XML. global $ErrorManager; if (($errors = $ErrorManager->getPostponedErrorsAsHTML())) printf("\n\n", AsXML($errors)); $request->finish(); // NORETURN!!!! } function image_properties () { global $Theme; $img_url = AbsoluteURL($Theme->getImageURL('logo')); if (!$img_url) return false; return array('title' => WIKI_NAME, 'link' => WikiURL(HOME_PAGE, false, 'absurl'), 'url' => $img_url); } function textinput_properties () { return array('title' => _("Search"), 'description' => _("Title Search"), 'name' => 's', 'link' => WikiURL(_("TitleSearch"), false, 'absurl')); } function channel_properties () { global $request; $rc_url = WikiURL($request->getArg('pagename'), false, 'absurl'); return array('title' => WIKI_NAME, 'link' => $rc_url, 'description' => _("RecentChanges"), 'dc:date' => Iso8601DateTime(time())); /* FIXME: other things one might like in : * sy:updateFrequency * sy:updatePeriod * sy:updateBase * dc:subject * dc:publisher * dc:language * dc:rights * rss091:language * rss091:managingEditor * rss091:webmaster * rss091:lastBuildDate * rss091:copyright */ } function item_properties ($rev) { $page = $rev->getPage(); $pagename = $page->getName(); return array( 'title' => split_pagename($pagename), 'description' => $this->summary($rev), 'link' => $this->pageURL($rev), 'dc:date' => $this->time($rev), 'dc:contributor' => $rev->get('author'), 'wiki:version' => $rev->getVersion(), 'wiki:importance' => $this->importance($rev), 'wiki:status' => $this->status($rev), 'wiki:diff' => $this->diffURL($rev), 'wiki:history' => $this->historyURL($rev) ); } } class NonDeletedRevisionIterator extends WikiDB_PageRevisionIterator { /** Constructor * * @param $revisions object a WikiDB_PageRevisionIterator. */ function NonDeletedRevisionIterator ($revisions, $check_current_revision = true) { $this->_revisions = $revisions; $this->_check_current_revision = $check_current_revision; } function next () { while (($rev = $this->_revisions->next())) { if ($this->_check_current_revision) { $page = $rev->getPage(); $check_rev = $page->getCurrentRevision(); } else { $check_rev = $rev; } if (! $check_rev->hasDefaultContents()) return $rev; } $this->free(); return false; } function free () { $this->_revisions->free(); } } class WikiPlugin_RecentChanges extends WikiPlugin { function getName () { return _("RecentChanges"); } function getVersion() { return preg_replace("/[Revision: $]/", '', "\$Revision: 1.85 $"); } function managesValidators() { // Note that this is a bit of a fig. // We set validators based on the most recently changed page, // but this fails when the most-recent page is deleted. // (Consider that the Last-Modified time will decrease // when this happens.) // We might be better off, leaving this as false (and junking // the validator logic above) and just falling back to the // default behavior (handled by WikiPlugin) of just using // the WikiDB global timestamp as the mtime. // Nevertheless, for now, I leave this here, mostly as an // example for how to use appendValidators() and managesValidators(). return true; } function getDefaultArguments() { return array('days' => 2, 'show_minor' => false, 'show_major' => true, 'show_all' => false, 'show_deleted' => 'sometimes', 'limit' => false, 'format' => false, 'daylist' => false, 'difflinks' => true, 'historylinks' => false, 'caption' => '' ); } function getArgs ($argstr, $request, $defaults = false) { $args = WikiPlugin::getArgs($argstr, $request, $defaults); $action = $request->getArg('action'); if ($action != 'browse' && ! $request->isActionPage($action)) $args['format'] = false; // default -> HTML if ($args['format'] == 'rss' && empty($args['limit'])) $args['limit'] = 15; // Fix default value for RSS. if ($args['format'] == 'sidebar' && empty($args['limit'])) $args['limit'] = 10; // Fix default value for sidebar. return $args; } function getMostRecentParams ($args) { extract($args); $params = array('include_minor_revisions' => $show_minor, 'exclude_major_revisions' => !$show_major, 'include_all_revisions' => !empty($show_all)); if ($limit != 0) $params['limit'] = $limit; if ($days > 0.0) $params['since'] = time() - 24 * 3600 * $days; elseif ($days < 0.0) $params['since'] = 24 * 3600 * $days - time(); return $params; } function getChanges ($dbi, $args) { $changes = $dbi->mostRecent($this->getMostRecentParams($args)); $show_deleted = $args['show_deleted']; if ($show_deleted == 'sometimes') $show_deleted = $args['show_minor']; if (!$show_deleted) $changes = new NonDeletedRevisionIterator($changes, !$args['show_all']); return $changes; } function format ($changes, $args) { global $Theme; $format = $args['format']; $fmt_class = $Theme->getFormatter('RecentChanges', $format); if (!$fmt_class) { if ($format == 'rss') $fmt_class = '_RecentChanges_RssFormatter'; elseif ($format == 'rss091') { include_once "lib/RSSWriter091.php"; $fmt_class = '_RecentChanges_RssFormatter091'; } elseif ($format == 'sidebar') $fmt_class = '_RecentChanges_SideBarFormatter'; else $fmt_class = '_RecentChanges_HtmlFormatter'; } $fmt = new $fmt_class($args); return $fmt->format($changes); } function run($dbi, $argstr, &$request, $basepage) { $args = $this->getArgs($argstr, $request); // HACKish: fix for SF bug #622784 (1000 years of RecentChanges ought // to be enough for anyone.) $args['days'] = min($args['days'], 365000); // Hack alert: format() is a NORETURN for rss formatters. return $this->format($this->getChanges($dbi, $args), $args); } }; class DayButtonBar extends HtmlElement { function DayButtonBar ($plugin_args) { $this->HtmlElement('p', array('class' => 'wiki-rc-action')); // Display days selection buttons extract($plugin_args); // Custom caption if (! $caption) { if ($show_minor) $caption = _("Show minor edits for:"); elseif ($show_all) $caption = _("Show all changes for:"); else $caption = _("Show changes for:"); } $this->pushContent($caption, ' '); global $Theme; $sep = $Theme->getButtonSeparator(); $n = 0; foreach (explode(",", $daylist) as $days) { if ($n++) $this->pushContent($sep); $this->pushContent($this->_makeDayButton($days)); } } function _makeDayButton ($days) { global $Theme, $request; if ($days == 1) $label = _("1 day"); elseif ($days < 1) $label = "..."; //alldays else $label = sprintf(_("%s days"), abs($days)); $url = $request->getURLtoSelf(array('action' => 'browse', 'days' => $days)); return $Theme->makeButton($label, $url, 'wiki-rc-action'); } } // $Log: not supported by cvs2svn $ // Revision 1.84 2004/02/15 22:29:42 rurban // revert premature performance fix // // Revision 1.83 2004/02/15 21:34:37 rurban // PageList enhanced and improved. // fixed new WikiAdmin... plugins // editpage, Theme with exp. htmlarea framework // (htmlarea yet committed, this is really questionable) // WikiUser... code with better session handling for prefs // enhanced UserPreferences (again) // RecentChanges for show_deleted: how should pages be deleted then? // // Revision 1.82 2004/01/25 03:58:43 rurban // use stdlib:isWikiWord() // // Revision 1.81 2003/11/28 21:06:31 carstenklapp // Enhancement: Mozilla RecentChanges sidebar now defaults to 10 changes // instead of 1. Make diff buttons smaller with css. Added description // line back in at the top. // // Revision 1.80 2003/11/27 15:17:01 carstenklapp // Theme & appearance tweaks: Converted Mozilla sidebar link into a Theme // button, to allow an image button for it to be added to Themes. Output // RSS button in small text size when theme has no button image. // // Revision 1.79 2003/04/29 14:34:20 dairiki // Bug fix: "add sidebar" link didn't work when USE_PATH_INFO was false. // // Revision 1.78 2003/03/04 01:55:05 dairiki // Fix to ensure absolute URL for logo in RSS recent changes. // // Revision 1.77 2003/02/27 23:23:38 dairiki // Fix my breakage of CSS and sidebar RecentChanges output. // // Revision 1.76 2003/02/27 22:48:44 dairiki // Fixes invalid HTML generated by PageHistory plugin. // // (