Current File : /home/jvzmxxx/wiki1/extensions/MobileFrontend/includes/specials/SpecialMobileDiff.php
<?php
/**
 * SpecialMobileDiff.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;
	/** @var String $diffClass The name of the Difference class */
	protected $diffClass = 'InlineDifferenceEngine';

	/**
	 * Construct function
	 */
	public function __construct() {
		parent::__construct( 'MobileDiff' );
	}

	/**
	 * Get the revision object from ID
	 * @param integer $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[] 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 = intval( $revids[1] );
			$prevId = intval( $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 = intval( $revids[0] );
			if ( $id ) {
				$rev = static::getRevision( $id );
				if ( $rev ) {
					$prev = $rev->getPrevious();
				}
			}
		}
		return [ $prev, $rev ];
	}

	/**
	 * Render the diff page
	 * @return boolean false when revision not exist
	 * @param string $par Revision IDs separated by three points (e.g. 123...124)
	 */
	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 ( is_null( $rev ) ) {
			$this->executeBadQuery();
			return false;
		}
		$this->revId = $rev->getId();
		$this->rev = $rev;
		$this->prevRev = $prev;
		$this->targetTitle = $this->rev->getTitle();

		$output->setPageTitle( $this->msg(
			'mobile-frontend-diffview-title',
			$this->targetTitle->getPrefixedText()
		) );

		$output->addModuleStyles( [
			'skins.minerva.icons.images.scripts',
			'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'
		] );

		// 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->showHeader();
		$this->showDiff();
		$output->addHtml( '</div>' );

		$this->showFooter( $ctx );

		$output->addHtml( '</div>' );

		return true;
	}

	/**
	 * Render the header of a diff page including:
	 * Name with url to page
	 * Bytes added/removed
	 * Day and time of edit
	 * Edit Comment
	 */
	function showHeader() {
		$title = $this->targetTitle;

		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', 'icon-12px meta mw-mf-bytesadded' );
		} elseif ( $bytesChanged === 0 ) {
			$changeMsg = 'mobile-frontend-diffview-bytesnochange';
			$sizeClass = MobileUI::iconClass( 'bytesneutral', 'before',
				'icon-12px meta mw-mf-bytesneutral' );
		} else {
			$changeMsg = 'mobile-frontend-diffview-bytesremoved';
			$sizeClass = MobileUI::iconClass( 'bytesremoved', 'before',
				'icon-12px meta mw-mf-bytesremoved' );
			$bytesChanged = abs( $bytesChanged );
		}

		if ( $this->rev->isMinor() ) {
			$minor = ChangesList::flag( 'minor' );
		} else {
			$minor = '';
		}
		if ( $this->rev->getComment() !== '' ) {
			$comment = Linker::formatComment( $this->rev->getComment(), $title );
		} else {
			$comment = $this->msg( 'mobile-frontend-changeslist-nocomment' )->escaped();
		}

		$ts = new MWTimestamp( $this->rev->getTimestamp() );
		$this->getOutput()->addHtml(
			Html::openElement( 'div', [ 'id' => 'mw-mf-diff-info', 'class' => 'page-summary' ] )
				. Html::openElement( 'h2', [] )
				. Html::element( 'a',
					[
						'href' => $title->getLocalURL(),
					],
					$title->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 )
					)
				)->text()
			. Html::closeElement( 'div' )
			. $minor
			. Html::rawElement(
				'div',
				[ 'id' => 'mw-mf-diff-comment' ],
				$comment
			)
		);
	}

	/**
	 * Render the inline difference between two revisions
	 * using InlineDiffEngine
	 */
	function showDiff() {
		$output = $this->getOutput();

		$prevId = $this->prevRev ? $this->prevRev->getId() : 0;
		$unhide = (bool)$this->getRequest()->getVal( 'unhide' );
		$contentHandler = $this->rev->getContentHandler();
		$de = $contentHandler->createDifferenceEngine( $this->getContext(), $prevId, $this->revId );
		// HACK:
		if ( get_class( $de ) == 'DifferenceEngine' ) {
			$de = new $this->diffClass(
				$this->getContext(),
				$prevId,
				$this->revId,
				0,
				false,
				$unhide
			);
		} else {
			$de->showDiffPage();
			return;
		}
		$this->mDiffEngine = $de;
		$diff = $de->getDiffBody();
		if ( !$prevId ) {
			$audience = $unhide ? Revision::FOR_THIS_USER : Revision::FOR_PUBLIC;
			$diff = '<ins>'
				. nl2br(
					htmlspecialchars(
						ContentHandler::getContentText( $this->rev->getContent( $audience ) )
					)
				)
				. '</ins>';
		}

		$warnings = $de->getWarningMessageText();
		if ( $warnings ) {
			$warnings = MobileUI::warningBox( $warnings );
		}
		$output->addHtml(
			$warnings .
			'<div id="mw-mf-minidiff">' .
			$diff .
			'</div>'
		);
		$prev = $this->rev->getPrevious();
		$next = $this->rev->getNext();
		if ( $prev || $next ) {
			$history = Html::openElement( 'ul', [ 'class' => 'hlist revision-history-links' ] );
			if ( $prev ) {
				$history .= Html::openElement( 'li' ) .
					Html::element( 'a', [
						'href' => SpecialPage::getTitleFor( 'MobileDiff', $prev->getId() )->getLocalUrl()
					], $this->msg( 'previousdiff' ) ) . Html::closeElement( 'li' );
			}
			if ( $next ) {
				$history .= Html::openElement( 'li' ) .
					Html::element( 'a', [
						'href' => SpecialPage::getTitleFor( 'MobileDiff', $next->getId() )->getLocalUrl()
					], $this->msg( 'nextdiff' ) ) . Html::closeElement( 'li' );
			}
			$history .= Html::closeElement( 'ul' );
			$output->addHtml( $history );
		}

		$diffEngine = $this->mDiffEngine;
		if ( $diffEngine instanceof InlineDifferenceEngine ) {
			$output->addHtml( Html::rawElement(
				'div',
				[
					'class' => 'patrollink'
				],
				$diffEngine->getPatrolledLink()
			) );
		}
	}

	/**
	 * Render the footer including userinfos (Name, Role, Editcount)
	 *
	 * @param IContextSource $context Context
	 */
	private function showFooter( IContextSource $context ) {
		$output = $this->getOutput();

		$output->addHtml(
			Html::openElement( 'div', [ 'id' => 'mw-mf-userinfo',
				'class' => 'position-fixed' ] ) .
			Html::openElement( 'div', [ 'class' => 'post-content' ] )
		);

		$userId = $this->rev->getUser();
		if ( $userId ) {
			$user = User::newFromId( $userId );
			$edits = $user->getEditCount();
			$attrs = [
				'class' => MobileUI::iconClass( 'user', 'before', 'mw-mf-user icon-16px' ),
				'data-revision-id' => $this->revId,
				'data-user-name' => $user->getName(),
				'data-user-gender' => $user->getOption( 'gender' ),
			];
			$output->addHtml(
				Html::openElement( 'div', $attrs ) .
				$this->getLinkRenderer()->makeLink(
					$user->getUserPage(),
					$user->getName(),
					[ 'class' => 'mw-mf-user-link' ]
				) .
				'</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>'
			);
		} else {
			$ipAddr = $this->rev->getUserText();
			$userPage = SpecialPage::getTitleFor( 'Contributions', $ipAddr );
			$output->addHtml(
				Html::element( 'div', [
					'class' =>  MobileUI::iconClass( 'anonymous', 'before', 'mw-mf-user icon-16px mw-mf-anon' ),
				], $this->msg( 'mobile-frontend-diffview-anonymous' ) ) .
				'<div>' .
					$this->getLinkRenderer()->makeLink( $userPage, $ipAddr ) .
				'</div>'
			);
		}

		$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 The 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 boolean|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' );
		if ( $rev1 == 'prev' || $rev1 == 'next' ) { // Actually, both do the same, WTF
			$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 );
	}
}