%PDF- %PDF-
Direktori : /www/varak.net/wiki.varak.net/extensions/MobileFrontend/includes/specials/ |
Current File : /www/varak.net/wiki.varak.net/extensions/MobileFrontend/includes/specials/SpecialMobileDiff.php |
<?php /** * Show the difference between two revisions of a page */ class SpecialMobileDiff extends MobileSpecialPage { /** @var boolean $hasDesktopVersion Does this special page has a desktop version? */ protected $hasDesktopVersion = true; /** @var integer $revId Saves the actual revision ID */ private $revId; /** @var Revision $rev Saves the revision Object of actual revision */ private $rev; /** @var Revision $prevRev Saves the previous revision */ private $prevRev; /** @var Title Saves the title of the actual revision */ private $targetTitle; /** * @var InlineDifferenceEngine|DifferenceEngine $mDiffEngine * DifferenceEngine for this Diff-page */ protected $mDiffEngine; /** * Construct function */ public function __construct() { parent::__construct( 'MobileDiff' ); } /** * Get the revision object from ID * @param int $id ID of the wanted revision * @return Revision */ public static function getRevision( $id ) { return Revision::newFromId( $id ); } /** * Generate a 404 Error message, that revisions can not be found */ public function executeBadQuery() { wfHttpError( 404, $this->msg( 'mobile-frontend-diffview-404-title' )->text(), $this->msg( 'mobile-frontend-diffview-404-desc' )->text() ); } /** * Takes 2 ids/keywords and validates them returning respective revisions * * @param int[] $revids Array of revision ids currently limited to 2 elements * @return Revision[]|null[] Array of previous and next revision. The next revision is null if * a bad parameter is passed */ public function getRevisionsToCompare( $revids ) { $prev = null; $rev = null; // check 2 parameters are passed and are numbers if ( count( $revids ) === 2 && $revids[0] && $revids[1] ) { $id = (int)$revids[1]; $prevId = (int)$revids[0]; if ( $id && $prevId ) { $rev = static::getRevision( $id ); // deal with identical ids if ( $id === $prevId ) { $rev = null; } elseif ( $rev ) { $prev = static::getRevision( $prevId ); if ( !$prev ) { $rev = null; } } else { $rev = null; } } } elseif ( count( $revids ) === 1 ) { $id = (int)$revids[0]; if ( $id ) { $rev = static::getRevision( $id ); if ( $rev ) { $prev = $rev->getPrevious(); } } } return [ $prev, $rev ]; } /** * Render the diff page * @return bool false when revision not exist * @param string $par Revision IDs separated by three points (e.g. 123...124) */ public function executeWhenAvailable( $par ) { $ctx = MobileContext::singleton(); $this->setHeaders(); $output = $this->getOutput(); // @FIXME add full support for git-style notation (eg ...123, 123...) $revisions = $this->getRevisionsToCompare( explode( '...', $par ) ); $rev = $revisions[1]; $prev = $revisions[0]; if ( $rev === null ) { $this->executeBadQuery(); return false; } $this->revId = $rev->getId(); $this->rev = $rev; $this->prevRev = $prev; $this->targetTitle = $this->rev->getTitle(); $this->getSkin()->setRelevantTitle( $this->targetTitle ); $output->setPageTitle( $this->msg( 'mobile-frontend-diffview-title', $this->targetTitle->getPrefixedText() ) ); $output->addModuleStyles( [ 'mobile.special.user.icons', 'mobile.pagesummary.styles', // @todo FIXME: Don't add these styles. This is only needed for the user // icon to the left of the username 'mobile.special.pagefeed.styles' ] ); $output->addModules( 'mobile.special.mobilediff.scripts' ); // Allow other extensions to load more stuff here Hooks::run( 'BeforeSpecialMobileDiffDisplay', [ &$output, $ctx, $revisions ] ); $output->addHTML( '<div id="mw-mf-diffview" class="content-unstyled"><div id="mw-mf-diffarea">' ); $this->displayDiffPage(); $output->addHTML( '</div>' ); $this->showFooter( $ctx, $this->getRequest()->getBool( 'unhide' ) ); $output->addHTML( '</div>' ); return true; } /** * Returns the ID of the previous Revision, if it is set, otherwise 0. * * @return int|null */ protected function getPrevId() { return $this->prevRev ? $this->prevRev->getId() : 0; } /** * Setups the mobile DifferenceEngine and displays a mobile optimised diff. */ protected function displayDiffPage() { $unhide = $this->getRequest()->getBool( 'unhide' ); $contentHandler = $this->rev->getContentHandler(); $this->mDiffEngine = $contentHandler->createDifferenceEngine( $this->getContext(), $this->getPrevId(), $this->revId, 0, false, $unhide ); $this->showHeader( $unhide ); $this->mDiffEngine->showDiffPage(); } /** * Render the header of a diff page including: * Navigation links * Name with url to page * Bytes added/removed * Day and time of edit * Edit Comment */ private function showHeader( $unhide = false ) { if ( $this->rev->isMinor() ) { $minor = ChangesList::flag( 'minor' ); } else { $minor = ''; } $this->getOutput()->addHTML( $this->getRevisionNavigationLinksHTML() . $this->getIntroHTML() . $minor . $this->getCommentHTML( $unhide ) ); } /** * Get the edit comment * @return string Build HTML for edit comment section */ private function getCommentHTML( $unhide = false ) { $audience = $unhide ? Revision::FOR_THIS_USER : Revision::FOR_PUBLIC; $comment = $this->rev->getComment( $audience ); if ( $this->rev->isDeleted( Revision::DELETED_COMMENT ) && !$unhide ) { $commentHtml = $this->msg( 'rev-deleted-comment' )->escaped(); } elseif ( $comment !== '' && $comment !== null ) { $commentHtml = Linker::formatComment( $comment, $this->targetTitle ); } else { $commentHtml = $this->msg( 'mobile-frontend-changeslist-nocomment' )->escaped(); } return Html::rawElement( 'div', [ 'id' => 'mw-mf-diff-comment' ], $commentHtml ); } /** * Get the intro HTML * @return string Built HTML for intro section */ private function getIntroHTML() { if ( $this->prevRev ) { $bytesChanged = $this->rev->getSize() - $this->prevRev->getSize(); } else { $bytesChanged = $this->rev->getSize(); } if ( $bytesChanged > 0 ) { $changeMsg = 'mobile-frontend-diffview-bytesadded'; $sizeClass = MobileUI::iconClass( 'bytesadded', 'before', 'meta mw-mf-bytesadded mw-ui-icon-small' ); } elseif ( $bytesChanged === 0 ) { $changeMsg = 'mobile-frontend-diffview-bytesnochange'; $sizeClass = MobileUI::iconClass( 'bytesneutral', 'before', 'meta mw-mf-bytesneutral mw-ui-icon-small' ); } else { $changeMsg = 'mobile-frontend-diffview-bytesremoved'; $sizeClass = MobileUI::iconClass( 'bytesremoved', 'before', 'meta mw-mf-bytesremoved mw-ui-icon-small' ); $bytesChanged = abs( $bytesChanged ); } $ts = new MWTimestamp( $this->rev->getTimestamp() ); return Html::openElement( 'div', [ 'id' => 'mw-mf-diff-info', 'class' => 'page-summary' ] ) . Html::openElement( 'h2' ) . Html::element( 'a', [ 'href' => $this->targetTitle->getLocalURL( [ 'oldid' => $this->revId, ] ) ], $this->targetTitle->getPrefixedText() ) . Html::closeElement( 'h2' ) . $this->msg( 'mobile-frontend-diffview-comma' )->rawParams( Html::element( 'span', [ 'class' => $sizeClass ], $this->msg( $changeMsg )->numParams( $bytesChanged )->text() ), Html::element( 'span', [ 'class' => 'mw-mf-diff-date meta' ], $this->getLanguage()->getHumanTimestamp( $ts ) ) )->parse() . Html::closeElement( 'div' ); } /** * Render the revision navigation links * @return string built HTML for Revision navigation links */ private function getRevisionNavigationLinksHTML() { $prev = $this->rev->getPrevious(); $next = $this->rev->getNext(); $history = ''; if ( $prev || $next ) { $history = Html::openElement( 'ul', [ 'class' => 'hlist revision-history-links' ] ); if ( $prev ) { $history .= Html::openElement( 'li', [ 'class' => 'revision-history-prev' ] ) . Html::element( 'a', [ 'href' => SpecialPage::getTitleFor( 'MobileDiff', $prev->getId() ) ->getLocalURL() ], $this->msg( 'previousdiff' )->text() ) . Html::closeElement( 'li' ); } if ( $next ) { $history .= Html::openElement( 'li', [ 'class' => 'revision-history-next' ] ) . Html::element( 'a', [ 'href' => SpecialPage::getTitleFor( 'MobileDiff', $next->getId() ) ->getLocalURL() ], $this->msg( 'nextdiff' )->text() ) . Html::closeElement( 'li' ); } $history .= Html::closeElement( 'ul' ); } return $history; } /** * Render the footer including userinfos (Name, Role, Editcount) * * @param IContextSource $context * @param bool $unhide whether hidden content should be shown */ private function showFooter( IContextSource $context, $unhide ) { $output = $this->getOutput(); $output->addHTML( Html::openElement( 'div', [ 'id' => 'mw-mf-userinfo', 'class' => 'position-fixed' ] ) . Html::openElement( 'div', [ 'class' => 'post-content' ] ) ); $audience = $unhide ? Revision::FOR_THIS_USER : Revision::FOR_PUBLIC; $userId = $this->rev->getUser( $audience ); $ipAddr = $this->rev->getUserText( $audience ); // Note $userId will be 0 and $ipAddr an empty string if the current audience cannot see it. if ( $userId ) { $user = User::newFromId( $userId ); $edits = $user->getEditCount(); $attrs = [ 'class' => MobileUI::iconClass( 'user', 'before', 'mw-mf-user' ), 'data-revision-id' => $this->revId, 'data-user-name' => $user->getName(), 'data-user-gender' => $user->getOption( 'gender' ), ]; // Note we do not use LinkRenderer here as this will render // a broken link if the user page does not exist $output->addHTML( Html::openElement( 'div', $attrs ) . $this->getLinkRenderer()->makeLink( $user->getUserPage(), $user->getName(), [ 'class' => 'mw-mf-user-link' ], // T197581: Override red linking so that the user page is always accessible // for user pages that do not exist. We want to allow access to contributions [ 'action' => 'view' ] ) . '</div>' . '<div class="mw-mf-roles meta">' . $this->listGroups( $user, $context ) . '</div>' . '<div class="mw-mf-edit-count meta">' . $this->msg( 'mobile-frontend-diffview-editcount', $this->getLanguage()->formatNum( $edits ) )->parse() . '</div>' ); } elseif ( $ipAddr ) { $userPage = SpecialPage::getTitleFor( 'Contributions', $ipAddr ); $output->addHTML( Html::element( 'div', [ 'class' => MobileUI::iconClass( 'anonymous', 'before', 'mw-mf-user mw-mf-anon' ), ], $this->msg( 'mobile-frontend-diffview-anonymous' )->text() ) . '<div>' . $this->getLinkRenderer()->makeLink( $userPage, $ipAddr ) . '</div>' ); } else { // Case where the user cannot see who made the edit $output->addHTML( $this->msg( 'rev-deleted-user' )->escaped() ); } $output->addHTML( Html::closeElement( 'div' ) . Html::closeElement( 'div' ) ); } /** * Get the list of groups of user * @param User $user The user object to get the list from * @param IContextSource $context * @return string comma separated list of user groups */ private function listGroups( User $user, IContextSource $context ) { // Get groups to which the user belongs $userGroups = $user->getGroups(); $userMembers = []; foreach ( $userGroups as $group ) { $userMembers[] = UserGroupMembership::getLink( $group, $context, 'html' ); } return $this->getLanguage()->commaList( $userMembers ); } /** * Get the url for the mobile diff special page to use in Desktop footer * @return bool|string Return URL or false when revision id's not set */ public static function getMobileUrlFromDesktop() { $req = MobileContext::singleton()->getRequest(); $rev2 = $req->getText( 'diff' ); $rev1 = $req->getText( 'oldid' ); // Actually, both do the same, WTF if ( $rev1 == 'prev' || $rev1 == 'next' ) { $rev1 = ''; } // redirect requests to the diff page to mobile view if ( !$rev2 ) { if ( $rev1 ) { $rev2 = $rev1; $rev1 = ''; } else { return false; } } if ( $rev1 ) { $rev = static::getRevision( $rev1 ); if ( $rev ) { // the diff parameter could be the string prev or next - deal with these cases if ( $rev2 === 'prev' ) { $prev = $rev->getPrevious(); // yes this is confusing - this is how it works arrgghh $rev2 = $rev1; $rev1 = $prev ? $prev->getId() : ''; } elseif ( $rev2 === 'next' ) { $next = $rev->getNext(); $rev2 = $next ? $next->getId() : ''; } else { $rev2 = static::getRevision( $rev2 ); $rev2 = $rev2 ? $rev2->getId() : ''; } } else { $rev2 = ''; } } if ( $rev2 ) { $subpage = $rev1 ? $rev1 . '...' . $rev2 : $rev2; $title = SpecialPage::getTitleFor( 'MobileDiff', $subpage ); return $title->getLocalURL(); } return false; } /** * Get the URL for Desktop version of difference view * @param string $subPage URL of mobile diff page * @return string Url to mobile diff page */ public function getDesktopUrl( $subPage ) { $parts = explode( '...', $subPage ); if ( count( $parts ) > 1 ) { $params = [ 'diff' => $parts[1], 'oldid' => $parts[0] ]; } else { $params = [ 'diff' => $parts[0] ]; } if ( $this->getRequest()->getVal( 'unhide' ) ) { $params['unhide'] = 1; } return wfAppendQuery( wfScript(), $params ); } }