From 08aa4418c30cfc18ccc69a0f0f9cb9e17be6c196 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Mon, 12 Aug 2013 09:28:15 +0200 Subject: Update to MediaWiki 1.21.1 --- includes/diff/DifferenceEngine.php | 191 +++++++++++++++++++++++++++++-------- 1 file changed, 149 insertions(+), 42 deletions(-) (limited to 'includes/diff/DifferenceEngine.php') diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php index c7156fb2..0f3c77ff 100644 --- a/includes/diff/DifferenceEngine.php +++ b/includes/diff/DifferenceEngine.php @@ -38,7 +38,10 @@ class DifferenceEngine extends ContextSource { * @private */ var $mOldid, $mNewid; - var $mOldtext, $mNewtext; + /** + * @var Content + */ + var $mOldContent, $mNewContent; protected $mDiffLang; /** @@ -77,7 +80,7 @@ class DifferenceEngine extends ContextSource { * Constructor * @param $context IContextSource context to use, anything else will be ignored * @param $old Integer old ID we want to show and diff with. - * @param $new String either 'prev' or 'next'. + * @param string $new either 'prev' or 'next'. * @param $rcid Integer ??? FIXME (default 0) * @param $refreshCache boolean If set, refreshes the diff cache * @param $unhide boolean If set, allow viewing deleted revs @@ -149,7 +152,7 @@ class DifferenceEngine extends ContextSource { function deletedLink( $id ) { if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) { $dbr = wfGetDB( DB_SLAVE ); - $row = $dbr->selectRow('archive', '*', + $row = $dbr->selectRow( 'archive', '*', array( 'ar_rev_id' => $id ), __METHOD__ ); if ( $row ) { @@ -224,6 +227,10 @@ class DifferenceEngine extends ContextSource { # 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 should be mOldPage, but it may not be set, see below. @@ -260,6 +267,8 @@ class DifferenceEngine extends ContextSource { $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. @@ -287,12 +296,14 @@ class DifferenceEngine extends ContextSource { 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() ); + $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 = ' ' . $this->msg( 'parentheses' )->rawParams( - Html::element( 'a', array( + $undoLink = Html::element( 'a', array( 'href' => $this->mNewPage->getLocalUrl( array( 'action' => 'edit', 'undoafter' => $this->mOldid, @@ -300,7 +311,8 @@ class DifferenceEngine extends ContextSource { 'title' => Linker::titleAttrib( 'undo' ) ), $this->msg( 'editundo' )->text() - ) )->escaped(); + ); + $revisionTools[] = $undoLink; } } @@ -366,7 +378,15 @@ class DifferenceEngine extends ContextSource { # Handle RevisionDelete links... $rdel = $this->revisionDeleteLink( $this->mNewRev ); - $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) . $undoLink; + + # Allow extensions to define their own revision tools + wfRunHooks( 'DiffRevisionTools', array( $this->mNewRev, &$revisionTools ) ); + $formattedRevisionTools = array(); + // Put each one in parentheses (poor man's button) + foreach ( $revisionTools as $tool ) { + $formattedRevisionTools[] = $this->msg( 'parentheses' )->rawParams( $tool )->escaped(); + } + $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) . ' ' . implode( ' ', $formattedRevisionTools ); $newHeader = '
' . $newRevisionHeader . '
' . '
' . Linker::revUserTools( $this->mNewRev, !$this->unhide ) . @@ -417,8 +437,8 @@ class DifferenceEngine extends ContextSource { /** * Get a link to mark the change as patrolled, or '' if there's either no * revision to patrol or the user is not allowed to to it. - * Side effect: this method will call OutputPage::preventClickjacking() - * when a link is builded. + * Side effect: When the patrol link is build, this method will call + * OutputPage::preventClickjacking() and load mediawiki.page.patrol.ajax. * * @return String */ @@ -459,6 +479,8 @@ class DifferenceEngine extends ContextSource { // Build the link if ( $rcid ) { $this->getOutput()->preventClickjacking(); + $this->getOutput()->addModules( 'mediawiki.page.patrol.ajax' ); + $token = $this->getUser()->getEditToken( $rcid ); $this->mMarkPatrolledLink = ' [' . Linker::linkKnown( $this->mNewPage, @@ -510,19 +532,23 @@ class DifferenceEngine extends ContextSource { $out->setRevisionTimestamp( $this->mNewRev->getTimestamp() ); $out->setArticleFlag( true ); + // NOTE: only needed for B/C: custom rendering of JS/CSS via hook if ( $this->mNewPage->isCssJsSubpage() || $this->mNewPage->isCssOrJsPage() ) { // Stolen from Article::view --AG 2007-10-11 // Give hooks a chance to customise the output // @TODO: standardize this crap into one function - if ( wfRunHooks( 'ShowRawCssJs', array( $this->mNewtext, $this->mNewPage, $out ) ) ) { - // Wrap the whole lot in a
 and don't parse
-					$m = array();
-					preg_match( '!\.(css|js)$!u', $this->mNewPage->getText(), $m );
-					$out->addHTML( "
\n" );
-					$out->addHTML( htmlspecialchars( $this->mNewtext ) );
-					$out->addHTML( "\n
\n" ); + if ( ContentHandler::runLegacyHooks( 'ShowRawCssJs', array( $this->mNewContent, $this->mNewPage, $out ) ) ) { + // NOTE: deprecated hook, B/C only + // use the content object's own rendering + $cnt = $this->mNewRev->getContent(); + $po = $cnt ? $cnt->getParserOutput( $this->mNewRev->getTitle(), $this->mNewRev->getId() ) : null; + $txt = $po ? $po->getText() : ''; + $out->addHTML( $txt ); } - } elseif ( !wfRunHooks( 'ArticleViewCustom', array( $this->mNewtext, $this->mNewPage, $out ) ) ) { + } elseif( !wfRunHooks( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) { + // Handled by extension + } elseif( !ContentHandler::runLegacyHooks( 'ArticleViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) { + // NOTE: deprecated hook, B/C only // Handled by extension } else { // Normal page @@ -536,16 +562,21 @@ class DifferenceEngine extends ContextSource { $wikiPage = WikiPage::factory( $this->mNewPage ); } - $parserOptions = $wikiPage->makeParserOptions( $this->getContext() ); + $parserOutput = $this->getParserOutput( $wikiPage, $this->mNewRev ); - if ( !$this->mNewRev->isCurrent() ) { - $parserOptions->setEditSection( false ); - } + # Also try to load it as a redirect + $rt = $this->mNewContent ? $this->mNewContent->getRedirectTarget() : null; - $parserOutput = $wikiPage->getParserOutput( $parserOptions, $this->mNewid ); + if ( $rt ) { + $article = Article::newFromTitle( $this->mNewPage, $this->getContext() ); + $out->addHTML( $article->viewRedirect( $rt ) ); - # WikiPage::getParserOutput() should not return false, but just in case - if( $parserOutput ) { + # WikiPage::getParserOutput() should not return false, but just in case + if ( $parserOutput ) { + # Show categories etc. + $out->addParserOutputNoText( $parserOutput ); + } + } else if ( $parserOutput ) { $out->addParserOutput( $parserOutput ); } } @@ -556,6 +587,17 @@ class DifferenceEngine extends ContextSource { wfProfileOut( __METHOD__ ); } + protected function getParserOutput( WikiPage $page, Revision $rev ) { + $parserOptions = $page->makeParserOptions( $this->getContext() ); + + if ( !$rev->isCurrent() || !$rev->getTitle()->quickUserCan( "edit" ) ) { + $parserOptions->setEditSection( false ); + } + + $parserOutput = $page->getParserOutput( $parserOptions, $rev->getId() ); + return $parserOutput; + } + /** * Get the diff text, send it to the OutputPage object * Returns false if the diff could not be generated, otherwise returns true @@ -584,9 +626,9 @@ class DifferenceEngine extends ContextSource { /** * Get complete diff table, including header * - * @param $otitle Title: old title - * @param $ntitle Title: new title - * @param $notice String: HTML between diff header and body + * @param string|bool $otitle Header for old text or false + * @param string|bool $ntitle Header for new text or false + * @param string $notice HTML between diff header and body * @return mixed */ function getDiff( $otitle, $ntitle, $notice = '' ) { @@ -652,7 +694,7 @@ class DifferenceEngine extends ContextSource { return false; } - $difftext = $this->generateDiffBody( $this->mOldtext, $this->mNewtext ); + $difftext = $this->generateContentDiffBody( $this->mOldContent, $this->mNewContent ); // Save to cache for 7 days if ( !wfRunHooks( 'AbortDiffCache', array( &$this ) ) ) { @@ -689,14 +731,65 @@ class DifferenceEngine extends ContextSource { } } + /** + * Generate a diff, no caching. + * + * This implementation uses generateTextDiffBody() to generate a diff based on the default + * serialization of the given Content objects. This will fail if $old or $new are not + * instances of TextContent. + * + * Subclasses may override this to provide a different rendering for the diff, + * perhaps taking advantage of the content's native form. This is required for all content + * models that are not text based. + * + * @param $old Content: old content + * @param $new Content: new content + * + * @return bool|string + * @since 1.21 + * @throws MWException if $old or $new are not instances of TextContent. + */ + function generateContentDiffBody( Content $old, Content $new ) { + if ( !( $old instanceof TextContent ) ) { + throw new MWException( "Diff not implemented for " . get_class( $old ) . "; " + . "override generateContentDiffBody to fix this." ); + } + + if ( !( $new instanceof TextContent ) ) { + throw new MWException( "Diff not implemented for " . get_class( $new ) . "; " + . "override generateContentDiffBody to fix this." ); + } + + $otext = $old->serialize(); + $ntext = $new->serialize(); + + return $this->generateTextDiffBody( $otext, $ntext ); + } + /** * Generate a diff, no caching * - * @param $otext String: old text, must be already segmented - * @param $ntext String: new text, must be already segmented + * @param string $otext old text, must be already segmented + * @param string $ntext new text, must be already segmented * @return bool|string + * @deprecated since 1.21, use generateContentDiffBody() instead! */ function generateDiffBody( $otext, $ntext ) { + ContentHandler::deprecated( __METHOD__, "1.21" ); + + return $this->generateTextDiffBody( $otext, $ntext ); + } + + /** + * Generate a diff, no caching + * + * @todo move this to TextDifferenceEngine, make DifferenceEngine abstract. At some point. + * + * @param string $otext old text, must be already segmented + * @param string $ntext new text, must be already segmented + * @return bool|string + */ + function generateTextDiffBody( $otext, $ntext ) { global $wgExternalDiffEngine, $wgContLang; wfProfileIn( __METHOD__ ); @@ -804,7 +897,6 @@ class DifferenceEngine extends ContextSource { return $this->msg( 'lineno' )->numParams( $matches[1] )->escaped(); } - /** * If there are revisions between the ones being compared, return a note saying so. * @return string @@ -855,11 +947,11 @@ class DifferenceEngine extends ContextSource { * Get a header for a specified revision. * * @param $rev Revision - * @param $complete String: 'complete' to get the header wrapped depending + * @param string $complete 'complete' to get the header wrapped depending * the visibility of the revision and a link to edit the page. * @return String HTML fragment */ - private function getRevisionHeader( Revision $rev, $complete = '' ) { + protected function getRevisionHeader( Revision $rev, $complete = '' ) { $lang = $this->getLanguage(); $user = $this->getUser(); $revtimestamp = $rev->getTimestamp(); @@ -951,10 +1043,25 @@ class DifferenceEngine extends ContextSource { /** * Use specified text instead of loading from the database + * @deprecated since 1.21, use setContent() instead. */ function setText( $oldText, $newText ) { - $this->mOldtext = $oldText; - $this->mNewtext = $newText; + ContentHandler::deprecated( __METHOD__, "1.21" ); + + $oldContent = ContentHandler::makeContent( $oldText, $this->getTitle() ); + $newContent = ContentHandler::makeContent( $newText, $this->getTitle() ); + + $this->setContent( $oldContent, $newContent ); + } + + /** + * Use specified text instead of loading from the database + * @since 1.21 + */ + function setContent( Content $oldContent, Content $newContent ) { + $this->mOldContent = $oldContent; + $this->mNewContent = $newContent; + $this->mTextLoaded = 2; $this->mRevisionsLoaded = true; } @@ -1082,14 +1189,14 @@ class DifferenceEngine extends ContextSource { return false; } if ( $this->mOldRev ) { - $this->mOldtext = $this->mOldRev->getText( Revision::FOR_THIS_USER ); - if ( $this->mOldtext === false ) { + $this->mOldContent = $this->mOldRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ); + if ( $this->mOldContent === null ) { return false; } } if ( $this->mNewRev ) { - $this->mNewtext = $this->mNewRev->getText( Revision::FOR_THIS_USER ); - if ( $this->mNewtext === false ) { + $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ); + if ( $this->mNewContent === null ) { return false; } } @@ -1110,7 +1217,7 @@ class DifferenceEngine extends ContextSource { if ( !$this->loadRevisionData() ) { return false; } - $this->mNewtext = $this->mNewRev->getText( Revision::FOR_THIS_USER ); + $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ); return true; } } -- cgit v1.2.3-54-g00ecf