/** * @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"; }
/** * @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"; }
/** * 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"; }
/** * 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"; }
/** * 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"; }
/** * @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"; }
/** * 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; }
/** * 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"; }
/** * @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"; }
/** * @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); }
/** * @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"; }
/** * @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; }
/** * 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"; }
/** * 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 = '   ' . $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 = ' '; } 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 = ' '; } 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"; }