public function onView() { // TODO: use $this->useTransactionalTimeLimit(); when POST only wfTransactionalTimeLimit(); $details = null; $request = $this->getRequest(); $user = $this->getUser(); $result = $this->page->doRollback($request->getVal('from'), $request->getText('summary'), $request->getVal('token'), $request->getBool('bot'), $details, $this->getUser()); if (in_array(array('actionthrottledtext'), $result)) { throw new ThrottledError(); } if (isset($result[0][0]) && ($result[0][0] == 'alreadyrolled' || $result[0][0] == 'cantrollback')) { $this->getOutput()->setPageTitle($this->msg('rollbackfailed')); $errArray = $result[0]; $errMsg = array_shift($errArray); $this->getOutput()->addWikiMsgArray($errMsg, $errArray); if (isset($details['current'])) { /** @var Revision $current */ $current = $details['current']; if ($current->getComment() != '') { $this->getOutput()->addHTML($this->msg('editcomment')->rawParams(Linker::formatComment($current->getComment()))->parse()); } } return; } #NOTE: Permission errors already handled by Action::checkExecute. if ($result == array(array('readonlytext'))) { throw new ReadOnlyError(); } #XXX: Would be nice if ErrorPageError could take multiple errors, and/or a status object. # Right now, we only show the first error foreach ($result as $error) { throw new ErrorPageError('rollbackfailed', $error[0], array_slice($error, 1)); } /** @var Revision $current */ $current = $details['current']; $target = $details['target']; $newId = $details['newid']; $this->getOutput()->setPageTitle($this->msg('actioncomplete')); $this->getOutput()->setRobotPolicy('noindex,nofollow'); $old = Linker::revUserTools($current); $new = Linker::revUserTools($target); $this->getOutput()->addHTML($this->msg('rollback-success')->rawParams($old, $new)->parseAsBlock()); if ($user->getBoolOption('watchrollback')) { $user->addWatch($this->page->getTitle(), WatchedItem::IGNORE_USER_RIGHTS); } $this->getOutput()->returnToMain(false, $this->getTitle()); if (!$request->getBool('hidediff', false) && !$this->getUser()->getBoolOption('norollbackdiff', false)) { $contentHandler = $current->getContentHandler(); $de = $contentHandler->createDifferenceEngine($this->getContext(), $current->getId(), $newId, false, true); $de->showDiff('', ''); } }
/** * Generate the navigation links when browsing through an article revisions * It shows the information as: * Revision as of \<date\>; view current revision * \<- Previous version | Next Version -\> * * @param int $oldid Revision ID of this article revision */ public function setOldSubtitle($oldid = 0) { if (!Hooks::run('DisplayOldSubtitle', array(&$this, &$oldid))) { return; } $context = $this->getContext(); $unhide = $context->getRequest()->getInt('unhide') == 1; # Cascade unhide param in links for easy deletion browsing $extraParams = array(); if ($unhide) { $extraParams['unhide'] = 1; } if ($this->mRevision && $this->mRevision->getId() === $oldid) { $revision = $this->mRevision; } else { $revision = Revision::newFromId($oldid); } $timestamp = $revision->getTimestamp(); $current = $oldid == $this->mPage->getLatest(); $language = $context->getLanguage(); $user = $context->getUser(); $td = $language->userTimeAndDate($timestamp, $user); $tddate = $language->userDate($timestamp, $user); $tdtime = $language->userTime($timestamp, $user); # Show user links if allowed to see them. If hidden, then show them only if requested... $userlinks = Linker::revUserTools($revision, !$unhide); $infomsg = $current && !$context->msg('revision-info-current')->isDisabled() ? 'revision-info-current' : 'revision-info'; $outputPage = $context->getOutput(); $outputPage->addSubtitle("<div id=\"mw-{$infomsg}\">" . $context->msg($infomsg, $td)->rawParams($userlinks)->params($revision->getID(), $tddate, $tdtime, $revision->getUserText())->rawParams(Linker::revComment($revision, true, true))->parse() . "</div>"); $lnk = $current ? $context->msg('currentrevisionlink')->escaped() : Linker::linkKnown($this->getTitle(), $context->msg('currentrevisionlink')->escaped(), array(), $extraParams); $curdiff = $current ? $context->msg('diff')->escaped() : Linker::linkKnown($this->getTitle(), $context->msg('diff')->escaped(), array(), array('diff' => 'cur', 'oldid' => $oldid) + $extraParams); $prev = $this->getTitle()->getPreviousRevisionID($oldid); $prevlink = $prev ? Linker::linkKnown($this->getTitle(), $context->msg('previousrevision')->escaped(), array(), array('direction' => 'prev', 'oldid' => $oldid) + $extraParams) : $context->msg('previousrevision')->escaped(); $prevdiff = $prev ? Linker::linkKnown($this->getTitle(), $context->msg('diff')->escaped(), array(), array('diff' => 'prev', 'oldid' => $oldid) + $extraParams) : $context->msg('diff')->escaped(); $nextlink = $current ? $context->msg('nextrevision')->escaped() : Linker::linkKnown($this->getTitle(), $context->msg('nextrevision')->escaped(), array(), array('direction' => 'next', 'oldid' => $oldid) + $extraParams); $nextdiff = $current ? $context->msg('diff')->escaped() : Linker::linkKnown($this->getTitle(), $context->msg('diff')->escaped(), array(), array('diff' => 'next', 'oldid' => $oldid) + $extraParams); $cdel = Linker::getRevDeleteLink($user, $revision, $this->getTitle()); if ($cdel !== '') { $cdel .= ' '; } $outputPage->addSubtitle("<div id=\"mw-revision-nav\">" . $cdel . $context->msg('revision-nav')->rawParams($prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff)->escaped() . "</div>"); }
/** * 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"; }
/** * 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"; }
public function revUserTools($rev, $isPublic = false) { return Linker::revUserTools($rev, $isPublic); }
function formatRevisionRow($row) { $rev = new Revision($row); $stxt = ''; $last = $this->msg('last')->escaped(); $ts = wfTimestamp(TS_MW, $row->rev_timestamp); $checkBox = Xml::radio('mergepoint', $ts, $this->mTimestamp === $ts); $user = $this->getUser(); $pageLink = Linker::linkKnown($rev->getTitle(), htmlspecialchars($this->getLanguage()->userTimeAndDate($ts, $user)), [], ['oldid' => $rev->getId()]); if ($rev->isDeleted(Revision::DELETED_TEXT)) { $pageLink = '<span class="history-deleted">' . $pageLink . '</span>'; } # Last link if (!$rev->userCan(Revision::DELETED_TEXT, $user)) { $last = $this->msg('last')->escaped(); } elseif (isset($this->prevId[$row->rev_id])) { $last = Linker::linkKnown($rev->getTitle(), $this->msg('last')->escaped(), [], ['diff' => $row->rev_id, 'oldid' => $this->prevId[$row->rev_id]]); } $userLink = Linker::revUserTools($rev); $size = $row->rev_len; if (!is_null($size)) { $stxt = Linker::formatRevisionSize($size); } $comment = Linker::revComment($rev); return Html::rawElement('li', [], $this->msg('mergehistory-revisionrow')->rawParams($checkBox, $last, $pageLink, $userLink, $stxt, $comment)->escaped()); }
function formatRevisionRow($row) { $rev = new Revision($row); $stxt = ''; $last = $this->message['last']; $ts = wfTimestamp(TS_MW, $row->rev_timestamp); $checkBox = Xml::radio('mergepoint', $ts, false); $pageLink = Linker::linkKnown($rev->getTitle(), htmlspecialchars($this->getLanguage()->timeanddate($ts)), array(), array('oldid' => $rev->getId())); if ($rev->isDeleted(Revision::DELETED_TEXT)) { $pageLink = '<span class="history-deleted">' . $pageLink . '</span>'; } # Last link if (!$rev->userCan(Revision::DELETED_TEXT, $this->getUser())) { $last = $this->message['last']; } elseif (isset($this->prevId[$row->rev_id])) { $last = Linker::linkKnown($rev->getTitle(), $this->message['last'], array(), array('diff' => $row->rev_id, 'oldid' => $this->prevId[$row->rev_id])); } $userLink = Linker::revUserTools($rev); $size = $row->rev_len; if (!is_null($size)) { $stxt = Linker::formatRevisionSize($size); } $comment = Linker::revComment($rev); return "<li>{$checkBox} ({$last}) {$pageLink} . . {$userLink} {$stxt} {$comment}</li>"; }
private function formatRevisionRow($row, $earliestLiveTime, $remaining) { $rev = Revision::newFromArchiveRow($row, array('page' => $this->mTargetObj->getArticleId())); $stxt = ''; $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 = ''; } $user = $this->getUser(); // Build page & diff links... if ($this->mCanView) { $titleObj = $this->getTitle(); # 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); // Revision text size $size = $row->ar_len; if (!is_null($size)) { $stxt = Linker::formatRevisionSize($size); } // Edit summary $comment = Linker::revComment($rev); // Revision delete links $revdlink = Linker::getRevDeleteLink($user, $rev, $this->mTargetObj); return "<li>{$checkBox} {$revdlink} ({$last}) {$pageLink} . . {$userLink} {$stxt} {$comment}</li>"; }
/** * Sets the subtitle when viewing old revisions of a page. * This function's code is mostly copied from Article::setOldSubtitle(), * and it is meant to serve as a replacement for that function, using * the 'DisplayOldSubtitle' hook. * This display has the following differences from the standard one: * - It includes a link to the approved revision, which goes to the * default page. * - It includes a "diff" link alongside it. * - The "Latest revision" link points to the correct revision ID, * instead of to the default page (unless the latest revision is also * the approved one). * * @author Eli Handel */ static function setOldSubtitle($article, $revisionID) { $title = $article->getTitle(); # Added for ApprovedRevs - and removed hook $unhide = $article->getContext()->getRequest()->getInt('unhide') == 1; // Cascade unhide param in links for easy deletion browsing. $extraParams = array(); if ($unhide) { $extraParams['unhide'] = 1; } if ($article->mRevision && $article->mRevision->getId() === $revisionID) { $revision = $article->mRevision; } else { $revision = Revision::newFromId($revisionID); } $timestamp = $revision->getTimestamp(); $latestID = $article->getLatest(); // Modified for Approved Revs $current = $revisionID == $latestID; $approvedID = ApprovedRevs::getApprovedRevID($title); $language = $article->getContext()->getLanguage(); $user = $article->getContext()->getUser(); $td = $language->userTimeAndDate($timestamp, $user); $tddate = $language->userDate($timestamp, $user); $tdtime = $language->userTime($timestamp, $user); // Show the user links if they're allowed to see them. // If hidden, then show them only if requested... $userlinks = Linker::revUserTools($revision, !$unhide); $infomsg = $current && !wfMessage('revision-info-current')->isDisabled() ? 'revision-info-current' : 'revision-info'; $outputPage = $article->getContext()->getOutput(); $outputPage->addSubtitle("<div id=\"mw-{$infomsg}\">" . wfMessage($infomsg, $td)->rawParams($userlinks)->params($revision->getID(), $tddate, $tdtime, $revision->getUser())->parse() . "</div>"); // Created for Approved Revs $latestLinkParams = array(); if ($latestID != $approvedID) { $latestLinkParams['oldid'] = $latestID; } $lnk = $current ? wfMessage('currentrevisionlink')->escaped() : Linker::linkKnown($title, wfMessage('currentrevisionlink')->escaped(), array(), $latestLinkParams + $extraParams); $curdiff = $current ? wfMessage('diff')->escaped() : Linker::linkKnown($title, wfMessage('diff')->escaped(), array(), array('diff' => 'cur', 'oldid' => $revisionID) + $extraParams); $prev = $title->getPreviousRevisionID($revisionID); $prevlink = $prev ? Linker::linkKnown($title, wfMessage('previousrevision')->escaped(), array(), array('direction' => 'prev', 'oldid' => $revisionID) + $extraParams) : wfMessage('previousrevision')->escaped(); $prevdiff = $prev ? Linker::linkKnown($title, wfMessage('diff')->escaped(), array(), array('diff' => 'prev', 'oldid' => $revisionID) + $extraParams) : wfMessage('diff')->escaped(); $nextlink = $current ? wfMessage('nextrevision')->escaped() : Linker::linkKnown($title, wfMessage('nextrevision')->escaped(), array(), array('direction' => 'next', 'oldid' => $revisionID) + $extraParams); $nextdiff = $current ? wfMessage('diff')->escaped() : Linker::linkKnown($title, wfMessage('diff')->escaped(), array(), array('diff' => 'next', 'oldid' => $revisionID) + $extraParams); // Added for Approved Revs $approved = $approvedID != null && $revisionID == $approvedID; $approvedlink = $approved ? wfMessage('approvedrevs-approvedrevision')->escaped() : Linker::linkKnown($title, wfMessage('approvedrevs-approvedrevision')->escaped(), array(), $extraParams); $approveddiff = $approved ? wfMessage('diff')->escaped() : Linker::linkKnown($title, wfMessage('diff')->escaped(), array(), array('diff' => $approvedID, 'oldid' => $revisionID) + $extraParams); $cdel = Linker::getRevDeleteLink($user, $revision, $title); if ($cdel !== '') { $cdel .= ' '; } // Modified for ApprovedRevs $outputPage->addSubtitle("<div id=\"mw-revision-nav\">" . $cdel . wfMessage('approvedrevs-revision-nav')->rawParams($prevdiff, $prevlink, $approvedlink, $approveddiff, $lnk, $curdiff, $nextlink, $nextdiff)->escaped() . "</div>"); }
private static function doRollback() { global $wgRequest, $wgOut, $wgContLang; $wgOut->setArticleBodyOnly(true); $response = ""; $aid = intVal($wgRequest->getVal('aid')); $oldid = intVal($wgRequest->getVal('old')); $from = $wgRequest->getVal('from'); $from = preg_replace('/[_-]/', ' ', $from); $t = Title::newFromId($aid); if ($t && $t->exists()) { $r = Revision::newFromId($oldid); if ($r) { if ($from == '') { // no public user name $summary = wfMessage('rcp-revertpage-nouser'); } else { $summary = wfMessage('rcp-revertpage'); } // Allow the custom summary to use the same args as the default message $args = array($r->getUserText(), $from, $oldid); if ($summary instanceof Message) { $summary = $summary->params($args)->inContentLanguage()->text(); } else { $summary = wfMsgReplaceArgs($summary, $args); } // Trim spaces on user supplied text $summary = trim($summary); // Truncate for whole multibyte characters. $summary = $wgContLang->truncate($summary, 255); $a = new Article($t); $newRev = Revision::newFromTitle($t); $old = Linker::revUserTools(Revision::newFromId($oldid)); $new = Linker::revUserTools($newRev); $revision = 'r' . htmlspecialchars($wgContLang->formatNum($oldid, true)); $revlink = Linker::link($t, $revision, array(), array('oldid' => $oldid, 'diff' => 'prev')); $response = WfMessage('rcp-rollback-success')->rawParams($new, $old, $revlink); $status = $a->doEditContent($r->getContent(), $summary); if (!$status->isOK()) { $response = $status->getErrorsArray(); } // raise error, when the edit is an edit without a new version if (empty($status->value['revision'])) { $resultDetails = array('current' => $current); $query = array('oldid' => $oldid, 'diff' => 'prev'); $response = WfMessage('rcp-alreadyrolled')->params(array(htmlspecialchars($t->getPrefixedText()), htmlspecialchars($from), htmlspecialchars($newRev->getUserText())))->inContentLanguage()->parse(); } } } $wgOut->addHtml($response); }
function onDifferenceEngineNewHeader($differenceEngine, &$newHeader, $formattedRevisionTools, $nextlink, $rollback, $newminor, $diffOnly, $rdel, $unhide) { global $wgLanguageCode, $wgTitle; $user = $differenceEngine->getUser(); $newRevisionHeader = $differenceEngine->getRevisionHeader($differenceEngine->mNewRev, 'complete', 'new') . ' ' . implode(' ', $formattedRevisionTools); $newDaysAgo = wfTimeAgo($differenceEngine->mNewRev->getTimestamp()); //INTL: Avatar database data doesn't exist for sites other than English if ($wgLanguageCode == 'en') { $av = '<img src="' . Avatar::getAvatarURL($differenceEngine->mNewRev->getUserText()) . '" class="diff_avatar" />'; } $thumbsHtml = ""; $thumbHeader = ""; $th_diff_div = ""; if ($user->getId() != 0 && $wgTitle->getText() != "RCPatrol" && $wgTitle->getText() != "RCPatrolGuts" && $differenceEngine->mNewRev->getTitle()->getNamespace() == NS_MAIN) { $oldId = $differenceEngine->mNewRev->getPrevious(); $oldId = $oldId ? $oldId->getId() : -1; // Only show thumbs up for diffs that look back one revision if (class_exists('ThumbsUp')) { if ($oldId == -1 || $differenceEngine->mOldRev && $oldId == $differenceEngine->mOldRev->getId()) { $params = array('title' => $differenceEngine->mNewRev->getTitle(), 'new' => $differenceEngine->mNewid, 'old' => $oldId, 'vandal' => 0); $thumbsHtml = ThumbsUp::getThumbsUpButton($params, true); $th_diff_div = 'class="th_diff_div"'; } } } $newHeader = '<div id="mw-diff-ntitle1" ' . $th_diff_div . '><h4 ' . $thumbHeader . '>' . $newRevisionHeader . $nextlink . '</h4></div>' . '<div id="mw-diff-ntitle2">' . $av . $thumbsHtml . '<div id="mw-diff-oinfo">' . Linker::revUserTools($differenceEngine->mNewRev, !$unhide) . " {$rollback} " . '<br /><div id="mw-diff-ndaysago">' . $newDaysAgo . '</div>' . "</div>" . '<div id="mw-diff-ntitle4">' . $differenceEngine->markPatrolledLink() . '</div>' . "</div>" . '<div id="mw-diff-ntitle3" class="rccomment">' . $newminor . Linker::revComment($differenceEngine->mNewRev, !$diffOnly, !$unhide) . $rdel . '</div>'; return true; }
/** * Returns page information in an easily-manipulated format. Array keys are used so extensions * may add additional information in arbitrary positions. Array values are arrays with one * element to be rendered as a header, arrays with two elements to be rendered as a table row. */ protected function pageInfo() { global $wgContLang, $wgRCMaxAge; $user = $this->getUser(); $lang = $this->getLanguage(); $title = $this->getTitle(); $id = $title->getArticleID(); // Get page information that would be too "expensive" to retrieve by normal means $pageCounts = self::pageCounts($title, $user); // Get page properties $dbr = wfGetDB(DB_SLAVE); $result = $dbr->select('page_props', array('pp_propname', 'pp_value'), array('pp_page' => $id), __METHOD__); $pageProperties = array(); foreach ($result as $row) { $pageProperties[$row->pp_propname] = $row->pp_value; } // Basic information $pageInfo = array(); $pageInfo['header-basic'] = array(); // Display title $displayTitle = $title->getPrefixedText(); if (!empty($pageProperties['displaytitle'])) { $displayTitle = $pageProperties['displaytitle']; } $pageInfo['header-basic'][] = array($this->msg('pageinfo-display-title'), $displayTitle); // Default sort key $sortKey = $title->getCategorySortKey(); if (!empty($pageProperties['defaultsort'])) { $sortKey = $pageProperties['defaultsort']; } $pageInfo['header-basic'][] = array($this->msg('pageinfo-default-sort'), $sortKey); // Page length (in bytes) $pageInfo['header-basic'][] = array($this->msg('pageinfo-length'), $lang->formatNum($title->getLength())); // Page ID (number not localised, as it's a database ID) $pageInfo['header-basic'][] = array($this->msg('pageinfo-article-id'), $id); // Search engine status $pOutput = new ParserOutput(); if (isset($pageProperties['noindex'])) { $pOutput->setIndexPolicy('noindex'); } // Use robot policy logic $policy = $this->page->getRobotPolicy('view', $pOutput); $pageInfo['header-basic'][] = array($this->msg('pageinfo-robot-policy'), $this->msg("pageinfo-robot-{$policy['index']}")); if (isset($pageCounts['views'])) { // Number of views $pageInfo['header-basic'][] = array($this->msg('pageinfo-views'), $lang->formatNum($pageCounts['views'])); } if (isset($pageCounts['watchers'])) { // Number of page watchers $pageInfo['header-basic'][] = array($this->msg('pageinfo-watchers'), $lang->formatNum($pageCounts['watchers'])); } // Redirects to this page $whatLinksHere = SpecialPage::getTitleFor('Whatlinkshere', $title->getPrefixedText()); $pageInfo['header-basic'][] = array(Linker::link($whatLinksHere, $this->msg('pageinfo-redirects-name')->escaped(), array(), array('hidelinks' => 1, 'hidetrans' => 1)), $this->msg('pageinfo-redirects-value')->numParams(count($title->getRedirectsHere()))); // Subpages of this page, if subpages are enabled for the current NS if (MWNamespace::hasSubpages($title->getNamespace())) { $prefixIndex = SpecialPage::getTitleFor('Prefixindex', $title->getPrefixedText() . '/'); $pageInfo['header-basic'][] = array(Linker::link($prefixIndex, $this->msg('pageinfo-subpages-name')->escaped()), $this->msg('pageinfo-subpages-value')->numParams($pageCounts['subpages']['total'], $pageCounts['subpages']['redirects'], $pageCounts['subpages']['nonredirects'])); } // Page protection $pageInfo['header-restrictions'] = array(); // Page protection foreach ($title->getRestrictionTypes() as $restrictionType) { $protectionLevel = implode(', ', $title->getRestrictions($restrictionType)); if ($protectionLevel == '') { // Allow all users $message = $this->msg('protect-default')->escaped(); } else { // Administrators only $message = $this->msg("protect-level-{$protectionLevel}"); if ($message->isDisabled()) { // Require "$1" permission $message = $this->msg("protect-fallback", $protectionLevel)->parse(); } else { $message = $message->escaped(); } } $pageInfo['header-restrictions'][] = array($this->msg("restriction-{$restrictionType}"), $message); } if (!$this->page->exists()) { return $pageInfo; } // Edit history $pageInfo['header-edits'] = array(); $firstRev = $this->page->getOldestRevision(); // Page creator $pageInfo['header-edits'][] = array($this->msg('pageinfo-firstuser'), Linker::revUserTools($firstRev)); // Date of page creation $pageInfo['header-edits'][] = array($this->msg('pageinfo-firsttime'), Linker::linkKnown($title, $lang->userTimeAndDate($firstRev->getTimestamp(), $user), array(), array('oldid' => $firstRev->getId()))); // Latest editor $pageInfo['header-edits'][] = array($this->msg('pageinfo-lastuser'), Linker::revUserTools($this->page->getRevision())); // Date of latest edit $pageInfo['header-edits'][] = array($this->msg('pageinfo-lasttime'), Linker::linkKnown($title, $lang->userTimeAndDate($this->page->getTimestamp(), $user), array(), array('oldid' => $this->page->getLatest()))); // Total number of edits $pageInfo['header-edits'][] = array($this->msg('pageinfo-edits'), $lang->formatNum($pageCounts['edits'])); // Total number of distinct authors $pageInfo['header-edits'][] = array($this->msg('pageinfo-authors'), $lang->formatNum($pageCounts['authors'])); // Recent number of edits (within past 30 days) $pageInfo['header-edits'][] = array($this->msg('pageinfo-recent-edits', $lang->formatDuration($wgRCMaxAge)), $lang->formatNum($pageCounts['recent_edits'])); // Recent number of distinct authors $pageInfo['header-edits'][] = array($this->msg('pageinfo-recent-authors'), $lang->formatNum($pageCounts['recent_authors'])); // Array of MagicWord objects $magicWords = MagicWord::getDoubleUnderscoreArray(); // Array of magic word IDs $wordIDs = $magicWords->names; // Array of IDs => localized magic words $localizedWords = $wgContLang->getMagicWords(); $listItems = array(); foreach ($pageProperties as $property => $value) { if (in_array($property, $wordIDs)) { $listItems[] = Html::element('li', array(), $localizedWords[$property][1]); } } $localizedList = Html::rawElement('ul', array(), implode('', $listItems)); $hiddenCategories = $this->page->getHiddenCategories(); $transcludedTemplates = $title->getTemplateLinksFrom(); if (count($listItems) > 0 || count($hiddenCategories) > 0 || count($transcludedTemplates) > 0) { // Page properties $pageInfo['header-properties'] = array(); // Magic words if (count($listItems) > 0) { $pageInfo['header-properties'][] = array($this->msg('pageinfo-magic-words')->numParams(count($listItems)), $localizedList); } // Hidden categories if (count($hiddenCategories) > 0) { $pageInfo['header-properties'][] = array($this->msg('pageinfo-hidden-categories')->numParams(count($hiddenCategories)), Linker::formatHiddenCategories($hiddenCategories)); } // Transcluded templates if (count($transcludedTemplates) > 0) { $pageInfo['header-properties'][] = array($this->msg('pageinfo-templates')->numParams(count($transcludedTemplates)), Linker::formatTemplates($transcludedTemplates)); } } return $pageInfo; }
/** * Generate the navigation links when browsing through an article revisions * It shows the information as: * Revision as of \<date\>; view current revision * \<- Previous version | Next Version -\> * * @param $oldid String: revision ID of this article revision */ public function setOldSubtitle($oldid = 0) { global $wgLang, $wgOut, $wgUser, $wgRequest; if (!wfRunHooks('DisplayOldSubtitle', array(&$this, &$oldid))) { return; } $unhide = $wgRequest->getInt('unhide') == 1; # Cascade unhide param in links for easy deletion browsing $extraParams = array(); if ($wgRequest->getVal('unhide')) { $extraParams['unhide'] = 1; } $revision = Revision::newFromId($oldid); $timestamp = $revision->getTimestamp(); $current = $oldid == $this->mPage->getLatest(); $td = $wgLang->timeanddate($timestamp, true); $tddate = $wgLang->date($timestamp, true); $tdtime = $wgLang->time($timestamp, true); # Show user links if allowed to see them. If hidden, then show them only if requested... $userlinks = Linker::revUserTools($revision, !$unhide); $infomsg = $current && !wfMessage('revision-info-current')->isDisabled() ? 'revision-info-current' : 'revision-info'; $wgOut->addSubtitle("<div id=\"mw-{$infomsg}\">" . wfMessage($infomsg, $td)->rawParams($userlinks)->params($revision->getID(), $tddate, $tdtime, $revision->getUser())->parse() . "</div>"); $lnk = $current ? wfMsgHtml('currentrevisionlink') : Linker::link($this->getTitle(), wfMsgHtml('currentrevisionlink'), array(), $extraParams, array('known', 'noclasses')); $curdiff = $current ? wfMsgHtml('diff') : Linker::link($this->getTitle(), wfMsgHtml('diff'), array(), array('diff' => 'cur', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')); $prev = $this->getTitle()->getPreviousRevisionID($oldid); $prevlink = $prev ? Linker::link($this->getTitle(), wfMsgHtml('previousrevision'), array(), array('direction' => 'prev', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')) : wfMsgHtml('previousrevision'); $prevdiff = $prev ? Linker::link($this->getTitle(), wfMsgHtml('diff'), array(), array('diff' => 'prev', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')) : wfMsgHtml('diff'); $nextlink = $current ? wfMsgHtml('nextrevision') : Linker::link($this->getTitle(), wfMsgHtml('nextrevision'), array(), array('direction' => 'next', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')); $nextdiff = $current ? wfMsgHtml('diff') : Linker::link($this->getTitle(), wfMsgHtml('diff'), array(), array('diff' => 'next', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')); $cdel = Linker::getRevDeleteLink($wgUser, $revision, $this->getTitle()); if ($cdel !== '') { $cdel .= ' '; } $wgOut->addSubtitle("<div id=\"mw-revision-nav\">" . $cdel . wfMsgExt('revision-nav', array('escapenoentities', 'parsemag', 'replaceafter'), $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff) . "</div>"); }
/** * 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"; }
function showDiffPage($diffOnly = false) { wfProfileIn(__METHOD__); # Allow frames except in certain special cases $out = $this->getOutput(); $out->allowClickjacking(); $out->setRobotPolicy('noindex,nofollow'); if (!$this->loadRevisionData()) { $this->showMissingRevision(); wfProfileOut(__METHOD__); 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)) { wfProfileOut(__METHOD__); throw new PermissionsError('read', $permErrors); } # If external diffs are enabled both globally and for the user, # we'll use the application/x-external-editor interface to call # an external diff tool like kompare, kdiff3, etc. if (ExternalEdit::useExternalEngine($this->getContext(), 'diff')) { //TODO: come up with a good solution for non-text content here. // at least, the content format needs to be passed to the client somehow. // Currently, action=raw will just fail for non-text content. $urls = array('File' => array('Extension' => 'wiki', 'URL' => $this->mNewPage->getCanonicalURL(array('action' => 'raw', 'oldid' => $this->mOldid))), 'File2' => array('Extension' => 'wiki', 'URL' => $this->mNewPage->getCanonicalURL(array('action' => 'raw', 'oldid' => $this->mNewid)))); $externalEditor = new ExternalEdit($this->getContext(), $urls); $externalEditor->execute(); wfProfileOut(__METHOD__); return; } $rollback = ''; $undoLink = ''; $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); # 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 { wfRunHooks('DiffViewHeader', array($this, $this->mOldRev, $this->mNewRev)); $sk = $this->getSkin(); if (method_exists($sk, 'suppressQuickbar')) { $sk->suppressQuickbar(); } 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)) { $out->preventClickjacking(); $rollback = '   ' . Linker::generateRollback($this->mNewRev, $this->getContext()); } if (!$this->mOldRev->isDeleted(Revision::DELETED_TEXT) && !$this->mNewRev->isDeleted(Revision::DELETED_TEXT)) { $undoLink = ' ' . $this->msg('parentheses')->rawParams(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()))->escaped(); } } # 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'); $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-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); $newRevisionHeader = $this->getRevisionHeader($this->mNewRev, 'complete') . $undoLink; $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-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... $link = $this->getTitle()->getFullUrl($this->getRequest()->appendQueryValue('unhide', '1', true)); $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(); } } wfProfileOut(__METHOD__); }
/** * 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"; }
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"; }
/** * Returns page information in an easily-manipulated format. Array keys are used so extensions * may add additional information in arbitrary positions. Array values are arrays with one * element to be rendered as a header, arrays with two elements to be rendered as a table row. * * @return array */ protected function pageInfo() { global $wgContLang; $user = $this->getUser(); $lang = $this->getLanguage(); $title = $this->getTitle(); $id = $title->getArticleID(); $config = $this->context->getConfig(); $cache = ObjectCache::getMainWANInstance(); $memcKey = wfMemcKey('infoaction', sha1($title->getPrefixedText()), $this->page->getLatest()); $pageCounts = $cache->get($memcKey); $version = isset($pageCounts['cacheversion']) ? $pageCounts['cacheversion'] : false; if ($pageCounts === false || $version !== self::CACHE_VERSION) { // Get page information that would be too "expensive" to retrieve by normal means $pageCounts = $this->pageCounts($title); $pageCounts['cacheversion'] = self::CACHE_VERSION; $cache->set($memcKey, $pageCounts); } // Get page properties $dbr = wfGetDB(DB_SLAVE); $result = $dbr->select('page_props', array('pp_propname', 'pp_value'), array('pp_page' => $id), __METHOD__); $pageProperties = array(); foreach ($result as $row) { $pageProperties[$row->pp_propname] = $row->pp_value; } // Basic information $pageInfo = array(); $pageInfo['header-basic'] = array(); // Display title $displayTitle = $title->getPrefixedText(); if (isset($pageProperties['displaytitle'])) { $displayTitle = $pageProperties['displaytitle']; } $pageInfo['header-basic'][] = array($this->msg('pageinfo-display-title'), $displayTitle); // Is it a redirect? If so, where to? if ($title->isRedirect()) { $pageInfo['header-basic'][] = array($this->msg('pageinfo-redirectsto'), Linker::link($this->page->getRedirectTarget()) . $this->msg('word-separator')->escaped() . $this->msg('parentheses')->rawParams(Linker::link($this->page->getRedirectTarget(), $this->msg('pageinfo-redirectsto-info')->escaped(), array(), array('action' => 'info')))->escaped()); } // Default sort key $sortKey = $title->getCategorySortkey(); if (isset($pageProperties['defaultsort'])) { $sortKey = $pageProperties['defaultsort']; } $sortKey = htmlspecialchars($sortKey); $pageInfo['header-basic'][] = array($this->msg('pageinfo-default-sort'), $sortKey); // Page length (in bytes) $pageInfo['header-basic'][] = array($this->msg('pageinfo-length'), $lang->formatNum($title->getLength())); // Page ID (number not localised, as it's a database ID) $pageInfo['header-basic'][] = array($this->msg('pageinfo-article-id'), $id); // Language in which the page content is (supposed to be) written $pageLang = $title->getPageLanguage()->getCode(); if ($config->get('PageLanguageUseDB') && $this->getTitle()->userCan('pagelang', $this->getUser())) { // Link to Special:PageLanguage with pre-filled page title if user has permissions $titleObj = SpecialPage::getTitleFor('PageLanguage', $title->getPrefixedText()); $langDisp = Linker::link($titleObj, $this->msg('pageinfo-language')->escaped()); } else { // Display just the message $langDisp = $this->msg('pageinfo-language')->escaped(); } $pageInfo['header-basic'][] = array($langDisp, Language::fetchLanguageName($pageLang, $lang->getCode()) . ' ' . $this->msg('parentheses', $pageLang)->escaped()); // Content model of the page $pageInfo['header-basic'][] = array($this->msg('pageinfo-content-model'), htmlspecialchars(ContentHandler::getLocalizedName($title->getContentModel()))); // Search engine status $pOutput = new ParserOutput(); if (isset($pageProperties['noindex'])) { $pOutput->setIndexPolicy('noindex'); } if (isset($pageProperties['index'])) { $pOutput->setIndexPolicy('index'); } // Use robot policy logic $policy = $this->page->getRobotPolicy('view', $pOutput); $pageInfo['header-basic'][] = array($this->msg('pageinfo-robot-policy'), $this->msg("pageinfo-robot-{$policy['index']}")); $unwatchedPageThreshold = $config->get('UnwatchedPageThreshold'); if ($user->isAllowed('unwatchedpages') || $unwatchedPageThreshold !== false && $pageCounts['watchers'] >= $unwatchedPageThreshold) { // Number of page watchers $pageInfo['header-basic'][] = array($this->msg('pageinfo-watchers'), $lang->formatNum($pageCounts['watchers'])); if ($config->get('ShowUpdatedMarker') && isset($pageCounts['visitingWatchers'])) { $minToDisclose = $config->get('UnwatchedPageSecret'); if ($pageCounts['visitingWatchers'] > $minToDisclose || $user->isAllowed('unwatchedpages')) { $pageInfo['header-basic'][] = array($this->msg('pageinfo-visiting-watchers'), $lang->formatNum($pageCounts['visitingWatchers'])); } else { $pageInfo['header-basic'][] = array($this->msg('pageinfo-visiting-watchers'), $this->msg('pageinfo-few-visiting-watchers')); } } } elseif ($unwatchedPageThreshold !== false) { $pageInfo['header-basic'][] = array($this->msg('pageinfo-watchers'), $this->msg('pageinfo-few-watchers')->numParams($unwatchedPageThreshold)); } // Redirects to this page $whatLinksHere = SpecialPage::getTitleFor('Whatlinkshere', $title->getPrefixedText()); $pageInfo['header-basic'][] = array(Linker::link($whatLinksHere, $this->msg('pageinfo-redirects-name')->escaped(), array(), array('hidelinks' => 1, 'hidetrans' => 1, 'hideimages' => $title->getNamespace() == NS_FILE)), $this->msg('pageinfo-redirects-value')->numParams(count($title->getRedirectsHere()))); // Is it counted as a content page? if ($this->page->isCountable()) { $pageInfo['header-basic'][] = array($this->msg('pageinfo-contentpage'), $this->msg('pageinfo-contentpage-yes')); } // Subpages of this page, if subpages are enabled for the current NS if (MWNamespace::hasSubpages($title->getNamespace())) { $prefixIndex = SpecialPage::getTitleFor('Prefixindex', $title->getPrefixedText() . '/'); $pageInfo['header-basic'][] = array(Linker::link($prefixIndex, $this->msg('pageinfo-subpages-name')->escaped()), $this->msg('pageinfo-subpages-value')->numParams($pageCounts['subpages']['total'], $pageCounts['subpages']['redirects'], $pageCounts['subpages']['nonredirects'])); } if ($title->inNamespace(NS_CATEGORY)) { $category = Category::newFromTitle($title); // $allCount is the total number of cat members, // not the count of how many members are normal pages. $allCount = (int) $category->getPageCount(); $subcatCount = (int) $category->getSubcatCount(); $fileCount = (int) $category->getFileCount(); $pagesCount = $allCount - $subcatCount - $fileCount; $pageInfo['category-info'] = array(array($this->msg('pageinfo-category-total'), $lang->formatNum($allCount)), array($this->msg('pageinfo-category-pages'), $lang->formatNum($pagesCount)), array($this->msg('pageinfo-category-subcats'), $lang->formatNum($subcatCount)), array($this->msg('pageinfo-category-files'), $lang->formatNum($fileCount))); } // Page protection $pageInfo['header-restrictions'] = array(); // Is this page affected by the cascading protection of something which includes it? if ($title->isCascadeProtected()) { $cascadingFrom = ''; $sources = $title->getCascadeProtectionSources(); // Array deferencing is in PHP 5.4 :( foreach ($sources[0] as $sourceTitle) { $cascadingFrom .= Html::rawElement('li', array(), Linker::linkKnown($sourceTitle)); } $cascadingFrom = Html::rawElement('ul', array(), $cascadingFrom); $pageInfo['header-restrictions'][] = array($this->msg('pageinfo-protect-cascading-from'), $cascadingFrom); } // Is out protection set to cascade to other pages? if ($title->areRestrictionsCascading()) { $pageInfo['header-restrictions'][] = array($this->msg('pageinfo-protect-cascading'), $this->msg('pageinfo-protect-cascading-yes')); } // Page protection foreach ($title->getRestrictionTypes() as $restrictionType) { $protectionLevel = implode(', ', $title->getRestrictions($restrictionType)); if ($protectionLevel == '') { // Allow all users $message = $this->msg('protect-default')->escaped(); } else { // Administrators only // Messages: protect-level-autoconfirmed, protect-level-sysop $message = $this->msg("protect-level-{$protectionLevel}"); if ($message->isDisabled()) { // Require "$1" permission $message = $this->msg("protect-fallback", $protectionLevel)->parse(); } else { $message = $message->escaped(); } } $expiry = $title->getRestrictionExpiry($restrictionType); $formattedexpiry = $this->msg('parentheses', $this->getLanguage()->formatExpiry($expiry))->escaped(); $message .= $this->msg('word-separator')->escaped() . $formattedexpiry; // Messages: restriction-edit, restriction-move, restriction-create, // restriction-upload $pageInfo['header-restrictions'][] = array($this->msg("restriction-{$restrictionType}"), $message); } if (!$this->page->exists()) { return $pageInfo; } // Edit history $pageInfo['header-edits'] = array(); $firstRev = $this->page->getOldestRevision(); $lastRev = $this->page->getRevision(); $batch = new LinkBatch(); if ($firstRev) { $firstRevUser = $firstRev->getUserText(Revision::FOR_THIS_USER); if ($firstRevUser !== '') { $batch->add(NS_USER, $firstRevUser); $batch->add(NS_USER_TALK, $firstRevUser); } } if ($lastRev) { $lastRevUser = $lastRev->getUserText(Revision::FOR_THIS_USER); if ($lastRevUser !== '') { $batch->add(NS_USER, $lastRevUser); $batch->add(NS_USER_TALK, $lastRevUser); } } $batch->execute(); if ($firstRev) { // Page creator $pageInfo['header-edits'][] = array($this->msg('pageinfo-firstuser'), Linker::revUserTools($firstRev)); // Date of page creation $pageInfo['header-edits'][] = array($this->msg('pageinfo-firsttime'), Linker::linkKnown($title, htmlspecialchars($lang->userTimeAndDate($firstRev->getTimestamp(), $user)), array(), array('oldid' => $firstRev->getId()))); } if ($lastRev) { // Latest editor $pageInfo['header-edits'][] = array($this->msg('pageinfo-lastuser'), Linker::revUserTools($lastRev)); // Date of latest edit $pageInfo['header-edits'][] = array($this->msg('pageinfo-lasttime'), Linker::linkKnown($title, htmlspecialchars($lang->userTimeAndDate($this->page->getTimestamp(), $user)), array(), array('oldid' => $this->page->getLatest()))); } // Total number of edits $pageInfo['header-edits'][] = array($this->msg('pageinfo-edits'), $lang->formatNum($pageCounts['edits'])); // Total number of distinct authors if ($pageCounts['authors'] > 0) { $pageInfo['header-edits'][] = array($this->msg('pageinfo-authors'), $lang->formatNum($pageCounts['authors'])); } // Recent number of edits (within past 30 days) $pageInfo['header-edits'][] = array($this->msg('pageinfo-recent-edits', $lang->formatDuration($config->get('RCMaxAge'))), $lang->formatNum($pageCounts['recent_edits'])); // Recent number of distinct authors $pageInfo['header-edits'][] = array($this->msg('pageinfo-recent-authors'), $lang->formatNum($pageCounts['recent_authors'])); // Array of MagicWord objects $magicWords = MagicWord::getDoubleUnderscoreArray(); // Array of magic word IDs $wordIDs = $magicWords->names; // Array of IDs => localized magic words $localizedWords = $wgContLang->getMagicWords(); $listItems = array(); foreach ($pageProperties as $property => $value) { if (in_array($property, $wordIDs)) { $listItems[] = Html::element('li', array(), $localizedWords[$property][1]); } } $localizedList = Html::rawElement('ul', array(), implode('', $listItems)); $hiddenCategories = $this->page->getHiddenCategories(); if (count($listItems) > 0 || count($hiddenCategories) > 0 || $pageCounts['transclusion']['from'] > 0 || $pageCounts['transclusion']['to'] > 0) { $options = array('LIMIT' => $config->get('PageInfoTransclusionLimit')); $transcludedTemplates = $title->getTemplateLinksFrom($options); if ($config->get('MiserMode')) { $transcludedTargets = array(); } else { $transcludedTargets = $title->getTemplateLinksTo($options); } // Page properties $pageInfo['header-properties'] = array(); // Magic words if (count($listItems) > 0) { $pageInfo['header-properties'][] = array($this->msg('pageinfo-magic-words')->numParams(count($listItems)), $localizedList); } // Hidden categories if (count($hiddenCategories) > 0) { $pageInfo['header-properties'][] = array($this->msg('pageinfo-hidden-categories')->numParams(count($hiddenCategories)), Linker::formatHiddenCategories($hiddenCategories)); } // Transcluded templates if ($pageCounts['transclusion']['from'] > 0) { if ($pageCounts['transclusion']['from'] > count($transcludedTemplates)) { $more = $this->msg('morenotlisted')->escaped(); } else { $more = null; } $pageInfo['header-properties'][] = array($this->msg('pageinfo-templates')->numParams($pageCounts['transclusion']['from']), Linker::formatTemplates($transcludedTemplates, false, false, $more)); } if (!$config->get('MiserMode') && $pageCounts['transclusion']['to'] > 0) { if ($pageCounts['transclusion']['to'] > count($transcludedTargets)) { $more = Linker::link($whatLinksHere, $this->msg('moredotdotdot')->escaped(), array(), array('hidelinks' => 1, 'hideredirs' => 1)); } else { $more = null; } $pageInfo['header-properties'][] = array($this->msg('pageinfo-transclusions')->numParams($pageCounts['transclusion']['to']), Linker::formatTemplates($transcludedTargets, false, false, $more)); } } return $pageInfo; }
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(); } } }
/** * Generate the navigation links when browsing through an article revisions * It shows the information as: * Revision as of \<date\>; view current revision * \<- Previous version | Next Version -\> * * @param $oldid String: revision ID of this article revision */ public function setOldSubtitle($oldid = 0) { global $wgLang, $wgOut, $wgUser, $wgRequest; if (!wfRunHooks('DisplayOldSubtitle', array(&$this, &$oldid))) { return; } $unhide = $wgRequest->getInt('unhide') == 1; # Cascade unhide param in links for easy deletion browsing $extraParams = array(); if ($wgRequest->getVal('unhide')) { $extraParams['unhide'] = 1; } $revision = Revision::newFromId($oldid); $timestamp = $revision->getTimestamp(); $current = $oldid == $this->mPage->getLatest(); $td = $wgLang->timeanddate($timestamp, true); $tddate = $wgLang->date($timestamp, true); $tdtime = $wgLang->time($timestamp, true); $lnk = $current ? wfMsgHtml('currentrevisionlink') : Linker::link($this->getTitle(), wfMsgHtml('currentrevisionlink'), array(), $extraParams, array('known', 'noclasses')); $curdiff = $current ? wfMsgHtml('diff') : Linker::link($this->getTitle(), wfMsgHtml('diff'), array(), array('diff' => 'cur', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')); $prev = $this->getTitle()->getPreviousRevisionID($oldid); $prevlink = $prev ? Linker::link($this->getTitle(), wfMsgHtml('previousrevision'), array(), array('direction' => 'prev', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')) : wfMsgHtml('previousrevision'); $prevdiff = $prev ? Linker::link($this->getTitle(), wfMsgHtml('diff'), array(), array('diff' => 'prev', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')) : wfMsgHtml('diff'); $nextlink = $current ? wfMsgHtml('nextrevision') : Linker::link($this->getTitle(), wfMsgHtml('nextrevision'), array(), array('direction' => 'next', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')); $nextdiff = $current ? wfMsgHtml('diff') : Linker::link($this->getTitle(), wfMsgHtml('diff'), array(), array('diff' => 'next', 'oldid' => $oldid) + $extraParams, array('known', 'noclasses')); $cdel = ''; // User can delete revisions or view deleted revisions... $canHide = $wgUser->isAllowed('deleterevision'); if ($canHide || $revision->getVisibility() && $wgUser->isAllowed('deletedhistory')) { if (!$revision->userCan(Revision::DELETED_RESTRICTED)) { $cdel = Linker::revDeleteLinkDisabled($canHide); // rev was hidden from Sysops } else { $query = array('type' => 'revision', 'target' => $this->getTitle()->getPrefixedDbkey(), 'ids' => $oldid); $cdel = Linker::revDeleteLink($query, $revision->isDeleted(File::DELETED_RESTRICTED), $canHide); } $cdel .= ' '; } # Show user links if allowed to see them. If hidden, then show them only if requested... $userlinks = Linker::revUserTools($revision, !$unhide); $infomsg = $current && !wfMessage('revision-info-current')->isDisabled() ? 'revision-info-current' : 'revision-info'; $r = "\n\t\t\t\t<div id=\"mw-{$infomsg}\">" . wfMsgExt($infomsg, array('parseinline', 'replaceafter'), $td, $userlinks, $revision->getID(), $tddate, $tdtime, $revision->getUser()) . "</div>\n" . "\n\t\t\t\t<div id=\"mw-revision-nav\">" . $cdel . wfMsgExt('revision-nav', array('escapenoentities', 'parsemag', 'replaceafter'), $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff) . "</div>\n\t\t\t"; $wgOut->setSubtitle($r); }