summaryrefslogtreecommitdiff
path: root/includes/diff
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2012-05-03 13:01:35 +0200
committerPierre Schmitz <pierre@archlinux.de>2012-05-03 13:01:35 +0200
commitd9022f63880ce039446fba8364f68e656b7bf4cb (patch)
tree16b40fbf17bf7c9ee6f4ead25b16dd192378050a /includes/diff
parent27cf83d177256813e2e802241085fce5dd0f3fb9 (diff)
Update to MediaWiki 1.19.0
Diffstat (limited to 'includes/diff')
-rw-r--r--includes/diff/DairikiDiff.php187
-rw-r--r--includes/diff/DifferenceEngine.php913
-rw-r--r--includes/diff/WikiDiff3.php5
3 files changed, 604 insertions, 501 deletions
diff --git a/includes/diff/DairikiDiff.php b/includes/diff/DairikiDiff.php
index 8f19712b..c935eee2 100644
--- a/includes/diff/DairikiDiff.php
+++ b/includes/diff/DairikiDiff.php
@@ -24,10 +24,16 @@ class _DiffOp {
trigger_error( 'pure virtual', E_USER_ERROR );
}
+ /**
+ * @return int
+ */
function norig() {
return $this->orig ? sizeof( $this->orig ) : 0;
}
+ /**
+ * @return int
+ */
function nclosing() {
return $this->closing ? sizeof( $this->closing ) : 0;
}
@@ -49,6 +55,9 @@ class _DiffOp_Copy extends _DiffOp {
$this->closing = $closing;
}
+ /**
+ * @return _DiffOp_Copy
+ */
function reverse() {
return new _DiffOp_Copy( $this->closing, $this->orig );
}
@@ -67,6 +76,9 @@ class _DiffOp_Delete extends _DiffOp {
$this->closing = false;
}
+ /**
+ * @return _DiffOp_Add
+ */
function reverse() {
return new _DiffOp_Add( $this->orig );
}
@@ -85,6 +97,9 @@ class _DiffOp_Add extends _DiffOp {
$this->orig = false;
}
+ /**
+ * @return _DiffOp_Delete
+ */
function reverse() {
return new _DiffOp_Delete( $this->closing );
}
@@ -103,6 +118,9 @@ class _DiffOp_Change extends _DiffOp {
$this->closing = $closing;
}
+ /**
+ * @return _DiffOp_Change
+ */
function reverse() {
return new _DiffOp_Change( $this->closing, $this->orig );
}
@@ -145,6 +163,11 @@ class _DiffEngine {
protected $lcs = 0;
+ /**
+ * @param $from_lines
+ * @param $to_lines
+ * @return array
+ */
function diff ( $from_lines, $to_lines ) {
wfProfileIn( __METHOD__ );
@@ -199,6 +222,10 @@ class _DiffEngine {
return $edits;
}
+ /**
+ * @param $from_lines
+ * @param $to_lines
+ */
function diff_local ( $from_lines, $to_lines ) {
global $wgExternalDiffEngine;
wfProfileIn( __METHOD__ );
@@ -268,6 +295,8 @@ class _DiffEngine {
/**
* Returns the whole line if it's small enough, or the MD5 hash otherwise
+ * @param $line string
+ * @return string
*/
function _line_hash( $line ) {
if ( strlen( $line ) > self::MAX_XREF_LENGTH ) {
@@ -293,6 +322,12 @@ class _DiffEngine {
* of the two files do not match, and likewise that the last lines do not
* match. The caller must trim matching lines from the beginning and end
* of the portions it is going to specify.
+ * @param $xoff
+ * @param $xlim
+ * @param $yoff
+ * @param $ylim
+ * @param $nchunks
+ * @return array
*/
function _diag( $xoff, $xlim, $yoff, $ylim, $nchunks ) {
$flip = false;
@@ -373,6 +408,10 @@ class _DiffEngine {
return array( $this->lcs, $seps );
}
+ /**
+ * @param $ypos
+ * @return int
+ */
function _lcs_pos( $ypos ) {
$end = $this->lcs;
if ( $end == 0 || $ypos > $this->seq[$end] ) {
@@ -410,6 +449,10 @@ class _DiffEngine {
*
* Note that XLIM, YLIM are exclusive bounds.
* All line numbers are origin-0 and discarded lines are not counted.
+ * @param $xoff
+ * @param $xlim
+ * @param $yoff
+ * @param $ylim
*/
function _compareseq ( $xoff, $xlim, $yoff, $ylim ) {
// Slide down the bottom initial diagonal.
@@ -703,6 +746,8 @@ class Diff {
* Check a Diff for validity.
*
* This is here only for debugging purposes.
+ * @param $from_lines
+ * @param $to_lines
*/
function _check( $from_lines, $to_lines ) {
wfProfileIn( __METHOD__ );
@@ -886,6 +931,13 @@ class DiffFormatter {
return $end;
}
+ /**
+ * @param $xbeg
+ * @param $xlen
+ * @param $ybeg
+ * @param $ylen
+ * @param $edits
+ */
function _block( $xbeg, $xlen, $ybeg, $ylen, &$edits ) {
wfProfileIn( __METHOD__ );
$this->_start_block( $this->_block_header( $xbeg, $xlen, $ybeg, $ylen ) );
@@ -910,12 +962,22 @@ class DiffFormatter {
ob_start();
}
+ /**
+ * @return string
+ */
function _end_diff() {
$val = ob_get_contents();
ob_end_clean();
return $val;
}
+ /**
+ * @param $xbeg
+ * @param $xlen
+ * @param $ybeg
+ * @param $ylen
+ * @return string
+ */
function _block_header( $xbeg, $xlen, $ybeg, $ylen ) {
if ( $xlen > 1 ) {
$xbeg .= ',' . ( $xbeg + $xlen - 1 );
@@ -934,23 +996,41 @@ class DiffFormatter {
function _end_block() {
}
+ /**
+ * @param $lines
+ * @param $prefix string
+ */
function _lines( $lines, $prefix = ' ' ) {
foreach ( $lines as $line ) {
echo "$prefix $line\n";
}
}
+ /**
+ * @param $lines
+ */
function _context( $lines ) {
$this->_lines( $lines );
}
+ /**
+ * @param $lines
+ */
function _added( $lines ) {
$this->_lines( $lines, '>' );
}
+
+ /**
+ * @param $lines
+ */
function _deleted( $lines ) {
$this->_lines( $lines, '<' );
}
+ /**
+ * @param $orig
+ * @param $closing
+ */
function _changed( $orig, $closing ) {
$this->_deleted( $orig );
echo "---\n";
@@ -966,16 +1046,36 @@ class UnifiedDiffFormatter extends DiffFormatter {
var $leading_context_lines = 2;
var $trailing_context_lines = 2;
+ /**
+ * @param $lines
+ */
function _added( $lines ) {
$this->_lines( $lines, '+' );
}
+
+ /**
+ * @param $lines
+ */
function _deleted( $lines ) {
$this->_lines( $lines, '-' );
}
+
+ /**
+ * @param $orig
+ * @param $closing
+ */
function _changed( $orig, $closing ) {
$this->_deleted( $orig );
$this->_added( $closing );
}
+
+ /**
+ * @param $xbeg
+ * @param $xlen
+ * @param $ybeg
+ * @param $ylen
+ * @return string
+ */
function _block_header( $xbeg, $xlen, $ybeg, $ylen ) {
return "@@ -$xbeg,$xlen +$ybeg,$ylen @@";
}
@@ -986,6 +1086,11 @@ class UnifiedDiffFormatter extends DiffFormatter {
* @ingroup DifferenceEngine
*/
class ArrayDiffFormatter extends DiffFormatter {
+
+ /**
+ * @param $diff
+ * @return array
+ */
function format( $diff ) {
$oldline = 1;
$newline = 1;
@@ -1049,6 +1154,9 @@ class _HWLDF_WordAccumulator {
$this->_tag = '';
}
+ /**
+ * @param $new_tag
+ */
function _flushGroup( $new_tag ) {
if ( $this->_group !== '' ) {
if ( $this->_tag == 'ins' ) {
@@ -1065,6 +1173,9 @@ class _HWLDF_WordAccumulator {
$this->_tag = $new_tag;
}
+ /**
+ * @param $new_tag
+ */
function _flushLine( $new_tag ) {
$this->_flushGroup( $new_tag );
if ( $this->_line != '' ) {
@@ -1076,6 +1187,10 @@ class _HWLDF_WordAccumulator {
$this->_line = '';
}
+ /**
+ * @param $words
+ * @param $tag string
+ */
function addWords ( $words, $tag = '' ) {
if ( $tag != $this->_tag ) {
$this->_flushGroup( $tag );
@@ -1095,6 +1210,9 @@ class _HWLDF_WordAccumulator {
}
}
+ /**
+ * @return array
+ */
function getLines() {
$this->_flushLine( '~done' );
return $this->_lines;
@@ -1109,6 +1227,10 @@ class _HWLDF_WordAccumulator {
class WordLevelDiff extends MappedDiff {
const MAX_LINE_LENGTH = 10000;
+ /**
+ * @param $orig_lines
+ * @param $closing_lines
+ */
function __construct ( $orig_lines, $closing_lines ) {
wfProfileIn( __METHOD__ );
@@ -1120,6 +1242,10 @@ class WordLevelDiff extends MappedDiff {
wfProfileOut( __METHOD__ );
}
+ /**
+ * @param $lines
+ * @return array
+ */
function _split( $lines ) {
wfProfileIn( __METHOD__ );
@@ -1152,6 +1278,9 @@ class WordLevelDiff extends MappedDiff {
return array( $words, $stripped );
}
+ /**
+ * @return array
+ */
function orig() {
wfProfileIn( __METHOD__ );
$orig = new _HWLDF_WordAccumulator;
@@ -1168,6 +1297,9 @@ class WordLevelDiff extends MappedDiff {
return $lines;
}
+ /**
+ * @return array
+ */
function closing() {
wfProfileIn( __METHOD__ );
$closing = new _HWLDF_WordAccumulator;
@@ -1197,6 +1329,11 @@ class TableDiffFormatter extends DiffFormatter {
$this->trailing_context_lines = 2;
}
+ /**
+ * @static
+ * @param $msg
+ * @return mixed
+ */
public static function escapeWhiteSpace( $msg ) {
$msg = preg_replace( '/^ /m', '&#160; ', $msg );
$msg = preg_replace( '/ $/m', ' &#160;', $msg );
@@ -1204,12 +1341,22 @@ class TableDiffFormatter extends DiffFormatter {
return $msg;
}
+ /**
+ * @param $xbeg
+ * @param $xlen
+ * @param $ybeg
+ * @param $ylen
+ * @return string
+ */
function _block_header( $xbeg, $xlen, $ybeg, $ylen ) {
$r = '<tr><td colspan="2" class="diff-lineno"><!--LINE ' . $xbeg . "--></td>\n" .
'<td colspan="2" class="diff-lineno"><!--LINE ' . $ybeg . "--></td></tr>\n";
return $r;
}
+ /**
+ * @param $header
+ */
function _start_block( $header ) {
echo $header;
}
@@ -1220,21 +1367,39 @@ class TableDiffFormatter extends DiffFormatter {
function _lines( $lines, $prefix = ' ', $color = 'white' ) {
}
- # HTML-escape parameter before calling this
+ /**
+ * HTML-escape parameter before calling this
+ * @param $line
+ * @return string
+ */
function addedLine( $line ) {
return $this->wrapLine( '+', 'diff-addedline', $line );
}
- # HTML-escape parameter before calling this
+ /**
+ * HTML-escape parameter before calling this
+ * @param $line
+ * @return string
+ */
function deletedLine( $line ) {
return $this->wrapLine( '−', 'diff-deletedline', $line );
}
- # HTML-escape parameter before calling this
+ /**
+ * HTML-escape parameter before calling this
+ * @param $line
+ * @return string
+ */
function contextLine( $line ) {
return $this->wrapLine( '&#160;', 'diff-context', $line );
}
+ /**
+ * @param $marker
+ * @param $class
+ * @param $line
+ * @return string
+ */
private function wrapLine( $marker, $class, $line ) {
if ( $line !== '' ) {
// The <div> wrapper is needed for 'overflow: auto' style to scroll properly
@@ -1243,10 +1408,16 @@ class TableDiffFormatter extends DiffFormatter {
return "<td class='diff-marker'>$marker</td><td class='$class'>$line</td>";
}
+ /**
+ * @return string
+ */
function emptyLine() {
return '<td colspan="2">&#160;</td>';
}
+ /**
+ * @param $lines array
+ */
function _added( $lines ) {
foreach ( $lines as $line ) {
echo '<tr>' . $this->emptyLine() .
@@ -1255,6 +1426,9 @@ class TableDiffFormatter extends DiffFormatter {
}
}
+ /**
+ * @param $lines
+ */
function _deleted( $lines ) {
foreach ( $lines as $line ) {
echo '<tr>' . $this->deletedLine( '<del class="diffchange">' .
@@ -1263,6 +1437,9 @@ class TableDiffFormatter extends DiffFormatter {
}
}
+ /**
+ * @param $lines
+ */
function _context( $lines ) {
foreach ( $lines as $line ) {
echo '<tr>' .
@@ -1271,6 +1448,10 @@ class TableDiffFormatter extends DiffFormatter {
}
}
+ /**
+ * @param $orig
+ * @param $closing
+ */
function _changed( $orig, $closing ) {
wfProfileIn( __METHOD__ );
diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php
index 5902461b..439e3204 100644
--- a/includes/diff/DifferenceEngine.php
+++ b/includes/diff/DifferenceEngine.php
@@ -18,24 +18,25 @@ define( 'MW_DIFF_VERSION', '1.11a' );
* @todo document
* @ingroup DifferenceEngine
*/
-class DifferenceEngine {
+class DifferenceEngine extends ContextSource {
/**#@+
* @private
*/
var $mOldid, $mNewid;
- var $mOldtitle, $mNewtitle, $mPagetitle;
var $mOldtext, $mNewtext;
+ protected $mDiffLang;
/**
* @var Title
*/
- var $mOldPage, $mNewPage, $mTitle;
+ var $mOldPage, $mNewPage;
var $mRcidMarkPatrolled;
/**
* @var Revision
*/
var $mOldRev, $mNewRev;
+ private $mRevisionsIdsLoaded = false; // Have the revisions IDs been loaded
var $mRevisionsLoaded = false; // Have the revisions been loaded
var $mTextLoaded = 0; // How many text blobs have been loaded, 0, 1 or 2?
var $mCacheHit = false; // Was the diff fetched from cache?
@@ -51,49 +52,32 @@ class DifferenceEngine {
// readability and conserve space with many small diffs.
protected $mReducedLineNumbers = false;
+ // Link to action=markpatrolled
+ protected $mMarkPatrolledLink = null;
+
protected $unhide = false; # show rev_deleted content if allowed
/**#@-*/
/**
* Constructor
- * @param $titleObj Title object that the diff is associated with
+ * @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 $rcid Integer ??? FIXME (default 0)
* @param $refreshCache boolean If set, refreshes the diff cache
* @param $unhide boolean If set, allow viewing deleted revs
*/
- function __construct( $titleObj = null, $old = 0, $new = 0, $rcid = 0,
+ function __construct( $context = null, $old = 0, $new = 0, $rcid = 0,
$refreshCache = false, $unhide = false )
{
- if ( $titleObj ) {
- $this->mTitle = $titleObj;
- } else {
- global $wgTitle;
- $this->mTitle = $wgTitle; // @TODO: get rid of this
+ if ( $context instanceof IContextSource ) {
+ $this->setContext( $context );
}
+
wfDebug( "DifferenceEngine old '$old' new '$new' rcid '$rcid'\n" );
- if ( 'prev' === $new ) {
- # Show diff between revision $old and the previous one.
- # Get previous one from DB.
- $this->mNewid = intval( $old );
- $this->mOldid = $this->mTitle->getPreviousRevisionID( $this->mNewid );
- } elseif ( 'next' === $new ) {
- # Show diff between revision $old and the next one.
- # Get next one from DB.
- $this->mOldid = intval( $old );
- $this->mNewid = $this->mTitle->getNextRevisionID( $this->mOldid );
- if ( false === $this->mNewid ) {
- # if no result, NewId points to the newest old revision. The only newer
- # revision is cur, which is "0".
- $this->mNewid = 0;
- }
- } else {
- $this->mOldid = intval( $old );
- $this->mNewid = intval( $new );
- wfRunHooks( 'NewDifferenceEngine', array( &$titleObj, &$this->mOldid, &$this->mNewid, $old, $new ) );
- }
+ $this->mOldid = $old;
+ $this->mNewid = $new;
$this->mRcidMarkPatrolled = intval( $rcid ); # force it to be an integer
$this->mRefreshCache = $refreshCache;
$this->unhide = $unhide;
@@ -107,10 +91,14 @@ class DifferenceEngine {
}
/**
- * @return Title
+ * @return Language
*/
- function getTitle() {
- return $this->mTitle;
+ function getDiffLang() {
+ if ( $this->mDiffLang === null ) {
+ # Default language in which the diff text is written.
+ $this->mDiffLang = $this->getTitle()->getPageLanguage();
+ }
+ return $this->mDiffLang;
}
/**
@@ -124,6 +112,7 @@ class DifferenceEngine {
* @return int
*/
function getOldid() {
+ $this->loadRevisionIds();
return $this->mOldid;
}
@@ -131,6 +120,7 @@ class DifferenceEngine {
* @return Bool|int
*/
function getNewid() {
+ $this->loadRevisionIds();
return $this->mNewid;
}
@@ -142,8 +132,7 @@ class DifferenceEngine {
* @return mixed URL or false
*/
function deletedLink( $id ) {
- global $wgUser;
- if ( $wgUser->isAllowed( 'deletedhistory' ) ) {
+ if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
$dbr = wfGetDB( DB_SLAVE );
$row = $dbr->selectRow('archive', '*',
array( 'ar_rev_id' => $id ),
@@ -176,281 +165,214 @@ class DifferenceEngine {
}
function showDiffPage( $diffOnly = false ) {
- global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol;
wfProfileIn( __METHOD__ );
# Allow frames except in certain special cases
- $wgOut->allowClickjacking();
-
- # 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 ( $wgUseExternalEditor && $wgUser->getOption( 'externaldiff' ) ) {
- global $wgCanonicalServer, $wgScript, $wgLang;
- $wgOut->disable();
- header ( "Content-type: application/x-external-editor; charset=UTF-8" );
- $url1 = $this->mTitle->getCanonical( array(
- 'action' => 'raw',
- 'oldid' => $this->mOldid
- ) );
- $url2 = $this->mTitle->getCanonical( array(
- 'action' => 'raw',
- 'oldid' => $this->mNewid
- ) );
- $special = $wgLang->getNsText( NS_SPECIAL );
- $control = <<<CONTROL
- [Process]
- Type=Diff text
- Engine=MediaWiki
- Script={$wgCanonicalServer}{$wgScript}
- Special namespace={$special}
-
- [File]
- Extension=wiki
- URL=$url1
-
- [File 2]
- Extension=wiki
- URL=$url2
-CONTROL;
- echo( $control );
-
- wfProfileOut( __METHOD__ );
- return;
- }
+ $out = $this->getOutput();
+ $out->allowClickjacking();
+ $out->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleFlag( false );
if ( !$this->loadRevisionData() ) {
// Sounds like a deleted revision... Let's see what we can do.
- $t = $this->mTitle->getPrefixedText();
- $d = wfMsgExt( 'missingarticle-diff', array( 'escape' ),
+ $t = $this->getTitle()->getPrefixedText();
+ $d = $this->msg( 'missingarticle-diff',
$this->deletedIdMarker( $this->mOldid ),
- $this->deletedIdMarker( $this->mNewid ) );
- $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );
- $wgOut->addWikiMsg( 'missing-article', "<nowiki>$t</nowiki>", "<span class='plainlinks'>$d</span>" );
+ $this->deletedIdMarker( $this->mNewid ) )->escaped();
+ $out->setPageTitle( $this->msg( 'errorpagetitle' ) );
+ $out->addWikiMsg( 'missing-article', "<nowiki>$t</nowiki>", "<span class='plainlinks'>$d</span>" );
wfProfileOut( __METHOD__ );
return;
}
- wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
-
- if ( $this->mNewRev->isCurrent() ) {
- $wgOut->setArticleFlag( true );
+ $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 ) );
}
-
- # mOldid 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->mOldid === false ) {
- $this->showFirstRevision();
- $this->renderNewRevision(); // should we respect $diffOnly here or not?
+ if ( count( $permErrors ) ) {
wfProfileOut( __METHOD__ );
- return;
+ throw new PermissionsError( 'read', $permErrors );
}
- $oldTitle = $this->mOldPage->getPrefixedText();
- $newTitle = $this->mNewPage->getPrefixedText();
- if ( $oldTitle == $newTitle ) {
- $wgOut->setPageTitle( $newTitle );
- } else {
- $wgOut->setPageTitle( $oldTitle . ', ' . $newTitle );
- }
- if ( $this->mNewPage->equals( $this->mOldPage ) ) {
- $wgOut->setSubtitle( wfMsgExt( 'difference', array( 'parseinline' ) ) );
- } else {
- $wgOut->setSubtitle( wfMsgExt( 'difference-multipage', array( 'parseinline' ) ) );
- }
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
+ # 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' ) ) {
+ $urls = array(
+ 'File' => array( 'Extension' => 'wiki', 'URL' =>
+ # This should be mOldPage, but it may not be set, see below.
+ $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();
- if ( !$this->mOldPage->userCanRead() || !$this->mNewPage->userCanRead() ) {
- $wgOut->loginToUse();
- $wgOut->output();
- $wgOut->disable();
wfProfileOut( __METHOD__ );
return;
}
- $sk = $wgUser->getSkin();
- if ( method_exists( $sk, 'suppressQuickbar' ) ) {
- $sk->suppressQuickbar();
+ $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 );
- // Check if page is editable
- $editable = $this->mNewRev->getTitle()->userCan( 'edit' );
- if ( $editable && $this->mNewRev->isCurrent() && $wgUser->isAllowed( 'rollback' ) ) {
- $wgOut->preventClickjacking();
- $rollback = '&#160;&#160;&#160;' . $sk->generateRollback( $this->mNewRev );
+ # 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->mNewPage->getPrefixedText() );
+ $out->addSubtitle( $this->msg( 'difference' ) );
+ $samePage = true;
+ $oldHeader = '';
} else {
- $rollback = '';
- }
+ wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
- // Prepare a change patrol link, if applicable
- if ( $wgUseRCPatrol && $this->mTitle->userCan( 'patrol' ) ) {
- // If we've been given an explicit change identifier, use it; saves time
- if ( $this->mRcidMarkPatrolled ) {
- $rcid = $this->mRcidMarkPatrolled;
- $rc = RecentChange::newFromId( $rcid );
- // Already patrolled?
- $rcid = is_object( $rc ) && !$rc->getAttribute( 'rc_patrolled' ) ? $rcid : 0;
+ $sk = $this->getSkin();
+ if ( method_exists( $sk, 'suppressQuickbar' ) ) {
+ $sk->suppressQuickbar();
+ }
+
+ if ( $this->mNewPage->equals( $this->mOldPage ) ) {
+ $out->setPageTitle( $this->mNewPage->getPrefixedText() );
+ $out->addSubtitle( $this->msg( 'difference' ) );
+ $samePage = true;
} else {
- // Look for an unpatrolled change corresponding to this diff
- $db = wfGetDB( DB_SLAVE );
- $change = RecentChange::newFromConds(
- array(
- // Redundant user,timestamp condition so we can use the existing index
- 'rc_user_text' => $this->mNewRev->getRawUserText(),
- 'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ),
- 'rc_this_oldid' => $this->mNewid,
- 'rc_last_oldid' => $this->mOldid,
- 'rc_patrolled' => 0
- ),
- __METHOD__
- );
- if ( $change instanceof RecentChange ) {
- $rcid = $change->mAttribs['rc_id'];
- $this->mRcidMarkPatrolled = $rcid;
- } else {
- // None found
- $rcid = 0;
+ $out->setPageTitle( $this->mOldPage->getPrefixedText() . ', ' . $this->mNewPage->getPrefixedText() );
+ $out->addSubtitle( $this->msg( 'difference-multipage' ) );
+ $samePage = false;
+ }
+
+ if ( $samePage && $this->mNewPage->userCan( 'edit', $user ) ) {
+ if ( $this->mNewRev->isCurrent() && $this->mNewPage->userCan( 'rollback', $user ) ) {
+ $out->preventClickjacking();
+ $rollback = '&#160;&#160;&#160;' . Linker::generateRollback( $this->mNewRev );
+ }
+ 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();
}
}
- // Build the link
- if ( $rcid ) {
- $wgOut->preventClickjacking();
- $token = $wgUser->editToken( $rcid );
- $patrol = ' <span class="patrollink">[' . $sk->link(
- $this->mTitle,
- wfMsgHtml( 'markaspatrolleddiff' ),
- array(),
- array(
- 'action' => 'markpatrolled',
- 'rcid' => $rcid,
- 'token' => $token,
- ),
- array(
- 'known',
- 'noclasses'
- )
- ) . ']</span>';
+
+ # 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 {
- $patrol = '';
+ $prevlink = '&#160;';
}
- } else {
- $patrol = '';
- }
- # Carry over 'diffonly' param via navigation links
- if ( $diffOnly != $wgUser->getBoolOption( 'diffonly' ) ) {
- $query['diffonly'] = $diffOnly;
- }
+ if ( $this->mOldRev->isMinor() ) {
+ $oldminor = ChangesList::flag( 'minor' );
+ } else {
+ $oldminor = '';
+ }
- # Make "previous revision link"
- $query['diff'] = 'prev';
- $query['oldid'] = $this->mOldid;
- # Cascade unhide param in links for easy deletion browsing
- if ( $this->unhide ) {
- $query['unhide'] = 1;
- }
- if ( !$this->mOldRev->getPrevious() ) {
- $prevlink = '&#160;';
- } else {
- $prevlink = $sk->link(
- $this->mTitle,
- wfMsgHtml( 'previousdiff' ),
- array(
- 'id' => 'differences-prevlink'
- ),
- $query,
- array(
- 'known',
- 'noclasses'
- )
- );
+ $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"
- $query['diff'] = 'next';
- $query['oldid'] = $this->mNewid;
# Skip next link on the top revision
- if ( $this->mNewRev->isCurrent() ) {
- $nextlink = '&#160;';
- } else {
- $nextlink = $sk->link(
- $this->mTitle,
- wfMsgHtml( 'nextdiff' ),
- array(
- 'id' => 'differences-nextlink'
- ),
- $query,
- array(
- 'known',
- 'noclasses'
- )
+ 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 = '&#160;';
}
- $oldminor = '';
- $newminor = '';
-
- if ( $this->mOldRev->isMinor() ) {
- $oldminor = ChangesList::flag( 'minor' );
- }
if ( $this->mNewRev->isMinor() ) {
$newminor = ChangesList::flag( 'minor' );
+ } else {
+ $newminor = '';
}
# Handle RevisionDelete links...
- $ldel = $this->revisionDeleteLink( $this->mOldRev );
$rdel = $this->revisionDeleteLink( $this->mNewRev );
+ $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) . $undoLink;
- $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $this->mOldtitle . '</strong></div>' .
- '<div id="mw-diff-otitle2">' .
- $sk->revUserTools( $this->mOldRev, !$this->unhide ) . '</div>' .
- '<div id="mw-diff-otitle3">' . $oldminor .
- $sk->revComment( $this->mOldRev, !$diffOnly, !$this->unhide ) . $ldel . '</div>' .
- '<div id="mw-diff-otitle4">' . $prevlink . '</div>';
- $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $this->mNewtitle . '</strong></div>' .
- '<div id="mw-diff-ntitle2">' . $sk->revUserTools( $this->mNewRev, !$this->unhide ) .
+ $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 .
- $sk->revComment( $this->mNewRev, !$diffOnly, !$this->unhide ) . $rdel . '</div>' .
- '<div id="mw-diff-ntitle4">' . $nextlink . $patrol . '</div>';
+ Linker::revComment( $this->mNewRev, !$diffOnly, !$this->unhide ) . $rdel . '</div>' .
+ '<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>';
- # Check if this user can see the revisions
- $allowed = $this->mOldRev->userCan( Revision::DELETED_TEXT )
- && $this->mNewRev->userCan( Revision::DELETED_TEXT );
- # Check if one of the revisions is deleted/suppressed
- $deleted = $suppressed = false;
- 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
- }
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();
- $wgOut->addHTML( $this->addHeader( '', $oldHeader, $newHeader, $multi ) );
+ $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
- $wgOut->wrapWikiMsg( "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n",
+ $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->mTitle->getFullUrl( array(
- 'diff' => $this->mNewid,
- 'oldid' => $this->mOldid,
- 'unhide' => 1
- ) );
+ $link = $this->getTitle()->getFullUrl( $this->getRequest()->appendQueryValue( 'unhide', '1', true ) );
$msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff';
- $wgOut->wrapWikiMsg( "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n", array( $msg, $link ) );
+ $out->wrapWikiMsg( "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n", array( $msg, $link ) );
}
# Otherwise, output a regular diff...
} else {
@@ -458,7 +380,7 @@ CONTROL;
$notice = '';
if ( $deleted ) {
$msg = $suppressed ? 'rev-suppressed-diff-view' : 'rev-deleted-diff-view';
- $notice = "<div id='mw-$msg' class='mw-warning plainlinks'>\n" . wfMsgExt( $msg, 'parseinline' ) . "</div>\n";
+ $notice = "<div id='mw-$msg' class='mw-warning plainlinks'>\n" . $this->msg( $msg )->parse() . "</div>\n";
}
$this->showDiff( $oldHeader, $newHeader, $notice );
if ( !$diffOnly ) {
@@ -469,29 +391,79 @@ CONTROL;
}
/**
- * @param $rev Revision
+ * 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.
+ *
* @return String
*/
- protected function revisionDeleteLink( $rev ) {
- global $wgUser;
- $link = '';
- $canHide = $wgUser->isAllowed( 'deleterevision' );
- // Show del/undel link if:
- // (a) the user can delete revisions, or
- // (b) the user can view deleted revision *and* this one is deleted
- if ( $canHide || ( $rev->getVisibility() && $wgUser->isAllowed( 'deletedhistory' ) ) ) {
- $sk = $wgUser->getSkin();
- if ( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
- $link = $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
+ protected function markPatrolledLink() {
+ global $wgUseRCPatrol;
+
+ if ( $this->mMarkPatrolledLink === null ) {
+ // Prepare a change patrol link, if applicable
+ if ( $wgUseRCPatrol && $this->mNewPage->userCan( 'patrol', $this->getUser() ) ) {
+ // If we've been given an explicit change identifier, use it; saves time
+ if ( $this->mRcidMarkPatrolled ) {
+ $rcid = $this->mRcidMarkPatrolled;
+ $rc = RecentChange::newFromId( $rcid );
+ // Already patrolled?
+ $rcid = is_object( $rc ) && !$rc->getAttribute( 'rc_patrolled' ) ? $rcid : 0;
+ } else {
+ // Look for an unpatrolled change corresponding to this diff
+ $db = wfGetDB( DB_SLAVE );
+ $change = RecentChange::newFromConds(
+ array(
+ // Redundant user,timestamp condition so we can use the existing index
+ 'rc_user_text' => $this->mNewRev->getRawUserText(),
+ 'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ),
+ 'rc_this_oldid' => $this->mNewid,
+ 'rc_last_oldid' => $this->mOldid,
+ 'rc_patrolled' => 0
+ ),
+ __METHOD__
+ );
+ if ( $change instanceof RecentChange ) {
+ $rcid = $change->mAttribs['rc_id'];
+ $this->mRcidMarkPatrolled = $rcid;
+ } else {
+ // None found
+ $rcid = 0;
+ }
+ }
+ // Build the link
+ if ( $rcid ) {
+ $this->getOutput()->preventClickjacking();
+ $token = $this->getUser()->getEditToken( $rcid );
+ $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown(
+ $this->mNewPage,
+ $this->msg( 'markaspatrolleddiff' )->escaped(),
+ array(),
+ array(
+ 'action' => 'markpatrolled',
+ 'rcid' => $rcid,
+ 'token' => $token,
+ )
+ ) . ']</span>';
+ } else {
+ $this->mMarkPatrolledLink = '';
+ }
} else {
- $query = array(
- 'type' => 'revision',
- 'target' => $rev->mTitle->getPrefixedDbkey(),
- 'ids' => $rev->getId()
- );
- $link = $sk->revDeleteLink( $query,
- $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
+ $this->mMarkPatrolledLink = '';
}
+ }
+
+ return $this->mMarkPatrolledLink;
+ }
+
+ /**
+ * @param $rev Revision
+ * @return String
+ */
+ protected function revisionDeleteLink( $rev ) {
+ $link = Linker::getRevDeleteLink( $this->getUser(), $rev, $rev->getTitle() );
+ if ( $link !== '' ) {
$link = '&#160;&#160;&#160;' . $link . ' ';
}
return $link;
@@ -501,156 +473,81 @@ CONTROL;
* Show the new revision of the page.
*/
function renderNewRevision() {
- global $wgOut, $wgUser;
wfProfileIn( __METHOD__ );
+ $out = $this->getOutput();
+ $revHeader = $this->getRevisionHeader( $this->mNewRev );
# Add "current version as of X" title
- $wgOut->addHTML( "<hr class='diff-hr' />
- <h2 class='diff-currentversion-title'>{$this->mPagetitle}</h2>\n" );
+ $out->addHTML( "<hr class='diff-hr' />
+ <h2 class='diff-currentversion-title'>{$revHeader}</h2>\n" );
# Page content may be handled by a hooked call instead...
- if ( wfRunHooks( 'ArticleContentOnDiff', array( $this, $wgOut ) ) ) {
- # Use the current version parser cache if applicable
- $pCache = true;
- if ( !$this->mNewRev->isCurrent() ) {
- $oldEditSectionSetting = $wgOut->parserOptions()->setEditSection( false );
- $pCache = false;
- }
-
+ if ( wfRunHooks( 'ArticleContentOnDiff', array( $this, $out ) ) ) {
$this->loadNewText();
- $wgOut->setRevisionId( $this->mNewRev->getId() );
+ $out->setRevisionId( $this->mNewid );
+ $out->setRevisionTimestamp( $this->mNewRev->getTimestamp() );
+ $out->setArticleFlag( true );
- if ( $this->mTitle->isCssJsSubpage() || $this->mTitle->isCssOrJsPage() ) {
+ 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->mTitle, $wgOut ) ) ) {
+ if ( wfRunHooks( 'ShowRawCssJs', array( $this->mNewtext, $this->mNewPage, $out ) ) ) {
// Wrap the whole lot in a <pre> and don't parse
$m = array();
- preg_match( '!\.(css|js)$!u', $this->mTitle->getText(), $m );
- $wgOut->addHTML( "<pre class=\"mw-code mw-{$m[1]}\" dir=\"ltr\">\n" );
- $wgOut->addHTML( htmlspecialchars( $this->mNewtext ) );
- $wgOut->addHTML( "\n</pre>\n" );
+ preg_match( '!\.(css|js)$!u', $this->mNewPage->getText(), $m );
+ $out->addHTML( "<pre class=\"mw-code mw-{$m[1]}\" dir=\"ltr\">\n" );
+ $out->addHTML( htmlspecialchars( $this->mNewtext ) );
+ $out->addHTML( "\n</pre>\n" );
}
- } elseif ( $pCache ) {
- $article = new Article( $this->mTitle, 0 );
- $pOutput = ParserCache::singleton()->get( $article, $wgOut->parserOptions() );
- if( $pOutput ) {
- $wgOut->addParserOutput( $pOutput );
+ } elseif ( !wfRunHooks( 'ArticleViewCustom', array( $this->mNewtext, $this->mNewPage, $out ) ) ) {
+ // Handled by extension
+ } else {
+ // Normal page
+ if ( $this->getTitle()->equals( $this->mNewPage ) ) {
+ // If the Title stored in the context is the same as the one
+ // of the new revision, we can use its associated WikiPage
+ // object.
+ $wikiPage = $this->getWikiPage();
} else {
- $article->doViewParse();
+ // Otherwise we need to create our own WikiPage object
+ $wikiPage = WikiPage::factory( $this->mNewPage );
}
- } else {
- $wgOut->addWikiTextTidy( $this->mNewtext );
- }
- if ( !$this->mNewRev->isCurrent() ) {
- $wgOut->parserOptions()->setEditSection( $oldEditSectionSetting );
- }
- }
- # Add redundant patrol link on bottom...
- if ( $this->mRcidMarkPatrolled && $this->mTitle->quickUserCan( 'patrol' ) ) {
- $sk = $wgUser->getSkin();
- $token = $wgUser->editToken( $this->mRcidMarkPatrolled );
- $wgOut->preventClickjacking();
- $wgOut->addHTML(
- "<div class='patrollink'>[" . $sk->link(
- $this->mTitle,
- wfMsgHtml( 'markaspatrolleddiff' ),
- array(),
- array(
- 'action' => 'markpatrolled',
- 'rcid' => $this->mRcidMarkPatrolled,
- 'token' => $token,
- )
- ) . ']</div>'
- );
- }
+ $parserOptions = ParserOptions::newFromContext( $this->getContext() );
+ $parserOptions->enableLimitReport();
+ $parserOptions->setTidy( true );
- wfProfileOut( __METHOD__ );
- }
-
- /**
- * Show the first revision of an article. Uses normal diff headers in
- * contrast to normal "old revision" display style.
- */
- function showFirstRevision() {
- global $wgOut, $wgUser;
- wfProfileIn( __METHOD__ );
-
- # Get article text from the DB
- #
- if ( ! $this->loadNewText() ) {
- $t = $this->mTitle->getPrefixedText();
- $d = wfMsgExt( 'missingarticle-diff', array( 'escape' ),
- $this->deletedIdMarker( $this->mOldid ),
- $this->deletedIdMarker( $this->mNewid ) );
- $wgOut->setPagetitle( wfMsg( 'errorpagetitle' ) );
- $wgOut->addWikiMsg( 'missing-article', "<nowiki>$t</nowiki>", "<span class='plainlinks'>$d</span>" );
- wfProfileOut( __METHOD__ );
- return;
- }
- if ( $this->mNewRev->isCurrent() ) {
- $wgOut->setArticleFlag( true );
- }
-
- # Check if user is allowed to look at this page. If not, bail out.
- #
- if ( !$this->mTitle->userCanRead() ) {
- $wgOut->loginToUse();
- $wgOut->output();
- wfProfileOut( __METHOD__ );
- throw new MWException( "Permission Error: you do not have access to view this page" );
- }
+ if ( !$this->mNewRev->isCurrent() ) {
+ $parserOptions->setEditSection( false );
+ }
- # Prepare the header box
- #
- $sk = $wgUser->getSkin();
+ $parserOutput = $wikiPage->getParserOutput( $parserOptions, $this->mNewid );
- $next = $this->mTitle->getNextRevisionID( $this->mNewid );
- if ( !$next ) {
- $nextlink = '';
- } else {
- $nextlink = '<br />' . $sk->link(
- $this->mTitle,
- wfMsgHtml( 'nextdiff' ),
- array(
- 'id' => 'differences-nextlink'
- ),
- array(
- 'diff' => 'next',
- 'oldid' => $this->mNewid,
- ),
- array(
- 'known',
- 'noclasses'
- )
- );
+ # WikiPage::getParserOutput() should not return false, but just in case
+ if( $parserOutput ) {
+ $out->addParserOutput( $parserOutput );
+ }
+ }
}
- $header = "<div class=\"firstrevisionheader\" style=\"text-align: center\">" .
- $sk->revUserTools( $this->mNewRev ) . "<br />" . $sk->revComment( $this->mNewRev ) . $nextlink . "</div>\n";
-
- $wgOut->addHTML( $header );
-
- $wgOut->setSubtitle( wfMsgExt( 'difference', array( 'parseinline' ) ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
+ # Add redundant patrol link on bottom...
+ $out->addHTML( $this->markPatrolledLink() );
wfProfileOut( __METHOD__ );
}
/**
- * Get the diff text, send it to $wgOut
+ * Get the diff text, send it to the OutputPage object
* Returns false if the diff could not be generated, otherwise returns true
*
* @return bool
*/
function showDiff( $otitle, $ntitle, $notice = '' ) {
- global $wgOut;
$diff = $this->getDiff( $otitle, $ntitle, $notice );
if ( $diff === false ) {
- $wgOut->addWikiMsg( 'missing-article', "<nowiki>(fixme, bug)</nowiki>", '' );
+ $this->getOutput()->addWikiMsg( 'missing-article', "<nowiki>(fixme, bug)</nowiki>", '' );
return false;
} else {
$this->showDiffStyle();
- $wgOut->addHTML( $diff );
+ $this->getOutput()->addHTML( $diff );
return true;
}
}
@@ -659,8 +556,7 @@ CONTROL;
* Add style sheets and supporting JS for diff display.
*/
function showDiffStyle() {
- global $wgOut;
- $wgOut->addModuleStyles( 'mediawiki.action.history.diff' );
+ $this->getOutput()->addModuleStyles( 'mediawiki.action.history.diff' );
}
/**
@@ -694,16 +590,17 @@ CONTROL;
if ( !$this->loadRevisionData() ) {
wfProfileOut( __METHOD__ );
return false;
- } elseif ( $this->mOldRev && !$this->mOldRev->userCan( Revision::DELETED_TEXT ) ) {
+ } elseif ( $this->mOldRev && !$this->mOldRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
wfProfileOut( __METHOD__ );
return false;
- } elseif ( $this->mNewRev && !$this->mNewRev->userCan( Revision::DELETED_TEXT ) ) {
+ } elseif ( $this->mNewRev && !$this->mNewRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
wfProfileOut( __METHOD__ );
return false;
}
// Short-circuit
- if ( $this->mOldRev && $this->mNewRev
- && $this->mOldRev->getID() == $this->mNewRev->getID() )
+ // If mOldRev is false, it means that the
+ if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev
+ && $this->mOldRev->getID() == $this->mNewRev->getID() ) )
{
wfProfileOut( __METHOD__ );
return '';
@@ -878,9 +775,8 @@ CONTROL;
}
function localiseLineNumbersCb( $matches ) {
- global $wgLang;
if ( $matches[1] === '1' && $this->mReducedLineNumbers ) return '';
- return wfMsgExt( 'lineno', 'escape', $wgLang->formatNum( $matches[1] ) );
+ return $this->msg( 'lineno' )->numParams( $matches[1] )->escaped();
}
@@ -904,10 +800,10 @@ CONTROL;
$newRev = $this->mNewRev;
}
- $nEdits = $this->mTitle->countRevisionsBetween( $oldRev, $newRev );
+ $nEdits = $this->mNewPage->countRevisionsBetween( $oldRev, $newRev );
if ( $nEdits > 0 ) {
$limit = 100; // use diff-multi-manyusers if too many users
- $numUsers = $this->mTitle->countAuthorsBetween( $oldRev, $newRev, $limit );
+ $numUsers = $this->mNewPage->countAuthorsBetween( $oldRev, $newRev, $limit );
return self::intermediateEditsMsg( $nEdits, $numUsers, $limit );
}
return ''; // nothing
@@ -921,15 +817,63 @@ CONTROL;
* @return string
*/
public static function intermediateEditsMsg( $numEdits, $numUsers, $limit ) {
- global $wgLang;
if ( $numUsers > $limit ) {
$msg = 'diff-multi-manyusers';
$numUsers = $limit;
} else {
$msg = 'diff-multi';
}
- return wfMsgExt( $msg, 'parseinline',
- $wgLang->formatnum( $numEdits ), $wgLang->formatnum( $numUsers ) );
+ return wfMessage( $msg )->numParams( $numEdits, $numUsers )->parse();
+ }
+
+ /**
+ * Get a header for a specified revision.
+ *
+ * @param $rev Revision
+ * @param $complete String: '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 = '' ) {
+ $lang = $this->getLanguage();
+ $user = $this->getUser();
+ $revtimestamp = $rev->getTimestamp();
+ $timestamp = $lang->userTimeAndDate( $revtimestamp, $user );
+ $dateofrev = $lang->userDate( $revtimestamp, $user );
+ $timeofrev = $lang->userTime( $revtimestamp, $user );
+
+ $header = $this->msg(
+ $rev->isCurrent() ? 'currentrev-asof' : 'revisionasof',
+ $timestamp,
+ $dateofrev,
+ $timeofrev
+ )->escaped();
+
+ if ( $complete !== 'complete' ) {
+ return $header;
+ }
+
+ $title = $rev->getTitle();
+
+ $header = Linker::linkKnown( $title, $header, array(),
+ array( 'oldid' => $rev->getID() ) );
+
+ if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
+ $editQuery = array( 'action' => 'edit' );
+ if ( !$rev->isCurrent() ) {
+ $editQuery['oldid'] = $rev->getID();
+ }
+
+ $msg = $this->msg( $title->userCan( 'edit', $user ) ? 'editold' : 'viewsourceold' )->escaped();
+ $header .= ' (' . Linker::linkKnown( $title, $msg, array(), $editQuery ) . ')';
+ if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+ $header = Html::rawElement( 'span', array( 'class' => 'history-deleted' ), $header );
+ }
+ } else {
+ $header = Html::rawElement( 'span', array( 'class' => 'history-deleted' ), $header );
+ }
+
+ return $header;
}
/**
@@ -938,28 +882,36 @@ CONTROL;
* @return string
*/
function addHeader( $diff, $otitle, $ntitle, $multi = '', $notice = '' ) {
- // shared.css sets diff in interface language/dir,
- // but the actual content should be in the page language/dir
- $pageLang = $this->mTitle->getPageLanguage();
- $tableClass = 'diff diff-contentalign-' . htmlspecialchars( $pageLang->alignStart() );
+ // shared.css sets diff in interface language/dir, but the actual content
+ // is often in a different language, mostly the page content language/dir
+ $tableClass = 'diff diff-contentalign-' . htmlspecialchars( $this->getDiffLang()->alignStart() );
$header = "<table class='$tableClass'>";
- if ( $diff ) { // Safari/Chrome show broken output if cols not used
+
+ if ( !$diff && !$otitle ) {
$header .= "
- <col class='diff-marker' />
- <col class='diff-content' />
- <col class='diff-marker' />
- <col class='diff-content' />";
- $colspan = 2;
- $multiColspan = 4;
+ <tr valign='top'>
+ <td class='diff-ntitle'>{$ntitle}</td>
+ </tr>";
+ $multiColspan = 1;
} else {
- $colspan = 1;
- $multiColspan = 2;
+ if ( $diff ) { // Safari/Chrome show broken output if cols not used
+ $header .= "
+ <col class='diff-marker' />
+ <col class='diff-content' />
+ <col class='diff-marker' />
+ <col class='diff-content' />";
+ $colspan = 2;
+ $multiColspan = 4;
+ } else {
+ $colspan = 1;
+ $multiColspan = 2;
+ }
+ $header .= "
+ <tr valign='top'>
+ <td colspan='$colspan' class='diff-otitle'>{$otitle}</td>
+ <td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td>
+ </tr>";
}
- $header .= "
- <tr valign='top'>
- <td colspan='$colspan' class='diff-otitle'>{$otitle}</td>
- <td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td>
- </tr>";
if ( $multi != '' ) {
$header .= "<tr><td colspan='{$multiColspan}' align='center' class='diff-multi'>{$multi}</td></tr>";
@@ -982,6 +934,50 @@ CONTROL;
}
/**
+ * Set the language in which the diff text is written
+ * (Defaults to page content language).
+ * @since 1.19
+ */
+ function setTextLanguage( $lang ) {
+ $this->mDiffLang = wfGetLangObj( $lang );
+ }
+
+ /**
+ * Load revision IDs
+ */
+ private function loadRevisionIds() {
+ if ( $this->mRevisionsIdsLoaded ) {
+ return;
+ }
+
+ $this->mRevisionsIdsLoaded = true;
+
+ $old = $this->mOldid;
+ $new = $this->mNewid;
+
+ if ( $new === 'prev' ) {
+ # Show diff between revision $old and the previous one.
+ # Get previous one from DB.
+ $this->mNewid = intval( $old );
+ $this->mOldid = $this->getTitle()->getPreviousRevisionID( $this->mNewid );
+ } elseif ( $new === 'next' ) {
+ # Show diff between revision $old and the next one.
+ # Get next one from DB.
+ $this->mOldid = intval( $old );
+ $this->mNewid = $this->getTitle()->getNextRevisionID( $this->mOldid );
+ if ( $this->mNewid === false ) {
+ # if no result, NewId points to the newest old revision. The only newer
+ # revision is cur, which is "0".
+ $this->mNewid = 0;
+ }
+ } else {
+ $this->mOldid = intval( $old );
+ $this->mNewid = intval( $new );
+ wfRunHooks( 'NewDifferenceEngine', array( $this->getTitle(), &$this->mOldid, &$this->mNewid, $old, $new ) );
+ }
+ }
+
+ /**
* Load revision metadata for the specified articles. If newid is 0, then compare
* the old article in oldid to the current article; if oldid is 0, then
* compare the current article to the immediately previous one (ignoring the
@@ -994,72 +990,27 @@ CONTROL;
* @return bool
*/
function loadRevisionData() {
- global $wgLang, $wgUser;
if ( $this->mRevisionsLoaded ) {
return true;
- } else {
- // Whether it succeeds or fails, we don't want to try again
- $this->mRevisionsLoaded = true;
}
+ // Whether it succeeds or fails, we don't want to try again
+ $this->mRevisionsLoaded = true;
+
+ $this->loadRevisionIds();
+
// Load the new revision object
$this->mNewRev = $this->mNewid
? Revision::newFromId( $this->mNewid )
- : Revision::newFromTitle( $this->mTitle );
+ : Revision::newFromTitle( $this->getTitle() );
+
if ( !$this->mNewRev instanceof Revision ) {
return false;
}
// Update the new revision ID in case it was 0 (makes life easier doing UI stuff)
$this->mNewid = $this->mNewRev->getId();
-
- // Check if page is editable
- $editable = $this->mNewRev->getTitle()->userCan( 'edit' );
-
- // Set assorted variables
- $timestamp = $wgLang->timeanddate( $this->mNewRev->getTimestamp(), true );
- $dateofrev = $wgLang->date( $this->mNewRev->getTimestamp(), true );
- $timeofrev = $wgLang->time( $this->mNewRev->getTimestamp(), true );
$this->mNewPage = $this->mNewRev->getTitle();
- if ( $this->mNewRev->isCurrent() ) {
- $newLink = $this->mNewPage->escapeLocalUrl( array(
- 'oldid' => $this->mNewid
- ) );
- $this->mPagetitle = htmlspecialchars( wfMsg(
- 'currentrev-asof',
- $timestamp,
- $dateofrev,
- $timeofrev
- ) );
- $newEdit = $this->mNewPage->escapeLocalUrl( array(
- 'action' => 'edit'
- ) );
-
- $this->mNewtitle = "<a href='$newLink'>{$this->mPagetitle}</a>";
- $this->mNewtitle .= " (<a href='$newEdit'>" . wfMsgHtml( $editable ? 'editold' : 'viewsourceold' ) . "</a>)";
- } else {
- $newLink = $this->mNewPage->escapeLocalUrl( array(
- 'oldid' => $this->mNewid
- ) );
- $newEdit = $this->mNewPage->escapeLocalUrl( array(
- 'action' => 'edit',
- 'oldid' => $this->mNewid
- ) );
- $this->mPagetitle = htmlspecialchars( wfMsg(
- 'revisionasof',
- $timestamp,
- $dateofrev,
- $timeofrev
- ) );
-
- $this->mNewtitle = "<a href='$newLink'>{$this->mPagetitle}</a>";
- $this->mNewtitle .= " (<a href='$newEdit'>" . wfMsgHtml( $editable ? 'editold' : 'viewsourceold' ) . "</a>)";
- }
- if ( !$this->mNewRev->userCan( Revision::DELETED_TEXT ) ) {
- $this->mNewtitle = "<span class='history-deleted'>{$this->mPagetitle}</span>";
- } elseif ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
- $this->mNewtitle = "<span class='history-deleted'>{$this->mNewtitle}</span>";
- }
// Load the old revision object
$this->mOldRev = false;
@@ -1083,38 +1034,6 @@ CONTROL;
if ( $this->mOldRev ) {
$this->mOldPage = $this->mOldRev->getTitle();
-
- $t = $wgLang->timeanddate( $this->mOldRev->getTimestamp(), true );
- $dateofrev = $wgLang->date( $this->mOldRev->getTimestamp(), true );
- $timeofrev = $wgLang->time( $this->mOldRev->getTimestamp(), true );
- $oldLink = $this->mOldPage->escapeLocalUrl( array(
- 'oldid' => $this->mOldid
- ) );
- $oldEdit = $this->mOldPage->escapeLocalUrl( array(
- 'action' => 'edit',
- 'oldid' => $this->mOldid
- ) );
- $this->mOldPagetitle = htmlspecialchars( wfMsg( 'revisionasof', $t, $dateofrev, $timeofrev ) );
-
- $this->mOldtitle = "<a href='$oldLink'>{$this->mOldPagetitle}</a>"
- . " (<a href='$oldEdit'>" . wfMsgHtml( $editable ? 'editold' : 'viewsourceold' ) . "</a>)";
- // Add an "undo" link
- if ( $editable && !$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' => $wgUser->getSkin()->titleAttrib( 'undo' )
- ), wfMsg( 'editundo' ) );
- $this->mNewtitle .= ' (' . $undoLink . ')';
- }
-
- if ( !$this->mOldRev->userCan( Revision::DELETED_TEXT ) ) {
- $this->mOldtitle = '<span class="history-deleted">' . $this->mOldPagetitle . '</span>';
- } elseif ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) {
- $this->mOldtitle = '<span class="history-deleted">' . $this->mOldtitle . '</span>';
- }
}
return true;
diff --git a/includes/diff/WikiDiff3.php b/includes/diff/WikiDiff3.php
index 27d3d5b8..66727445 100644
--- a/includes/diff/WikiDiff3.php
+++ b/includes/diff/WikiDiff3.php
@@ -546,9 +546,12 @@ class WikiDiff3 {
}
// return the middle diagonal with maximal progress.
- return $max_progress[floor( $num_progress / 2 )];
+ return $max_progress[(int)floor( $num_progress / 2 )];
}
+ /**
+ * @return mixed
+ */
public function getLcsLength() {
if ( $this->heuristicUsed && !$this->lcsLengthCorrectedForHeuristic ) {
$this->lcsLengthCorrectedForHeuristic = true;