/**
  * @return string A HTML <li> element representing this revision, showing
  * change tags and everything
  */
 public function getHTML()
 {
     $difflink = $this->list->msg('parentheses')->rawParams($this->getDiffLink())->escaped();
     $revlink = $this->getRevisionLink();
     $userlink = Linker::revUserLink($this->revision);
     $comment = Linker::revComment($this->revision);
     if ($this->isDeleted()) {
         $revlink = "<span class=\"history-deleted\">{$revlink}</span>";
     }
     $content = "{$difflink} {$revlink} {$userlink} {$comment}";
     $attribs = array();
     $tags = $this->getTags();
     if ($tags) {
         list($tagSummary, $classes) = ChangeTags::formatSummaryRow($tags, 'edittags');
         $content .= " {$tagSummary}";
         $attribs['class'] = implode(' ', $classes);
     }
     return Xml::tags('li', $attribs, $content);
 }
 /**
  * Format a row, providing the timestamp, links to the page/history, size, user links, and a comment
  *
  * @param $result Result row
  * @return String
  */
 public function formatRow($result)
 {
     $title = Title::newFromRow($result);
     # Revision deletion works on revisions, so we should cast one
     $row = array('comment' => $result->rc_comment, 'deleted' => $result->rc_deleted, 'user_text' => $result->rc_user_text, 'user' => $result->rc_user);
     $rev = new Revision($row);
     $rev->setTitle($title);
     $classes = array();
     $lang = $this->getLanguage();
     $dm = $lang->getDirMark();
     $spanTime = Html::element('span', array('class' => 'mw-newpages-time'), $lang->userTimeAndDate($result->rc_timestamp, $this->getUser()));
     $time = Linker::linkKnown($title, $spanTime, array(), array('oldid' => $result->rc_this_oldid), array());
     $query = array('redirect' => 'no');
     if ($this->patrollable($result)) {
         $query['rcid'] = $result->rc_id;
     }
     // Linker::linkKnown() uses 'known' and 'noclasses' options. This breaks the colouration for stubs.
     $plink = Linker::link($title, null, array('class' => 'mw-newpages-pagename'), $query, array('known'));
     $histLink = Linker::linkKnown($title, $this->msg('hist')->escaped(), array(), array('action' => 'history'));
     $hist = Html::rawElement('span', array('class' => 'mw-newpages-history'), $this->msg('parentheses')->rawParams($histLink)->escaped());
     $length = Html::element('span', array('class' => 'mw-newpages-length'), $this->msg('brackets')->params($this->msg('nbytes')->numParams($result->length)->text()));
     $ulink = Linker::revUserTools($rev);
     $comment = Linker::revComment($rev);
     if ($this->patrollable($result)) {
         $classes[] = 'not-patrolled';
     }
     # Add a class for zero byte pages
     if ($result->length == 0) {
         $classes[] = 'mw-newpages-zero-byte-page';
     }
     # Tags, if any.
     if (isset($result->ts_tags)) {
         list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($result->ts_tags, 'newpages');
         $classes = array_merge($classes, $newClasses);
     } else {
         $tagDisplay = '';
     }
     $css = count($classes) ? ' class="' . implode(' ', $classes) . '"' : '';
     # Display the old title if the namespace/title has been changed
     $oldTitleText = '';
     $oldTitle = Title::makeTitle($result->rc_namespace, $result->rc_title);
     if (!$title->equals($oldTitle)) {
         $oldTitleText = $this->msg('rc-old-title')->params($oldTitle->getPrefixedText())->escaped();
     }
     return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} {$dm}{$ulink} {$comment} {$tagDisplay} {$oldTitleText}</li>\n";
 }
Example #3
0
 /**
  * @param $row Row: a single row from the result set
  * @return String: Formatted HTML list item
  */
 public function logLine($row)
 {
     $classes = array('mw-logline-' . $row->log_type);
     $title = Title::makeTitle($row->log_namespace, $row->log_title);
     // Log time
     $time = $this->logTimestamp($row);
     // User links
     $userLink = $this->logUserLinks($row);
     // Extract extra parameters
     $paramArray = LogPage::extractParams($row->log_params);
     // Event description
     $action = $this->logAction($row, $title, $paramArray);
     // Log comment
     $comment = $this->logComment($row);
     // Add review/revert links and such...
     $revert = $this->logActionLinks($row, $title, $paramArray, $comment);
     // Some user can hide log items and have review links
     $del = $this->getShowHideLinks($row);
     if ($del != '') {
         $del .= ' ';
     }
     // Any tags...
     list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'logevent');
     $classes = array_merge($classes, $newClasses);
     return Xml::tags('li', array("class" => implode(' ', $classes)), $del . "{$time} {$userLink} {$action} {$comment} {$revert} {$tagDisplay}") . "\n";
 }
Example #4
0
 /**
  * Returns a row from the history printout.
  *
  * @todo document some more, and maybe clean up the code (some params redundant?)
  *
  * @param $row Object: the database row corresponding to the previous line.
  * @param $next Mixed: the database row corresponding to the next line. (chronologically previous)
  * @param $notificationtimestamp
  * @param $latest Boolean: whether this row corresponds to the page's latest revision.
  * @param $firstInList Boolean: whether this row corresponds to the first displayed on this history page.
  * @return String: HTML output for the row
  */
 function historyLine($row, $next, $notificationtimestamp = false, $latest = false, $firstInList = false)
 {
     $rev = new Revision($row);
     $rev->setTitle($this->getTitle());
     if (is_object($next)) {
         $prevRev = new Revision($next);
         $prevRev->setTitle($this->getTitle());
     } else {
         $prevRev = null;
     }
     $curlink = $this->curLink($rev, $latest);
     $lastlink = $this->lastLink($rev, $next);
     $diffButtons = $this->diffButtons($rev, $firstInList);
     $histLinks = Html::rawElement('span', array('class' => 'mw-history-histlinks'), '(' . $curlink . $this->historyPage->message['pipe-separator'] . $lastlink . ') ');
     $s = $histLinks . $diffButtons;
     $link = $this->revLink($rev);
     $classes = array();
     $del = '';
     $user = $this->getUser();
     // Show checkboxes for each revision
     if ($user->isAllowed('deleterevision')) {
         $this->preventClickjacking();
         // If revision was hidden from sysops, disable the checkbox
         if (!$rev->userCan(Revision::DELETED_RESTRICTED, $user)) {
             $del = Xml::check('deleterevisions', false, array('disabled' => 'disabled'));
             // Otherwise, enable the checkbox...
         } else {
             $del = Xml::check('showhiderevisions', false, array('name' => 'ids[' . $rev->getId() . ']'));
         }
         // User can only view deleted revisions...
     } elseif ($rev->getVisibility() && $user->isAllowed('deletedhistory')) {
         // If revision was hidden from sysops, disable the link
         if (!$rev->userCan(Revision::DELETED_RESTRICTED, $user)) {
             $cdel = Linker::revDeleteLinkDisabled(false);
             // Otherwise, show the link...
         } else {
             $query = array('type' => 'revision', 'target' => $this->getTitle()->getPrefixedDbkey(), 'ids' => $rev->getId());
             $del .= Linker::revDeleteLink($query, $rev->isDeleted(Revision::DELETED_RESTRICTED), false);
         }
     }
     if ($del) {
         $s .= " {$del} ";
     }
     $lang = $this->getLanguage();
     $dirmark = $lang->getDirMark();
     $s .= " {$link}";
     $s .= $dirmark;
     $s .= " <span class='history-user'>" . Linker::revUserTools($rev, true) . "</span>";
     $s .= $dirmark;
     if ($rev->isMinor()) {
         $s .= ' ' . ChangesList::flag('minor');
     }
     # Size is always public data
     $prevSize = $prevRev ? $prevRev->getSize() : 0;
     $sDiff = ChangesList::showCharacterDifference($prevSize, $rev->getSize());
     $fSize = Linker::formatRevisionSize($rev->getSize());
     $s .= " . . {$fSize} {$sDiff} . . ";
     $s .= Linker::revComment($rev, false, true);
     if ($notificationtimestamp && $row->rev_timestamp >= $notificationtimestamp) {
         $s .= ' <span class="updatedmarker">' . $this->msg('updatedmarker')->escaped() . '</span>';
     }
     $tools = array();
     # Rollback and undo links
     if ($prevRev && !count($this->getTitle()->getUserPermissionsErrors('edit', $this->getUser()))) {
         if ($latest && !count($this->getTitle()->getUserPermissionsErrors('rollback', $this->getUser()))) {
             $this->preventClickjacking();
             $tools[] = '<span class="mw-rollback-link">' . Linker::buildRollbackLink($rev) . '</span>';
         }
         if (!$rev->isDeleted(Revision::DELETED_TEXT) && !$prevRev->isDeleted(Revision::DELETED_TEXT)) {
             # Create undo tooltip for the first (=latest) line only
             $undoTooltip = $latest ? array('title' => $this->msg('tooltip-undo')->text()) : array();
             $undolink = Linker::linkKnown($this->getTitle(), $this->msg('editundo')->escaped(), $undoTooltip, array('action' => 'edit', 'undoafter' => $prevRev->getId(), 'undo' => $rev->getId()));
             $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>";
         }
     }
     if ($tools) {
         $s .= ' (' . $lang->pipeList($tools) . ')';
     }
     # Tags
     list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'history');
     $classes = array_merge($classes, $newClasses);
     $s .= " {$tagSummary}";
     wfRunHooks('PageHistoryLineEnding', array($this, &$row, &$s, &$classes));
     $attribs = array();
     if ($classes) {
         $attribs['class'] = implode(' ', $classes);
     }
     return Xml::tags('li', $attribs, $s) . "\n";
 }
Example #5
0
 /**
  * Generates each row in the contributions list.
  *
  * Contributions which are marked "top" are currently on top of the history.
  * For these contributions, a [rollback] link is shown for users with roll-
  * back privileges. The rollback link restores the most recent version that
  * was not written by the target user.
  *
  * @todo This would probably look a lot nicer in a table.
  * @param object $row
  * @return string
  */
 function formatRow($row)
 {
     $ret = '';
     $classes = [];
     /*
      * There may be more than just revision rows. To make sure that we'll only be processing
      * revisions here, let's _try_ to build a revision out of our row (without displaying
      * notices though) and then trying to grab data from the built object. If we succeed,
      * we're definitely dealing with revision data and we may proceed, if not, we'll leave it
      * to extensions to subscribe to the hook to parse the row.
      */
     MediaWiki\suppressWarnings();
     try {
         $rev = new Revision($row);
         $validRevision = (bool) $rev->getId();
     } catch (Exception $e) {
         $validRevision = false;
     }
     MediaWiki\restoreWarnings();
     if ($validRevision) {
         $classes = [];
         $page = Title::newFromRow($row);
         $link = Linker::link($page, htmlspecialchars($page->getPrefixedText()), ['class' => 'mw-contributions-title'], $page->isRedirect() ? ['redirect' => 'no'] : []);
         # Mark current revisions
         $topmarktext = '';
         $user = $this->getUser();
         if ($row->rev_id === $row->page_latest) {
             $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
             $classes[] = 'mw-contributions-current';
             # Add rollback link
             if (!$row->page_is_new && $page->quickUserCan('rollback', $user) && $page->quickUserCan('edit', $user)) {
                 $this->preventClickjacking();
                 $topmarktext .= ' ' . Linker::generateRollback($rev, $this->getContext());
             }
         }
         # Is there a visible previous revision?
         if ($rev->userCan(Revision::DELETED_TEXT, $user) && $rev->getParentId() !== 0) {
             $difftext = Linker::linkKnown($page, $this->messages['diff'], [], ['diff' => 'prev', 'oldid' => $row->rev_id]);
         } else {
             $difftext = $this->messages['diff'];
         }
         $histlink = Linker::linkKnown($page, $this->messages['hist'], [], ['action' => 'history']);
         if ($row->rev_parent_id === null) {
             // For some reason rev_parent_id isn't populated for this row.
             // Its rumoured this is true on wikipedia for some revisions (bug 34922).
             // Next best thing is to have the total number of bytes.
             $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
             $chardiff .= Linker::formatRevisionSize($row->rev_len);
             $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
         } else {
             $parentLen = 0;
             if (isset($this->mParentLens[$row->rev_parent_id])) {
                 $parentLen = $this->mParentLens[$row->rev_parent_id];
             }
             $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
             $chardiff .= ChangesList::showCharacterDifference($parentLen, $row->rev_len, $this->getContext());
             $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
         }
         $lang = $this->getLanguage();
         $comment = $lang->getDirMark() . Linker::revComment($rev, false, true);
         $date = $lang->userTimeAndDate($row->rev_timestamp, $user);
         if ($rev->userCan(Revision::DELETED_TEXT, $user)) {
             $d = Linker::linkKnown($page, htmlspecialchars($date), ['class' => 'mw-changeslist-date'], ['oldid' => intval($row->rev_id)]);
         } else {
             $d = htmlspecialchars($date);
         }
         if ($rev->isDeleted(Revision::DELETED_TEXT)) {
             $d = '<span class="history-deleted">' . $d . '</span>';
         }
         # Show user names for /newbies as there may be different users.
         # Note that we already excluded rows with hidden user names.
         if ($this->contribs == 'newbie') {
             $userlink = ' . . ' . $lang->getDirMark() . Linker::userLink($rev->getUser(), $rev->getUserText());
             $userlink .= ' ' . $this->msg('parentheses')->rawParams(Linker::userTalkLink($rev->getUser(), $rev->getUserText()))->escaped() . ' ';
         } else {
             $userlink = '';
         }
         $flags = [];
         if ($rev->getParentId() === 0) {
             $flags[] = ChangesList::flag('newpage');
         }
         if ($rev->isMinor()) {
             $flags[] = ChangesList::flag('minor');
         }
         $del = Linker::getRevDeleteLink($user, $rev, $page);
         if ($del !== '') {
             $del .= ' ';
         }
         $diffHistLinks = $this->msg('parentheses')->rawParams($difftext . $this->messages['pipe-separator'] . $histlink)->escaped();
         # Tags, if any.
         list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'contributions', $this->getContext());
         $classes = array_merge($classes, $newClasses);
         Hooks::run('SpecialContributions::formatRow::flags', [$this->getContext(), $row, &$flags]);
         $templateParams = ['del' => $del, 'timestamp' => $d, 'diffHistLinks' => $diffHistLinks, 'charDifference' => $chardiff, 'flags' => $flags, 'articleLink' => $link, 'userlink' => $userlink, 'logText' => $comment, 'topmarktext' => $topmarktext, 'tagSummary' => $tagSummary];
         # Denote if username is redacted for this edit
         if ($rev->isDeleted(Revision::DELETED_USER)) {
             $templateParams['rev-deleted-user-contribs'] = $this->msg('rev-deleted-user-contribs')->escaped();
         }
         $templateParser = new TemplateParser();
         $ret = $templateParser->processTemplate('SpecialContributionsLine', $templateParams);
     }
     // Let extensions add data
     Hooks::run('ContributionsLineEnding', [$this, &$ret, $row, &$classes]);
     // TODO: Handle exceptions in the catch block above.  Do any extensions rely on
     // receiving empty rows?
     if ($classes === [] && $ret === '') {
         wfDebug("Dropping Special:Contribution row that could not be formatted\n");
         return "<!-- Could not format Special:Contribution row. -->\n";
     }
     // FIXME: The signature of the ContributionsLineEnding hook makes it
     // very awkward to move this LI wrapper into the template.
     return Html::rawElement('li', ['class' => $classes], $ret) . "\n";
 }
Example #6
0
 /**
  * Format a row, providing the timestamp, links to the page/history, size, user links, and a comment
  *
  * @param $result Result row
  * @return String
  */
 public function formatRow($result)
 {
     global $wgLang;
     # Revision deletion works on revisions, so we should cast one
     $row = array('comment' => $result->rc_comment, 'deleted' => $result->rc_deleted, 'user_text' => $result->rc_user_text, 'user' => $result->rc_user);
     $rev = new Revision($row);
     $classes = array();
     $dm = $wgLang->getDirMark();
     $title = Title::makeTitleSafe($result->rc_namespace, $result->rc_title);
     $time = Html::element('span', array('class' => 'mw-newpages-time'), $wgLang->timeAndDate($result->rc_timestamp, true));
     $query = array('redirect' => 'no');
     if ($this->patrollable($result)) {
         $query['rcid'] = $result->rc_id;
     }
     $plink = $this->getSkin()->linkKnown($title, null, array('class' => 'mw-newpages-pagename'), $query, array('known'));
     $histLink = $this->getSkin()->linkKnown($title, wfMsgHtml('hist'), array(), array('action' => 'history'));
     $hist = Html::rawElement('span', array('class' => 'mw-newpages-history'), wfMsg('parentheses', $histLink));
     $length = Html::rawElement('span', array('class' => 'mw-newpages-length'), '[' . wfMsgExt('nbytes', array('parsemag', 'escape'), $wgLang->formatNum($result->length)) . ']');
     $ulink = $this->getSkin()->revUserTools($rev);
     $comment = $this->getSkin()->revComment($rev);
     if ($this->patrollable($result)) {
         $classes[] = 'not-patrolled';
     }
     # Add a class for zero byte pages
     if ($result->length == 0) {
         $classes[] = 'mw-newpages-zero-byte-page';
     }
     # Tags, if any. check for including due to bug 23293
     if (!$this->including()) {
         list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($result->ts_tags, 'newpages');
         $classes = array_merge($classes, $newClasses);
     } else {
         $tagDisplay = '';
     }
     $css = count($classes) ? ' class="' . implode(' ', $classes) . '"' : '';
     return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} {$dm}{$ulink} {$comment} {$tagDisplay}</li>\n";
 }
Example #7
0
 /**
  * @param $s string
  * @param $rc RecentChange
  * @param $classes
  */
 public function insertTags(&$s, &$rc, &$classes)
 {
     if (empty($rc->mAttribs['ts_tags'])) {
         return;
     }
     list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($rc->mAttribs['ts_tags'], 'changeslist');
     $classes = array_merge($classes, $newClasses);
     $s .= ' ' . $tagSummary;
 }
 /**
  * Returns a row from the history printout.
  *
  * @todo document some more, and maybe clean up the code (some params redundant?)
  *
  * @param stdClass $row The database row corresponding to the previous line.
  * @param mixed $next The database row corresponding to the next line
  *   (chronologically previous)
  * @param bool|string $notificationtimestamp
  * @param bool $latest Whether this row corresponds to the page's latest revision.
  * @param bool $firstInList Whether this row corresponds to the first
  *   displayed on this history page.
  * @return string HTML output for the row
  */
 function historyLine($row, $next, $notificationtimestamp = false, $latest = false, $firstInList = false)
 {
     $rev = new Revision($row);
     $rev->setTitle($this->getTitle());
     if (is_object($next)) {
         $prevRev = new Revision($next);
         $prevRev->setTitle($this->getTitle());
     } else {
         $prevRev = null;
     }
     $curlink = $this->curLink($rev, $latest);
     $lastlink = $this->lastLink($rev, $next);
     $curLastlinks = $curlink . $this->historyPage->message['pipe-separator'] . $lastlink;
     $histLinks = Html::rawElement('span', array('class' => 'mw-history-histlinks'), $this->msg('parentheses')->rawParams($curLastlinks)->escaped());
     $diffButtons = $this->diffButtons($rev, $firstInList);
     $s = $histLinks . $diffButtons;
     $link = $this->revLink($rev);
     $classes = array();
     $del = '';
     $user = $this->getUser();
     // Show checkboxes for each revision
     if ($user->isAllowed('deleterevision')) {
         $this->preventClickjacking();
         // If revision was hidden from sysops, disable the checkbox
         if (!$rev->userCan(Revision::DELETED_RESTRICTED, $user)) {
             $del = Xml::check('deleterevisions', false, array('disabled' => 'disabled'));
             // Otherwise, enable the checkbox...
         } else {
             $del = Xml::check('showhiderevisions', false, array('name' => 'ids[' . $rev->getId() . ']'));
         }
         // User can only view deleted revisions...
     } elseif ($rev->getVisibility() && $user->isAllowed('deletedhistory')) {
         // If revision was hidden from sysops, disable the link
         if (!$rev->userCan(Revision::DELETED_RESTRICTED, $user)) {
             $del = Linker::revDeleteLinkDisabled(false);
             // Otherwise, show the link...
         } else {
             $query = array('type' => 'revision', 'target' => $this->getTitle()->getPrefixedDBkey(), 'ids' => $rev->getId());
             $del .= Linker::revDeleteLink($query, $rev->isDeleted(Revision::DELETED_RESTRICTED), false);
         }
     }
     if ($del) {
         $s .= " {$del} ";
     }
     $lang = $this->getLanguage();
     $dirmark = $lang->getDirMark();
     $s .= " {$link}";
     $s .= $dirmark;
     $s .= " <span class='history-user'>" . Linker::revUserTools($rev, true) . "</span>";
     $s .= $dirmark;
     if ($rev->isMinor()) {
         $s .= ' ' . ChangesList::flag('minor');
     }
     # Sometimes rev_len isn't populated
     if ($rev->getSize() !== null) {
         # Size is always public data
         $prevSize = isset($this->parentLens[$row->rev_parent_id]) ? $this->parentLens[$row->rev_parent_id] : 0;
         $sDiff = ChangesList::showCharacterDifference($prevSize, $rev->getSize());
         $fSize = Linker::formatRevisionSize($rev->getSize());
         $s .= ' <span class="mw-changeslist-separator">. .</span> ' . "{$fSize} {$sDiff}";
     }
     # Text following the character difference is added just before running hooks
     $s2 = Linker::revComment($rev, false, true);
     if ($notificationtimestamp && $row->rev_timestamp >= $notificationtimestamp) {
         $s2 .= ' <span class="updatedmarker">' . $this->msg('updatedmarker')->escaped() . '</span>';
         $classes[] = 'mw-history-line-updated';
     }
     $tools = array();
     # Rollback and undo links
     if ($prevRev && $this->getTitle()->quickUserCan('edit', $user)) {
         if ($latest && $this->getTitle()->quickUserCan('rollback', $user)) {
             // Get a rollback link without the brackets
             $rollbackLink = Linker::generateRollback($rev, $this->getContext(), array('verify', 'noBrackets'));
             if ($rollbackLink) {
                 $this->preventClickjacking();
                 $tools[] = $rollbackLink;
             }
         }
         if (!$rev->isDeleted(Revision::DELETED_TEXT) && !$prevRev->isDeleted(Revision::DELETED_TEXT)) {
             # Create undo tooltip for the first (=latest) line only
             $undoTooltip = $latest ? array('title' => $this->msg('tooltip-undo')->text()) : array();
             $undolink = Linker::linkKnown($this->getTitle(), $this->msg('editundo')->escaped(), $undoTooltip, array('action' => 'edit', 'undoafter' => $prevRev->getId(), 'undo' => $rev->getId()));
             $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>";
         }
     }
     // Allow extension to add their own links here
     wfRunHooks('HistoryRevisionTools', array($rev, &$tools));
     if ($tools) {
         $s2 .= ' ' . $this->msg('parentheses')->rawParams($lang->pipeList($tools))->escaped();
     }
     # Tags
     list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'history');
     $classes = array_merge($classes, $newClasses);
     if ($tagSummary !== '') {
         $s2 .= " {$tagSummary}";
     }
     # Include separator between character difference and following text
     if ($s2 !== '') {
         $s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2;
     }
     wfRunHooks('PageHistoryLineEnding', array($this, &$row, &$s, &$classes));
     $attribs = array();
     if ($classes) {
         $attribs['class'] = implode(' ', $classes);
     }
     return Xml::tags('li', $attribs, $s) . "\n";
 }
Example #9
0
 /**
  * Generates each row in the contributions list.
  *
  * Contributions which are marked "top" are currently on top of the history.
  * For these contributions, a [rollback] link is shown for users with roll-
  * back privileges. The rollback link restores the most recent version that
  * was not written by the target user.
  *
  * @todo This would probably look a lot nicer in a table.
  */
 function formatRow($row)
 {
     global $wgLang, $wgUser, $wgContLang;
     wfProfileIn(__METHOD__);
     $sk = $this->getSkin();
     $rev = new Revision($row);
     $classes = array();
     $page = Title::newFromRow($row);
     $page->resetArticleId($row->rev_page);
     // use process cache
     $link = $sk->makeLinkObj($page, $page->getPrefixedText(), $page->isRedirect() ? 'redirect=no' : '');
     # Mark current revisions
     $difftext = $topmarktext = '';
     if ($row->rev_id == $row->page_latest) {
         $topmarktext .= '<strong>' . $this->messages['uctop'] . '</strong>';
         if (!$row->page_is_new) {
             $difftext .= '(' . $sk->makeKnownLinkObj($page, $this->messages['diff'], 'diff=0') . ')';
             # Add rollback link
             if ($page->quickUserCan('rollback') && $page->quickUserCan('edit')) {
                 $topmarktext .= ' ' . $sk->generateRollback($rev);
             }
         } else {
             $difftext .= $this->messages['newarticle'];
         }
     }
     # Is there a visible previous revision?
     if ($rev->userCan(Revision::DELETED_TEXT)) {
         $difftext = '(' . $sk->makeKnownLinkObj($page, $this->messages['diff'], 'diff=prev&oldid=' . $row->rev_id) . ')';
     } else {
         $difftext = '(' . $this->messages['diff'] . ')';
     }
     $histlink = '(' . $sk->makeKnownLinkObj($page, $this->messages['hist'], 'action=history') . ')';
     $comment = $wgContLang->getDirMark() . $sk->revComment($rev, false, true);
     $date = $wgLang->timeanddate(wfTimestamp(TS_MW, $row->rev_timestamp), true);
     $d = $sk->makeKnownLinkObj($page, $date, 'oldid=' . intval($row->rev_id));
     if ($this->target == 'newbies') {
         $userlink = ' . . ' . $sk->userLink($row->rev_user, $row->rev_user_text);
         $userlink .= ' (' . $sk->userTalkLink($row->rev_user, $row->rev_user_text) . ') ';
     } else {
         $userlink = '';
     }
     if ($rev->isDeleted(Revision::DELETED_TEXT)) {
         $d = '<span class="history-deleted">' . $d . '</span>';
     }
     if ($rev->getParentId() === 0) {
         $nflag = '<span class="newpage">' . $this->messages['newpageletter'] . '</span>';
     } else {
         $nflag = '';
     }
     if ($rev->isMinor()) {
         $mflag = '<span class="minor">' . $this->messages['minoreditletter'] . '</span> ';
     } else {
         $mflag = '';
     }
     $ret = "{$d} {$histlink} {$difftext} {$nflag}{$mflag} {$link}{$userlink} {$comment} {$topmarktext}";
     if ($rev->isDeleted(Revision::DELETED_TEXT)) {
         $ret .= ' ' . wfMsgHtml('deletedrev');
     }
     # Tags, if any.
     list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'contributions');
     $classes = array_merge($classes, $newClasses);
     $ret .= " {$tagSummary}";
     // Let extensions add data
     wfRunHooks('ContributionsLineEnding', array(&$this, &$ret, $row));
     $classes = implode(' ', $classes);
     $ret = "<li class=\"{$classes}\">{$ret}</li>\n";
     wfProfileOut(__METHOD__);
     return $ret;
 }
Example #10
0
 /**
  * Format a row, providing the timestamp, links to the page/history, size, user links, and a comment
  *
  * @param $skin Skin to use
  * @param $result Result row
  * @return string
  */
 public function formatRow($result)
 {
     global $wgLang, $wgContLang, $wgUser;
     $classes = array();
     $dm = $wgContLang->getDirMark();
     $title = Title::makeTitleSafe($result->rc_namespace, $result->rc_title);
     $time = $wgLang->timeAndDate($result->rc_timestamp, true);
     $query = $this->patrollable($result) ? "rcid={$result->rc_id}&redirect=no" : 'redirect=no';
     $plink = $this->skin->makeKnownLinkObj($title, '', $query);
     $hist = $this->skin->makeKnownLinkObj($title, wfMsgHtml('hist'), 'action=history');
     $length = wfMsgExt('nbytes', array('parsemag', 'escape'), $wgLang->formatNum($result->length));
     $ulink = $this->skin->userLink($result->rc_user, $result->rc_user_text) . ' ' . $this->skin->userToolLinks($result->rc_user, $result->rc_user_text);
     $comment = $this->skin->commentBlock($result->rc_comment);
     if ($this->patrollable($result)) {
         $classes[] = 'not-patrolled';
     }
     # Tags, if any.
     list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($result->ts_tags, 'newpages');
     $classes = array_merge($classes, $newClasses);
     $css = count($classes) ? ' class="' . implode(" ", $classes) . '"' : '';
     return "<li{$css}>{$time} {$dm}{$plink} ({$hist}) {$dm}[{$length}] {$dm}{$ulink} {$comment} {$tagDisplay}</li>\n";
 }
Example #11
0
 /**
  * @param $row Row: a single row from the result set
  * @return String: Formatted HTML list item
  */
 public function logLine($row)
 {
     # start wikia change
     $this->fixUserName($row);
     # end wikia change
     $entry = DatabaseLogEntry::newFromRow($row);
     $formatter = LogFormatter::newFromEntry($entry);
     $formatter->setShowUserToolLinks(!($this->flags & self::NO_EXTRA_USER_LINKS));
     $action = $formatter->getActionText();
     $comment = $formatter->getComment();
     $classes = array('mw-logline-' . $entry->getType());
     $title = $entry->getTarget();
     $time = $this->logTimestamp($entry);
     // Extract extra parameters
     $paramArray = LogPage::extractParams($row->log_params);
     // Add review/revert links and such...
     $revert = $this->logActionLinks($row, $title, $paramArray, $comment);
     // Some user can hide log items and have review links
     $del = $this->getShowHideLinks($row);
     if ($del != '') {
         $del .= ' ';
     }
     // Any tags...
     list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'logevent');
     $classes = array_merge($classes, $newClasses);
     return Xml::tags('li', array("class" => implode(' ', $classes)), $del . "{$time} {$action} {$comment} {$revert} {$tagDisplay}") . "\n";
 }
Example #12
0
 /**
  * @return string A HTML <li> element representing this revision, showing
  * change tags and everything
  */
 public function getHTML()
 {
     $date = htmlspecialchars($this->list->getLanguage()->userTimeAndDate($this->row->log_timestamp, $this->list->getUser()));
     $title = Title::makeTitle($this->row->log_namespace, $this->row->log_title);
     $formatter = LogFormatter::newFromRow($this->row);
     $formatter->setContext($this->list->getContext());
     $formatter->setAudience(LogFormatter::FOR_THIS_USER);
     // Log link for this page
     $loglink = Linker::link(SpecialPage::getTitleFor('Log'), $this->list->msg('log')->escaped(), array(), array('page' => $title->getPrefixedText()));
     $loglink = $this->list->msg('parentheses')->rawParams($loglink)->escaped();
     // User links and action text
     $action = $formatter->getActionText();
     // Comment
     $comment = $this->list->getLanguage()->getDirMark() . $formatter->getComment();
     if (LogEventsList::isDeleted($this->row, LogPage::DELETED_COMMENT)) {
         $comment = '<span class="history-deleted">' . $comment . '</span>';
     }
     $content = "{$loglink} {$date} {$action} {$comment}";
     $attribs = array();
     $tags = $this->getTags();
     if ($tags) {
         list($tagSummary, $classes) = ChangeTags::formatSummaryRow($tags, 'edittags', $this->list->getContext());
         $content .= " {$tagSummary}";
         $attribs['class'] = implode(' ', $classes);
     }
     return Xml::tags('li', $attribs, $content);
 }
Example #13
0
 /**
  * @param $row Row: a single row from the result set
  * @return String: Formatted HTML list item
  */
 public function logLine($row)
 {
     global $wgLang, $wgUser, $wgContLang;
     $title = Title::makeTitle($row->log_namespace, $row->log_title);
     $classes = array("mw-logline-{$row->log_type}");
     $time = $wgLang->timeanddate(wfTimestamp(TS_MW, $row->log_timestamp), true);
     // User links
     if (self::isDeleted($row, LogPage::DELETED_USER)) {
         $userLink = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-user') . '</span>';
     } else {
         $userLink = $this->skin->userLink($row->log_user, $row->user_name) . $this->skin->userToolLinks($row->log_user, $row->user_name, true, 0, $row->user_editcount);
     }
     // Comment
     if (self::isDeleted($row, LogPage::DELETED_COMMENT)) {
         $comment = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-comment') . '</span>';
     } else {
         $comment = $wgContLang->getDirMark() . $this->skin->commentBlock($row->log_comment);
     }
     // Extract extra parameters
     $paramArray = LogPage::extractParams($row->log_params);
     $revert = $del = '';
     // Some user can hide log items and have review links
     if ($wgUser->isAllowed('deleterevision')) {
         $del = $this->getShowHideLinks($row) . ' ';
     }
     // Add review links and such...
     if ($this->flags & self::NO_ACTION_LINK || $row->log_deleted & LogPage::DELETED_ACTION) {
         // Action text is suppressed...
     } else {
         if (self::typeAction($row, 'move', 'move', 'move') && !empty($paramArray[0])) {
             $destTitle = Title::newFromText($paramArray[0]);
             if ($destTitle) {
                 $revert = '(' . $this->skin->makeKnownLinkObj(SpecialPage::getTitleFor('Movepage'), $this->message['revertmove'], 'wpOldTitle=' . urlencode($destTitle->getPrefixedDBkey()) . '&wpNewTitle=' . urlencode($title->getPrefixedDBkey()) . '&wpReason=' . urlencode(wfMsgForContent('revertmove')) . '&wpMovetalk=0') . ')';
             }
             // Show undelete link
         } else {
             if (self::typeAction($row, array('delete', 'suppress'), 'delete', 'delete')) {
                 $revert = '(' . $this->skin->makeKnownLinkObj(SpecialPage::getTitleFor('Undelete'), $this->message['undeletelink'], 'target=' . urlencode($title->getPrefixedDBkey())) . ')';
                 // Show unblock/change block link
             } else {
                 if (self::typeAction($row, array('block', 'suppress'), array('block', 'reblock'), 'block')) {
                     $revert = '(' . $this->skin->link(SpecialPage::getTitleFor('Ipblocklist'), $this->message['unblocklink'], array(), array('action' => 'unblock', 'ip' => $row->log_title), 'known') . $this->message['pipe-separator'] . $this->skin->link(SpecialPage::getTitleFor('Blockip', $row->log_title), $this->message['change-blocklink'], array(), array(), 'known') . ')';
                     // Show change protection link
                 } else {
                     if (self::typeAction($row, 'protect', array('modify', 'protect', 'unprotect'))) {
                         $revert .= ' (' . $this->skin->link($title, $this->message['hist'], array(), array('action' => 'history', 'offset' => $row->log_timestamp));
                         if ($wgUser->isAllowed('protect')) {
                             $revert .= $this->message['pipe-separator'] . $this->skin->link($title, $this->message['protect_change'], array(), array('action' => 'protect'), 'known');
                         }
                         $revert .= ')';
                         // Show unmerge link
                     } else {
                         if (self::typeAction($row, 'merge', 'merge', 'mergehistory')) {
                             $merge = SpecialPage::getTitleFor('Mergehistory');
                             $revert = '(' . $this->skin->makeKnownLinkObj($merge, $this->message['revertmerge'], wfArrayToCGI(array('target' => $paramArray[0], 'dest' => $title->getPrefixedDBkey(), 'mergepoint' => $paramArray[1]))) . ')';
                             // If an edit was hidden from a page give a review link to the history
                         } else {
                             if (self::typeAction($row, array('delete', 'suppress'), 'revision', 'deleterevision')) {
                                 if (count($paramArray) == 2) {
                                     $revdel = SpecialPage::getTitleFor('Revisiondelete');
                                     // Different revision types use different URL params...
                                     $key = $paramArray[0];
                                     // Link to each hidden object ID, $paramArray[1] is the url param
                                     $Ids = explode(',', $paramArray[1]);
                                     $revParams = '';
                                     foreach ($Ids as $n => $id) {
                                         $revParams .= '&' . urlencode($key) . '[]=' . urlencode($id);
                                     }
                                     $revert = array();
                                     // Diff link for single rev deletions
                                     if ($key === 'oldid' && count($Ids) == 1) {
                                         $token = urlencode($wgUser->editToken(intval($Ids[0])));
                                         $revert[] = $this->skin->makeKnownLinkObj($title, $this->message['diff'], 'diff=' . intval($Ids[0]) . "&unhide=1&token={$token}");
                                     }
                                     // View/modify link...
                                     $revert[] = $this->skin->makeKnownLinkObj($revdel, $this->message['revdel-restore'], 'target=' . $title->getPrefixedUrl() . $revParams);
                                     $revert = '(' . implode(' | ', $revert) . ')';
                                 }
                                 // Hidden log items, give review link
                             } else {
                                 if (self::typeAction($row, array('delete', 'suppress'), 'event', 'deleterevision')) {
                                     if (count($paramArray) == 1) {
                                         $revdel = SpecialPage::getTitleFor('Revisiondelete');
                                         $Ids = explode(',', $paramArray[0]);
                                         // Link to each hidden object ID, $paramArray[1] is the url param
                                         $logParams = '';
                                         foreach ($Ids as $n => $id) {
                                             $logParams .= '&logid[]=' . intval($id);
                                         }
                                         $revert = '(' . $this->skin->makeKnownLinkObj($revdel, $this->message['revdel-restore'], 'target=' . $title->getPrefixedUrl() . $logParams) . ')';
                                     }
                                     // Self-created users
                                 } else {
                                     if (self::typeAction($row, 'newusers', 'create2')) {
                                         if (isset($paramArray[0])) {
                                             $revert = $this->skin->userToolLinks($paramArray[0], $title->getDBkey(), true);
                                         } else {
                                             # Fall back to a blue contributions link
                                             $revert = $this->skin->userToolLinks(1, $title->getDBkey());
                                         }
                                         if ($time < '20080129000000') {
                                             # Suppress $comment from old entries (before 2008-01-29),
                                             # not needed and can contain incorrect links
                                             $comment = '';
                                         }
                                         // Do nothing. The implementation is handled by the hook modifiying the passed-by-ref parameters.
                                     } else {
                                         wfRunHooks('LogLine', array($row->log_type, $row->log_action, $title, $paramArray, &$comment, &$revert, $row->log_timestamp));
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     // Event description
     if (self::isDeleted($row, LogPage::DELETED_ACTION)) {
         $action = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>';
     } else {
         $action = LogPage::actionText($row->log_type, $row->log_action, $title, $this->skin, $paramArray, true);
     }
     // Any tags...
     list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'logevent');
     $classes = array_merge($classes, $newClasses);
     if ($revert != '') {
         $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
     }
     return Xml::tags('li', array("class" => implode(' ', $classes)), $del . $time . ' ' . $userLink . ' ' . $action . ' ' . $comment . ' ' . $revert . " {$tagDisplay}") . "\n";
 }
Example #14
0
 /**
  * @param stdClass $row A single row from the result set
  * @return string Formatted HTML list item
  */
 public function logLine($row)
 {
     $entry = DatabaseLogEntry::newFromRow($row);
     $formatter = LogFormatter::newFromEntry($entry);
     $formatter->setContext($this->getContext());
     $formatter->setShowUserToolLinks(!($this->flags & self::NO_EXTRA_USER_LINKS));
     $time = htmlspecialchars($this->getLanguage()->userTimeAndDate($entry->getTimestamp(), $this->getUser()));
     $action = $formatter->getActionText();
     if ($this->flags & self::NO_ACTION_LINK) {
         $revert = '';
     } else {
         $revert = $formatter->getActionLinks();
         if ($revert != '') {
             $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
         }
     }
     $comment = $formatter->getComment();
     // Some user can hide log items and have review links
     $del = $this->getShowHideLinks($row);
     // Any tags...
     list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'logevent', $this->getContext());
     $classes = array_merge(array('mw-logline-' . $entry->getType()), $newClasses);
     return Html::rawElement('li', array('class' => $classes), "{$del} {$time} {$action} {$comment} {$revert} {$tagDisplay}") . "\n";
 }
 /**
  * Format a row, providing the timestamp, links to the page/history, size, user links, and a comment
  *
  * @param $result Result row
  * @return String
  */
 public function formatRow($result)
 {
     # Revision deletion works on revisions, so we should cast one
     $row = array('comment' => $result->rc_comment, 'deleted' => $result->rc_deleted, 'user_text' => $result->rc_user_text, 'user' => $result->rc_user);
     $rev = new Revision($row);
     $classes = array();
     $lang = $this->getLanguage();
     $dm = $lang->getDirMark();
     $title = Title::newFromRow($result);
     $spanTime = Html::element('span', array('class' => 'mw-newpages-time'), $lang->timeanddate($result->rc_timestamp, true));
     $time = Linker::linkKnown($title, $spanTime, array(), array('oldid' => $result->rc_this_oldid), array());
     $query = array('redirect' => 'no');
     if ($this->patrollable($result)) {
         $query['rcid'] = $result->rc_id;
     }
     $plink = Linker::linkKnown($title, null, array('class' => 'mw-newpages-pagename'), $query, array('known'));
     $histLink = Linker::linkKnown($title, wfMsgHtml('hist'), array(), array('action' => 'history'));
     $hist = Html::rawElement('span', array('class' => 'mw-newpages-history'), wfMsg('parentheses', $histLink));
     $length = Html::element('span', array('class' => 'mw-newpages-length'), '[' . $this->msg('nbytes')->numParams($result->length)->text() . ']');
     $ulink = Linker::revUserTools($rev);
     $comment = Linker::revComment($rev);
     if ($this->patrollable($result)) {
         $classes[] = 'not-patrolled';
     }
     # Add a class for zero byte pages
     if ($result->length == 0) {
         $classes[] = 'mw-newpages-zero-byte-page';
     }
     # Tags, if any. check for including due to bug 23293
     if (!$this->including()) {
         list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($result->ts_tags, 'newpages');
         $classes = array_merge($classes, $newClasses);
     } else {
         $tagDisplay = '';
     }
     $css = count($classes) ? ' class="' . implode(' ', $classes) . '"' : '';
     # Display the old title if the namespace has been changed
     $oldTitleText = '';
     if ($result->page_namespace !== $result->rc_namespace) {
         $oldTitleText = wfMessage('rc-old-title')->params(Title::makeTitle($result->rc_namespace, $result->rc_title)->getPrefixedText())->escaped();
     }
     return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} {$dm}{$ulink} {$comment} {$tagDisplay} {$oldTitleText}</li>\n";
 }
 /**
  * Generates each row in the contributions list.
  *
  * Contributions which are marked "top" are currently on top of the history.
  * For these contributions, a [rollback] link is shown for users with roll-
  * back privileges. The rollback link restores the most recent version that
  * was not written by the target user.
  *
  * @todo This would probably look a lot nicer in a table.
  * @param $row
  * @return string
  */
 function formatRow($row)
 {
     wfProfileIn(__METHOD__);
     $ret = '';
     $classes = array();
     /*
      * There may be more than just revision rows. To make sure that we'll only be processing
      * revisions here, let's _try_ to build a revision out of our row (without displaying
      * notices though) and then trying to grab data from the built object. If we succeed,
      * we're definitely dealing with revision data and we may proceed, if not, we'll leave it
      * to extensions to subscribe to the hook to parse the row.
      */
     wfSuppressWarnings();
     $rev = new Revision($row);
     $validRevision = $rev->getParentId() !== null;
     wfRestoreWarnings();
     if ($validRevision) {
         $classes = array();
         $page = Title::newFromRow($row);
         $link = Linker::link($page, htmlspecialchars($page->getPrefixedText()), array('class' => 'mw-contributions-title'), $page->isRedirect() ? array('redirect' => 'no') : array());
         # Mark current revisions
         $topmarktext = '';
         $user = $this->getUser();
         if ($row->rev_id == $row->page_latest) {
             $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
             # Add rollback link
             if (!$row->page_is_new && $page->quickUserCan('rollback', $user) && $page->quickUserCan('edit', $user)) {
                 $this->preventClickjacking();
                 $topmarktext .= ' ' . Linker::generateRollback($rev, $this->getContext());
             }
         }
         # Is there a visible previous revision?
         if ($rev->userCan(Revision::DELETED_TEXT, $user) && $rev->getParentId() !== 0) {
             $difftext = Linker::linkKnown($page, $this->messages['diff'], array(), array('diff' => 'prev', 'oldid' => $row->rev_id));
         } else {
             $difftext = $this->messages['diff'];
         }
         $histlink = Linker::linkKnown($page, $this->messages['hist'], array(), array('action' => 'history'));
         if ($row->rev_parent_id === null) {
             // For some reason rev_parent_id isn't populated for this row.
             // Its rumoured this is true on wikipedia for some revisions (bug 34922).
             // Next best thing is to have the total number of bytes.
             $chardiff = ' <span class="mw-changeslist-separator">. .</span> ' . Linker::formatRevisionSize($row->rev_len) . ' <span class="mw-changeslist-separator">. .</span> ';
         } else {
             $parentLen = isset($this->mParentLens[$row->rev_parent_id]) ? $this->mParentLens[$row->rev_parent_id] : 0;
             $chardiff = ' <span class="mw-changeslist-separator">. .</span> ' . ChangesList::showCharacterDifference($parentLen, $row->rev_len, $this->getContext()) . ' <span class="mw-changeslist-separator">. .</span> ';
         }
         $lang = $this->getLanguage();
         $comment = $lang->getDirMark() . Linker::revComment($rev, false, true);
         $date = $lang->userTimeAndDate($row->rev_timestamp, $user);
         if ($rev->userCan(Revision::DELETED_TEXT, $user)) {
             $d = Linker::linkKnown($page, htmlspecialchars($date), array('class' => 'mw-changeslist-date'), array('oldid' => intval($row->rev_id)));
         } else {
             $d = htmlspecialchars($date);
         }
         if ($rev->isDeleted(Revision::DELETED_TEXT)) {
             $d = '<span class="history-deleted">' . $d . '</span>';
         }
         # Show user names for /newbies as there may be different users.
         # Note that we already excluded rows with hidden user names.
         if ($this->contribs == 'newbie') {
             $userlink = ' . . ' . Linker::userLink($rev->getUser(), $rev->getUserText());
             $userlink .= ' ' . $this->msg('parentheses')->rawParams(Linker::userTalkLink($rev->getUser(), $rev->getUserText()))->escaped() . ' ';
         } else {
             $userlink = '';
         }
         if ($rev->getParentId() === 0) {
             $nflag = ChangesList::flag('newpage');
         } else {
             $nflag = '';
         }
         if ($rev->isMinor()) {
             $mflag = ChangesList::flag('minor');
         } else {
             $mflag = '';
         }
         $del = Linker::getRevDeleteLink($user, $rev, $page);
         if ($del !== '') {
             $del .= ' ';
         }
         $diffHistLinks = $this->msg('parentheses')->rawParams($difftext . $this->messages['pipe-separator'] . $histlink)->escaped();
         $ret = "{$del}{$d} {$diffHistLinks}{$chardiff}{$nflag}{$mflag} {$link}{$userlink} {$comment} {$topmarktext}";
         # Denote if username is redacted for this edit
         if ($rev->isDeleted(Revision::DELETED_USER)) {
             $ret .= " <strong>" . $this->msg('rev-deleted-user-contribs')->escaped() . "</strong>";
         }
         # Tags, if any.
         list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'contributions');
         $classes = array_merge($classes, $newClasses);
         $ret .= " {$tagSummary}";
     }
     // Let extensions add data
     wfRunHooks('ContributionsLineEnding', array($this, &$ret, $row, &$classes));
     $classes = implode(' ', $classes);
     $ret = "<li class=\"{$classes}\">{$ret}</li>\n";
     wfProfileOut(__METHOD__);
     return $ret;
 }
Example #17
0
 /**
  * Returns a row from the history printout.
  *
  * @todo document some more, and maybe clean up the code (some params redundant?)
  *
  * @param $row Object: the database row corresponding to the previous line.
  * @param $next Mixed: the database row corresponding to the next line.
  * @param $notificationtimestamp
  * @param $latest Boolean: whether this row corresponds to the page's latest revision.
  * @param $firstInList Boolean: whether this row corresponds to the first displayed on this history page.
  * @return String: HTML output for the row
  */
 function historyLine($row, $next, $notificationtimestamp = false, $latest = false, $firstInList = false)
 {
     global $wgUser, $wgLang;
     $rev = new Revision($row);
     $rev->setTitle($this->title);
     $curlink = $this->curLink($rev, $latest);
     $lastlink = $this->lastLink($rev, $next);
     $diffButtons = $this->diffButtons($rev, $firstInList);
     $histLinks = Html::rawElement('span', array('class' => 'mw-history-histlinks'), '(' . $curlink . $this->historyPage->message['pipe-separator'] . $lastlink . ') ');
     $s = $histLinks . $diffButtons;
     $link = $this->revLink($rev);
     $classes = array();
     $del = '';
     // Show checkboxes for each revision
     if ($wgUser->isAllowed('deleterevision')) {
         $this->preventClickjacking();
         // If revision was hidden from sysops, disable the checkbox
         if (!$rev->userCan(Revision::DELETED_RESTRICTED)) {
             $del = Xml::check('deleterevisions', false, array('disabled' => 'disabled'));
             // Otherwise, enable the checkbox...
         } else {
             $del = Xml::check('showhiderevisions', false, array('name' => 'ids[' . $rev->getId() . ']'));
         }
         // User can only view deleted revisions...
     } else {
         if ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) {
             // If revision was hidden from sysops, disable the link
             if (!$rev->userCan(Revision::DELETED_RESTRICTED)) {
                 $cdel = $this->getSkin()->revDeleteLinkDisabled(false);
                 // Otherwise, show the link...
             } else {
                 $query = array('type' => 'revision', 'target' => $this->title->getPrefixedDbkey(), 'ids' => $rev->getId());
                 $del .= $this->getSkin()->revDeleteLink($query, $rev->isDeleted(Revision::DELETED_RESTRICTED), false);
             }
         }
     }
     if ($del) {
         $s .= " {$del} ";
     }
     $s .= " {$link}";
     $s .= " <span class='history-user'>" . $this->getSkin()->revUserTools($rev, true) . "</span>";
     if ($rev->isMinor()) {
         $s .= ' ' . ChangesList::flag('minor');
     }
     if (!is_null($size = $rev->getSize()) && !$rev->isDeleted(Revision::DELETED_TEXT)) {
         $s .= ' ' . $this->getSkin()->formatRevisionSize($size);
     }
     $s .= $this->getSkin()->revComment($rev, false, true);
     if ($notificationtimestamp && $row->rev_timestamp >= $notificationtimestamp) {
         $s .= ' <span class="updatedmarker">' . wfMsgHtml('updatedmarker') . '</span>';
     }
     $tools = array();
     # Rollback and undo links
     if (!is_null($next) && is_object($next)) {
         if ($latest && $this->title->userCan('rollback') && $this->title->userCan('edit')) {
             $this->preventClickjacking();
             $tools[] = '<span class="mw-rollback-link">' . $this->getSkin()->buildRollbackLink($rev) . '</span>';
         }
         if ($this->title->quickUserCan('edit') && !$rev->isDeleted(Revision::DELETED_TEXT) && !$next->rev_deleted & Revision::DELETED_TEXT) {
             # Create undo tooltip for the first (=latest) line only
             $undoTooltip = $latest ? array('title' => wfMsg('tooltip-undo')) : array();
             $undolink = $this->getSkin()->link($this->title, wfMsgHtml('editundo'), $undoTooltip, array('action' => 'edit', 'undoafter' => $next->rev_id, 'undo' => $rev->getId()), array('known', 'noclasses'));
             $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>";
         }
     }
     if ($tools) {
         $s .= ' (' . $wgLang->pipeList($tools) . ')';
     }
     # Tags
     list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'history');
     $classes = array_merge($classes, $newClasses);
     $s .= " {$tagSummary}";
     wfRunHooks('PageHistoryLineEnding', array($this, &$row, &$s, &$classes));
     $attribs = array();
     if ($classes) {
         $attribs['class'] = implode(' ', $classes);
     }
     return Xml::tags('li', $attribs, $s) . "\n";
 }
 protected function formatRevisionRow($row, $earliestLiveTime, $remaining)
 {
     $rev = Revision::newFromArchiveRow($row, array('title' => $this->mTargetObj));
     $revTextSize = '';
     $ts = wfTimestamp(TS_MW, $row->ar_timestamp);
     // Build checkboxen...
     if ($this->mAllowed) {
         if ($this->mInvert) {
             if (in_array($ts, $this->mTargetTimestamp)) {
                 $checkBox = Xml::check("ts{$ts}");
             } else {
                 $checkBox = Xml::check("ts{$ts}", true);
             }
         } else {
             $checkBox = Xml::check("ts{$ts}");
         }
     } else {
         $checkBox = '';
     }
     // Build page & diff links...
     $user = $this->getUser();
     if ($this->mCanView) {
         $titleObj = $this->getPageTitle();
         # Last link
         if (!$rev->userCan(Revision::DELETED_TEXT, $this->getUser())) {
             $pageLink = htmlspecialchars($this->getLanguage()->userTimeAndDate($ts, $user));
             $last = $this->msg('diff')->escaped();
         } elseif ($remaining > 0 || $earliestLiveTime && $ts > $earliestLiveTime) {
             $pageLink = $this->getPageLink($rev, $titleObj, $ts);
             $last = Linker::linkKnown($titleObj, $this->msg('diff')->escaped(), array(), array('target' => $this->mTargetObj->getPrefixedText(), 'timestamp' => $ts, 'diff' => 'prev'));
         } else {
             $pageLink = $this->getPageLink($rev, $titleObj, $ts);
             $last = $this->msg('diff')->escaped();
         }
     } else {
         $pageLink = htmlspecialchars($this->getLanguage()->userTimeAndDate($ts, $user));
         $last = $this->msg('diff')->escaped();
     }
     // User links
     $userLink = Linker::revUserTools($rev);
     // Minor edit
     $minor = $rev->isMinor() ? ChangesList::flag('minor') : '';
     // Revision text size
     $size = $row->ar_len;
     if (!is_null($size)) {
         $revTextSize = Linker::formatRevisionSize($size);
     }
     // Edit summary
     $comment = Linker::revComment($rev);
     // Tags
     $attribs = array();
     list($tagSummary, $classes) = ChangeTags::formatSummaryRow($row->ts_tags, 'deletedhistory');
     if ($classes) {
         $attribs['class'] = implode(' ', $classes);
     }
     // Revision delete links
     $revdlink = Linker::getRevDeleteLink($user, $rev, $this->mTargetObj);
     $revisionRow = $this->msg('undelete-revision-row')->rawParams($checkBox, $revdlink, $last, $pageLink, $userLink, $minor, $revTextSize, $comment, $tagSummary)->escaped();
     return Xml::tags('li', $attribs, $revisionRow) . "\n";
 }
Example #19
0
 /**
  * Generates each row in the contributions list.
  *
  * Contributions which are marked "top" are currently on top of the history.
  * For these contributions, a [rollback] link is shown for users with roll-
  * back privileges. The rollback link restores the most recent version that
  * was not written by the target user.
  *
  * @todo This would probably look a lot nicer in a table.
  */
 function formatRow($row)
 {
     global $wgUser, $wgLang, $wgContLang;
     wfProfileIn(__METHOD__);
     $sk = $this->getSkin();
     $rev = new Revision($row);
     $classes = array();
     $page = Title::newFromRow($row);
     $page->resetArticleId($row->rev_page);
     // use process cache
     $link = $sk->link($page, htmlspecialchars($page->getPrefixedText()), array(), $page->isRedirect() ? array('redirect' => 'no') : array());
     # Mark current revisions
     $difftext = $topmarktext = '';
     if ($row->rev_id == $row->page_latest) {
         $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
         # Add rollback link
         if (!$row->page_is_new && $page->quickUserCan('rollback') && $page->quickUserCan('edit')) {
             $this->preventClickjacking();
             $topmarktext .= ' ' . $sk->generateRollback($rev);
         }
     }
     # Is there a visible previous revision?
     if ($rev->userCan(Revision::DELETED_TEXT) && $rev->getParentId() !== 0) {
         $difftext = $sk->linkKnown($page, $this->messages['diff'], array(), array('diff' => 'prev', 'oldid' => $row->rev_id));
     } else {
         $difftext = $this->messages['diff'];
     }
     $histlink = $sk->linkKnown($page, $this->messages['hist'], array(), array('action' => 'history'));
     $comment = $wgContLang->getDirMark() . $sk->revComment($rev, false, true);
     $date = $wgLang->timeanddate(wfTimestamp(TS_MW, $row->rev_timestamp), true);
     if ($rev->isDeleted(Revision::DELETED_TEXT)) {
         $d = '<span class="history-deleted">' . $date . '</span>';
     } else {
         $d = $sk->linkKnown($page, htmlspecialchars($date), array(), array('oldid' => intval($row->rev_id)));
     }
     if ($this->target == 'newbies') {
         $userlink = ' . . ' . $sk->userLink($row->rev_user, $row->rev_user_text);
         $userlink .= ' ' . wfMsg('parentheses', $sk->userTalkLink($row->rev_user, $row->rev_user_text)) . ' ';
     } else {
         $userlink = '';
     }
     if ($rev->getParentId() === 0) {
         $nflag = ChangesList::flag('newpage');
     } else {
         $nflag = '';
     }
     if ($rev->isMinor()) {
         $mflag = ChangesList::flag('minor');
     } else {
         $mflag = '';
     }
     // Don't show useless link to people who cannot hide revisions
     $canHide = $wgUser->isAllowed('deleterevision');
     if ($canHide || $rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) {
         if (!$rev->userCan(Revision::DELETED_RESTRICTED)) {
             $del = $this->mSkin->revDeleteLinkDisabled($canHide);
             // revision was hidden from sysops
         } else {
             $query = array('type' => 'revision', 'target' => $page->getPrefixedDbkey(), 'ids' => $rev->getId());
             $del = $this->mSkin->revDeleteLink($query, $rev->isDeleted(Revision::DELETED_RESTRICTED), $canHide);
         }
         $del .= ' ';
     } else {
         $del = '';
     }
     $diffHistLinks = '(' . $difftext . $this->messages['pipe-separator'] . $histlink . ')';
     $ret = "{$del}{$d} {$diffHistLinks} {$nflag}{$mflag} {$link}{$userlink} {$comment} {$topmarktext}";
     # Denote if username is redacted for this edit
     if ($rev->isDeleted(Revision::DELETED_USER)) {
         $ret .= " <strong>" . wfMsgHtml('rev-deleted-user-contribs') . "</strong>";
     }
     # Tags, if any.
     list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'contributions');
     $classes = array_merge($classes, $newClasses);
     $ret .= " {$tagSummary}";
     // Let extensions add data
     wfRunHooks('ContributionsLineEnding', array(&$this, &$ret, $row));
     $classes = implode(' ', $classes);
     $ret = "<li class=\"{$classes}\">{$ret}</li>\n";
     wfProfileOut(__METHOD__);
     return $ret;
 }
 public function showDiffPage($diffOnly = false)
 {
     # Allow frames except in certain special cases
     $out = $this->getOutput();
     $out->allowClickjacking();
     $out->setRobotPolicy('noindex,nofollow');
     if (!$this->loadRevisionData()) {
         $this->showMissingRevision();
         return;
     }
     $user = $this->getUser();
     $permErrors = $this->mNewPage->getUserPermissionsErrors('read', $user);
     if ($this->mOldPage) {
         # mOldPage might not be set, see below.
         $permErrors = wfMergeErrorArrays($permErrors, $this->mOldPage->getUserPermissionsErrors('read', $user));
     }
     if (count($permErrors)) {
         throw new PermissionsError('read', $permErrors);
     }
     $rollback = '';
     $query = array();
     # Carry over 'diffonly' param via navigation links
     if ($diffOnly != $user->getBoolOption('diffonly')) {
         $query['diffonly'] = $diffOnly;
     }
     # Cascade unhide param in links for easy deletion browsing
     if ($this->unhide) {
         $query['unhide'] = 1;
     }
     # Check if one of the revisions is deleted/suppressed
     $deleted = $suppressed = false;
     $allowed = $this->mNewRev->userCan(Revision::DELETED_TEXT, $user);
     $revisionTools = array();
     # mOldRev is false if the difference engine is called with a "vague" query for
     # a diff between a version V and its previous version V' AND the version V
     # is the first version of that article. In that case, V' does not exist.
     if ($this->mOldRev === false) {
         $out->setPageTitle($this->msg('difference-title', $this->mNewPage->getPrefixedText()));
         $samePage = true;
         $oldHeader = '';
     } else {
         Hooks::run('DiffViewHeader', array($this, $this->mOldRev, $this->mNewRev));
         if ($this->mNewPage->equals($this->mOldPage)) {
             $out->setPageTitle($this->msg('difference-title', $this->mNewPage->getPrefixedText()));
             $samePage = true;
         } else {
             $out->setPageTitle($this->msg('difference-title-multipage', $this->mOldPage->getPrefixedText(), $this->mNewPage->getPrefixedText()));
             $out->addSubtitle($this->msg('difference-multipage'));
             $samePage = false;
         }
         if ($samePage && $this->mNewPage->quickUserCan('edit', $user)) {
             if ($this->mNewRev->isCurrent() && $this->mNewPage->userCan('rollback', $user)) {
                 $rollbackLink = Linker::generateRollback($this->mNewRev, $this->getContext());
                 if ($rollbackLink) {
                     $out->preventClickjacking();
                     $rollback = '&#160;&#160;&#160;' . $rollbackLink;
                 }
             }
             if (!$this->mOldRev->isDeleted(Revision::DELETED_TEXT) && !$this->mNewRev->isDeleted(Revision::DELETED_TEXT)) {
                 $undoLink = Html::element('a', array('href' => $this->mNewPage->getLocalURL(array('action' => 'edit', 'undoafter' => $this->mOldid, 'undo' => $this->mNewid)), 'title' => Linker::titleAttrib('undo')), $this->msg('editundo')->text());
                 $revisionTools['mw-diff-undo'] = $undoLink;
             }
         }
         # Make "previous revision link"
         if ($samePage && $this->mOldRev->getPrevious()) {
             $prevlink = Linker::linkKnown($this->mOldPage, $this->msg('previousdiff')->escaped(), array('id' => 'differences-prevlink'), array('diff' => 'prev', 'oldid' => $this->mOldid) + $query);
         } else {
             $prevlink = '&#160;';
         }
         if ($this->mOldRev->isMinor()) {
             $oldminor = ChangesList::flag('minor');
         } else {
             $oldminor = '';
         }
         $ldel = $this->revisionDeleteLink($this->mOldRev);
         $oldRevisionHeader = $this->getRevisionHeader($this->mOldRev, 'complete');
         $oldChangeTags = ChangeTags::formatSummaryRow($this->mOldTags, 'diff');
         $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $oldRevisionHeader . '</strong></div>' . '<div id="mw-diff-otitle2">' . Linker::revUserTools($this->mOldRev, !$this->unhide) . '</div>' . '<div id="mw-diff-otitle3">' . $oldminor . Linker::revComment($this->mOldRev, !$diffOnly, !$this->unhide) . $ldel . '</div>' . '<div id="mw-diff-otitle5">' . $oldChangeTags[0] . '</div>' . '<div id="mw-diff-otitle4">' . $prevlink . '</div>';
         if ($this->mOldRev->isDeleted(Revision::DELETED_TEXT)) {
             $deleted = true;
             // old revisions text is hidden
             if ($this->mOldRev->isDeleted(Revision::DELETED_RESTRICTED)) {
                 $suppressed = true;
                 // also suppressed
             }
         }
         # Check if this user can see the revisions
         if (!$this->mOldRev->userCan(Revision::DELETED_TEXT, $user)) {
             $allowed = false;
         }
     }
     # Make "next revision link"
     # Skip next link on the top revision
     if ($samePage && !$this->mNewRev->isCurrent()) {
         $nextlink = Linker::linkKnown($this->mNewPage, $this->msg('nextdiff')->escaped(), array('id' => 'differences-nextlink'), array('diff' => 'next', 'oldid' => $this->mNewid) + $query);
     } else {
         $nextlink = '&#160;';
     }
     if ($this->mNewRev->isMinor()) {
         $newminor = ChangesList::flag('minor');
     } else {
         $newminor = '';
     }
     # Handle RevisionDelete links...
     $rdel = $this->revisionDeleteLink($this->mNewRev);
     # Allow extensions to define their own revision tools
     Hooks::run('DiffRevisionTools', array($this->mNewRev, &$revisionTools, $this->mOldRev, $user));
     $formattedRevisionTools = array();
     // Put each one in parentheses (poor man's button)
     foreach ($revisionTools as $key => $tool) {
         $toolClass = is_string($key) ? $key : 'mw-diff-tool';
         $element = Html::rawElement('span', array('class' => $toolClass), $this->msg('parentheses')->rawParams($tool)->escaped());
         $formattedRevisionTools[] = $element;
     }
     $newRevisionHeader = $this->getRevisionHeader($this->mNewRev, 'complete') . ' ' . implode(' ', $formattedRevisionTools);
     $newChangeTags = ChangeTags::formatSummaryRow($this->mNewTags, 'diff');
     $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $newRevisionHeader . '</strong></div>' . '<div id="mw-diff-ntitle2">' . Linker::revUserTools($this->mNewRev, !$this->unhide) . " {$rollback}</div>" . '<div id="mw-diff-ntitle3">' . $newminor . Linker::revComment($this->mNewRev, !$diffOnly, !$this->unhide) . $rdel . '</div>' . '<div id="mw-diff-ntitle5">' . $newChangeTags[0] . '</div>' . '<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>';
     if ($this->mNewRev->isDeleted(Revision::DELETED_TEXT)) {
         $deleted = true;
         // new revisions text is hidden
         if ($this->mNewRev->isDeleted(Revision::DELETED_RESTRICTED)) {
             $suppressed = true;
             // also suppressed
         }
     }
     # If the diff cannot be shown due to a deleted revision, then output
     # the diff header and links to unhide (if available)...
     if ($deleted && (!$this->unhide || !$allowed)) {
         $this->showDiffStyle();
         $multi = $this->getMultiNotice();
         $out->addHTML($this->addHeader('', $oldHeader, $newHeader, $multi));
         if (!$allowed) {
             $msg = $suppressed ? 'rev-suppressed-no-diff' : 'rev-deleted-no-diff';
             # Give explanation for why revision is not visible
             $out->wrapWikiMsg("<div id='mw-{$msg}' class='mw-warning plainlinks'>\n\$1\n</div>\n", array($msg));
         } else {
             # Give explanation and add a link to view the diff...
             $query = $this->getRequest()->appendQueryValue('unhide', '1');
             $link = $this->getTitle()->getFullURL($query);
             $msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff';
             $out->wrapWikiMsg("<div id='mw-{$msg}' class='mw-warning plainlinks'>\n\$1\n</div>\n", array($msg, $link));
         }
         # Otherwise, output a regular diff...
     } else {
         # Add deletion notice if the user is viewing deleted content
         $notice = '';
         if ($deleted) {
             $msg = $suppressed ? 'rev-suppressed-diff-view' : 'rev-deleted-diff-view';
             $notice = "<div id='mw-{$msg}' class='mw-warning plainlinks'>\n" . $this->msg($msg)->parse() . "</div>\n";
         }
         $this->showDiff($oldHeader, $newHeader, $notice);
         if (!$diffOnly) {
             $this->renderNewRevision();
         }
     }
 }
 /**
  * Returns a row from the history printout.
  *
  * @todo document some more, and maybe clean up the code (some params redundant?)
  *
  * @param Row $row The database row corresponding to the previous line.
  * @param mixed $next The database row corresponding to the next line.
  * @param int $counter Apparently a counter of what row number we're at, counted from the top row = 1.
  * @param $notificationtimestamp
  * @param bool $latest Whether this row corresponds to the page's latest revision.
  * @param bool $firstInList Whether this row corresponds to the first displayed on this history page.
  * @return string HTML output for the row
  */
 function historyLine($row, $next, $counter = '', $notificationtimestamp = false, $latest = false, $firstInList = false)
 {
     global $wgUser, $wgLang;
     $rev = new Revision($row);
     $rev->setTitle($this->mTitle);
     $curlink = $this->curLink($rev, $latest);
     $lastlink = $this->lastLink($rev, $next, $counter);
     $arbitrary = $this->diffButtons($rev, $firstInList, $counter);
     $link = $this->revLink($rev);
     $classes = array();
     $s = "({$curlink}) ({$lastlink}) {$arbitrary}";
     if ($wgUser->isAllowed('deleterevision')) {
         if ($latest) {
             // We don't currently handle well changing the top revision's settings
             $del = Xml::tags('span', array('class' => 'mw-revdelundel-link'), '(' . $this->message['rev-delundel'] . ')');
         } else {
             if (!$rev->userCan(Revision::DELETED_RESTRICTED)) {
                 // If revision was hidden from sysops
                 $del = Xml::tags('span', array('class' => 'mw-revdelundel-link'), '(' . $this->message['rev-delundel'] . ')');
             } else {
                 $query = array('target' => $this->mTitle->getPrefixedDbkey(), 'oldid' => $rev->getId());
                 $del = $this->mSkin->revDeleteLink($query, $rev->isDeleted(Revision::DELETED_RESTRICTED));
             }
         }
         $s .= " {$del} ";
     }
     $s .= " {$link}";
     $s .= " <span class='history-user'>" . $this->mSkin->revUserTools($rev, true) . "</span>";
     if ($rev->isMinor()) {
         $s .= ' ' . Xml::element('span', array('class' => 'minor'), wfMsg('minoreditletter'));
     }
     if (!is_null($size = $rev->getSize()) && !$rev->isDeleted(Revision::DELETED_TEXT)) {
         $s .= ' ' . $this->mSkin->formatRevisionSize($size);
     }
     $s .= $this->mSkin->revComment($rev, false, true);
     if ($notificationtimestamp && $row->rev_timestamp >= $notificationtimestamp) {
         $s .= ' <span class="updatedmarker">' . wfMsgHtml('updatedmarker') . '</span>';
     }
     if ($rev->isDeleted(Revision::DELETED_TEXT)) {
         $s .= ' <tt>' . wfMsgHtml('deletedrev') . '</tt>';
     }
     $tools = array();
     if (!is_null($next) && is_object($next)) {
         if ($latest && $this->mTitle->userCan('rollback') && $this->mTitle->userCan('edit')) {
             $tools[] = '<span class="mw-rollback-link">' . $this->mSkin->buildRollbackLink($rev) . '</span>';
         }
         if ($this->mTitle->quickUserCan('edit') && !$rev->isDeleted(Revision::DELETED_TEXT) && !$next->rev_deleted & Revision::DELETED_TEXT) {
             # Create undo tooltip for the first (=latest) line only
             $undoTooltip = $latest ? array('title' => wfMsg('tooltip-undo')) : array();
             $undolink = $this->mSkin->link($this->mTitle, wfMsgHtml('editundo'), $undoTooltip, array('action' => 'edit', 'undoafter' => $next->rev_id, 'undo' => $rev->getId()), array('known', 'noclasses'));
             $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>";
         }
     }
     if ($tools) {
         $s .= ' (' . $wgLang->pipeList($tools) . ')';
     }
     # Tags
     list($tagSummary, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'history');
     $classes = array_merge($classes, $newClasses);
     $s .= " {$tagSummary}";
     wfRunHooks('PageHistoryLineEnding', array($this, &$row, &$s));
     $classes = implode(' ', $classes);
     return "<li class=\"{$classes}\">{$s}</li>\n";
 }