227 wfDebug(
"DifferenceEngine old '$old' new '$new' rcid '$rcid'\n" );
229 $this->mOldid = $old;
230 $this->mNewid = $new;
240 if ( $this->isSlotDiffRenderer ) {
241 throw new LogicException( __METHOD__ .
' called in slot diff renderer mode' );
244 if ( $this->slotDiffRenderers ===
null ) {
250 $this->slotDiffRenderers = array_map(
function ( $contents ) {
252 $content = $contents[
'new'] ?: $contents[
'old'];
266 $this->isSlotDiffRenderer =
true;
275 if ( $this->isContentOverridden ) {
277 SlotRecord::MAIN => [
286 $newSlots = $this->mNewRev->getRevisionRecord()->getSlots()->getSlots();
287 if ( $this->mOldRev ) {
288 $oldSlots = $this->mOldRev->getRevisionRecord()->getSlots()->getSlots();
296 $roles = array_merge( array_keys( $newSlots ), array_keys( $oldSlots ) );
299 foreach ( $roles as $role ) {
301 'old' => isset( $oldSlots[$role] ) ? $oldSlots[$role]->getContent() :
null,
302 'new' => isset( $newSlots[$role] ) ? $newSlots[$role]->getContent() :
null,
306 if ( isset( $slots[SlotRecord::MAIN] ) ) {
307 $slots = [ SlotRecord::MAIN => $slots[SlotRecord::MAIN] ] + $slots;
314 return parent::getTitle() ?: Title::makeTitle(
NS_SPECIAL,
'BadTitle/DifferenceEngine' );
324 $this->mReducedLineNumbers =
$value;
333 if ( $this->mDiffLang ===
null ) {
334 # Default language in which the diff text is written.
335 $this->mDiffLang = $this->
getTitle()->getPageLanguage();
380 return $this->mOldRev ? $this->mOldRev->getRevisionRecord() :
null;
389 return $this->mNewRev ? $this->mNewRev->getRevisionRecord() :
null;
401 if ( $this->
getUser()->isAllowed(
'deletedhistory' ) ) {
404 $row =
$dbr->selectRow(
406 array_merge( $arQuery[
'fields'], [
'ar_namespace',
'ar_title' ] ),
407 [
'ar_rev_id' => $id ],
414 $title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
416 return SpecialPage::getTitleFor(
'Undelete' )->getFullURL( [
417 'target' => $title->getPrefixedText(),
418 'timestamp' =>
$rev->getTimestamp()
436 return "[$link $id]";
446 if ( $this->mOldRev ===
null ||
447 ( $this->mOldRev && $this->mOldContent ===
null )
451 if ( $this->mNewRev ===
null ||
452 ( $this->mNewRev && $this->mNewContent ===
null )
457 $out->setPageTitle( $this->
msg(
'errorpagetitle' ) );
458 $msg = $this->
msg(
'difference-missing-revision' )
459 ->params( $this->
getLanguage()->listToText( $missing ) )
460 ->numParams( count( $missing ) )
462 $out->addHTML( $msg );
466 # Allow frames except in certain special cases
468 $out->allowClickjacking();
469 $out->setRobotPolicy(
'noindex,nofollow' );
472 Hooks::run(
'DifferenceEngineShowDiffPage', [
$out ] );
475 if ( Hooks::run(
'DifferenceEngineShowDiffPageMaybeShowMissingRevision', [ $this ] ) ) {
483 if ( $this->mNewPage ) {
484 $permErrors = $this->mNewPage->getUserPermissionsErrors(
'read', $user );
486 if ( $this->mOldPage ) {
488 $this->mOldPage->getUserPermissionsErrors(
'read', $user ) );
490 if ( count( $permErrors ) ) {
497 # Carry over 'diffonly' param via navigation links
498 if ( $diffOnly != $user->getBoolOption(
'diffonly' ) ) {
499 $query[
'diffonly'] = $diffOnly;
501 # Cascade unhide param in links for easy deletion browsing
502 if ( $this->unhide ) {
506 # Check if one of the revisions is deleted/suppressed
512 # mOldRev is false if the difference engine is called with a "vague" query for
513 # a diff between a version V and its previous version V' AND the version V
514 # is the first version of that article. In that case, V' does not exist.
515 if ( $this->mOldRev ===
false ) {
516 if ( $this->mNewPage ) {
517 $out->setPageTitle( $this->
msg(
'difference-title', $this->mNewPage->getPrefixedText() ) );
522 Hooks::run(
'DifferenceEngineOldHeaderNoOldRev', [ &$oldHeader ] );
524 Hooks::run(
'DiffViewHeader', [ $this, $this->mOldRev, $this->mNewRev ] );
526 if ( !$this->mOldPage || !$this->mNewPage ) {
529 } elseif ( $this->mNewPage->equals( $this->mOldPage ) ) {
530 $out->setPageTitle( $this->
msg(
'difference-title', $this->mNewPage->getPrefixedText() ) );
533 $out->setPageTitle( $this->
msg(
'difference-title-multipage',
534 $this->mOldPage->getPrefixedText(), $this->mNewPage->getPrefixedText() ) );
535 $out->addSubtitle( $this->
msg(
'difference-multipage' ) );
539 if ( $samePage && $this->mNewPage && $this->mNewPage->quickUserCan(
'edit', $user ) ) {
540 if ( $this->mNewRev->isCurrent() && $this->mNewPage->userCan(
'rollback', $user ) ) {
542 if ( $rollbackLink ) {
543 $out->preventClickjacking();
544 $rollback =
"\u{00A0}\u{00A0}\u{00A0}" . $rollbackLink;
551 $undoLink = Html::element(
'a', [
552 'href' => $this->mNewPage->getLocalURL( [
554 'undoafter' => $this->mOldid,
555 'undo' => $this->mNewid
559 $this->msg(
'editundo' )->text()
561 $revisionTools[
'mw-diff-undo'] = $undoLink;
565 # Make "previous revision link"
566 if ( $samePage && $this->mOldPage && $this->mOldRev->getPrevious() ) {
569 $this->
msg(
'previousdiff' )->escaped(),
570 [
'id' =>
'differences-prevlink' ],
571 [
'diff' =>
'prev',
'oldid' => $this->mOldid ] +
$query
574 $prevlink =
"\u{00A0}";
577 if ( $this->mOldRev->isMinor() ) {
585 $oldChangeTags = ChangeTags::formatSummaryRow( $this->mOldTags,
'diff', $this->
getContext() );
587 $oldHeader =
'<div id="mw-diff-otitle1"><strong>' . $oldRevisionHeader .
'</strong></div>' .
588 '<div id="mw-diff-otitle2">' .
590 '<div id="mw-diff-otitle3">' .
$oldminor .
592 '<div id="mw-diff-otitle5">' . $oldChangeTags[0] .
'</div>' .
593 '<div id="mw-diff-otitle4">' . $prevlink .
'</div>';
596 Hooks::run(
'DifferenceEngineOldHeader', [ $this, &$oldHeader, $prevlink,
$oldminor,
597 $diffOnly, $ldel, $this->unhide ] );
606 # Check if this user can see the revisions
612 $out->addJsConfigVars( [
613 'wgDiffOldId' => $this->mOldid,
614 'wgDiffNewId' => $this->mNewid,
617 # Make "next revision link"
618 # Skip next link on the top revision
619 if ( $samePage && $this->mNewPage && !$this->mNewRev->isCurrent() ) {
622 $this->
msg(
'nextdiff' )->escaped(),
623 [
'id' =>
'differences-nextlink' ],
624 [
'diff' =>
'next',
'oldid' => $this->mNewid ] +
$query
627 $nextlink =
"\u{00A0}";
630 if ( $this->mNewRev->isMinor() ) {
636 # Handle RevisionDelete links...
639 # Allow extensions to define their own revision tools
640 Hooks::run(
'DiffRevisionTools',
641 [ $this->mNewRev, &$revisionTools, $this->mOldRev, $user ] );
642 $formattedRevisionTools = [];
644 foreach ( $revisionTools as $key => $tool ) {
645 $toolClass = is_string( $key ) ? $key :
'mw-diff-tool';
646 $element = Html::rawElement(
648 [
'class' => $toolClass ],
649 $this->
msg(
'parentheses' )->rawParams( $tool )->escaped()
651 $formattedRevisionTools[] = $element;
654 ' ' . implode(
' ', $formattedRevisionTools );
655 $newChangeTags = ChangeTags::formatSummaryRow( $this->mNewTags,
'diff', $this->
getContext() );
657 $newHeader =
'<div id="mw-diff-ntitle1"><strong>' . $newRevisionHeader .
'</strong></div>' .
660 '<div id="mw-diff-ntitle3">' .
$newminor .
662 '<div id="mw-diff-ntitle5">' . $newChangeTags[0] .
'</div>' .
663 '<div id="mw-diff-ntitle4">' . $nextlink . $this->
markPatrolledLink() .
'</div>';
666 Hooks::run(
'DifferenceEngineNewHeader', [ $this, &$newHeader, $formattedRevisionTools,
676 # If the diff cannot be shown due to a deleted revision, then output
677 # the diff header and links to unhide (if available)...
678 if ( $deleted && ( !$this->unhide || !$allowed ) ) {
681 $out->addHTML( $this->
addHeader(
'', $oldHeader, $newHeader, $multi ) );
683 $msg =
$suppressed ?
'rev-suppressed-no-diff' :
'rev-deleted-no-diff';
684 # Give explanation for why revision is not visible
685 $out->wrapWikiMsg(
"<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n",
688 # Give explanation and add a link to view the diff...
691 $msg =
$suppressed ?
'rev-suppressed-unhide-diff' :
'rev-deleted-unhide-diff';
693 "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n",
697 # Otherwise, output a regular diff...
699 # Add deletion notice if the user is viewing deleted content
702 $msg =
$suppressed ?
'rev-suppressed-diff-view' :
'rev-deleted-diff-view';
703 $notice =
"<div id='mw-$msg' class='mw-warning plainlinks'>\n" .
704 $this->
msg( $msg )->parse() .
707 $this->
showDiff( $oldHeader, $newHeader, $notice );
724 if ( $this->mMarkPatrolledLink ===
null ) {
727 if ( !$linkInfo || !$this->mNewPage ) {
728 $this->mMarkPatrolledLink =
'';
730 $this->mMarkPatrolledLink =
' <span class="patrollink" data-mw="interface">[' .
733 $this->
msg(
'markaspatrolleddiff' )->escaped(),
736 'action' =>
'markpatrolled',
737 'rcid' => $linkInfo[
'rcid'],
741 Hooks::run(
'DifferenceEngineMarkPatrolledLink', [ $this,
742 &$this->mMarkPatrolledLink, $linkInfo[
'rcid'] ] );
763 $wgUseRCPatrol && $this->mNewPage && $this->mNewPage->quickUserCan(
'patrol', $user ) &&
766 RecentChange::isInRCLifespan( $this->mNewRev->getTimestamp(), 21600 )
770 $change = RecentChange::newFromConds(
772 'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ),
773 'rc_this_oldid' => $this->mNewid,
774 'rc_patrolled' => RecentChange::PRC_UNPATROLLED
779 if ( $change && !$change->getPerformer()->equals( $user ) ) {
780 $rcid = $change->getAttribute(
'rc_id' );
791 Hooks::run(
'DifferenceEngineMarkPatrolledRCID', [ &$rcid, $this, $change, $user ] );
795 $this->
getOutput()->preventClickjacking();
796 if ( $user->isAllowed(
'writeapi' ) ) {
797 $this->
getOutput()->addModules(
'mediawiki.page.patrol.ajax' );
817 if (
$link !==
'' ) {
818 $link =
"\u{00A0}\u{00A0}\u{00A0}" .
$link .
' ';
830 if ( $this->isContentOverridden ) {
834 throw new LogicException(
836 .
' is not supported after calling setContent(). Use setRevisions() instead.'
842 # Add "current version as of X" title
843 $out->addHTML(
"<hr class='diff-hr' id='mw-oldid' />
844 <h2 class='diff-currentversion-title'>{$revHeader}</h2>\n" );
845 # Page content may be handled by a hooked call instead...
846 if ( Hooks::run(
'ArticleContentOnDiff', [ $this,
$out ] ) ) {
848 if ( !$this->mNewPage ) {
855 $out->setRevisionId( $this->mNewid );
856 $out->setRevisionTimestamp( $this->mNewRev->getTimestamp() );
857 $out->setArticleFlag(
true );
859 if ( !Hooks::run(
'ArticleRevisionViewCustom',
860 [ $this->mNewRev->getRevisionRecord(), $this->mNewPage, $this->mOldid,
$out ] )
864 } elseif ( !Hooks::run(
'ArticleContentViewCustom',
865 [ $this->mNewContent, $this->mNewPage,
$out ],
'1.32' )
871 if ( $this->
getTitle()->equals( $this->mNewPage ) ) {
878 $wikiPage = WikiPage::factory( $this->mNewPage );
883 # WikiPage::getParserOutput() should not return false, but just in case
884 if ( $parserOutput ) {
886 if ( Hooks::run(
'DifferenceEngineRenderRevisionAddParserOutput',
887 [ $this,
$out, $parserOutput, $wikiPage ] )
889 $out->addParserOutput( $parserOutput, [
890 'enableSectionEditLinks' => $this->mNewRev->isCurrent()
891 && $this->mNewRev->getTitle()->quickUserCan(
'edit', $this->getUser() ),
899 if ( Hooks::run(
'DifferenceEngineRenderRevisionShowFinalPatrolLink' ) ) {
900 # Add redundant patrol link on bottom...
912 if ( !
$rev->getId() ) {
919 $parserOptions = $page->makeParserOptions( $this->
getContext() );
920 $parserOutput = $page->getParserOutput( $parserOptions,
$rev->getId() );
922 return $parserOutput;
935 public function showDiff( $otitle, $ntitle, $notice =
'' ) {
937 Hooks::run(
'DifferenceEngineShowDiff', [ $this ] );
939 $diff = $this->
getDiff( $otitle, $ntitle, $notice );
940 if ( $diff ===
false ) {
956 if ( !$this->isSlotDiffRenderer ) {
957 $this->
getOutput()->addModuleStyles(
'mediawiki.diff.styles' );
959 $slotDiffRenderer->addModules( $this->
getOutput() );
973 public function getDiff( $otitle, $ntitle, $notice =
'' ) {
975 if ( $body ===
false ) {
981 if ( $body ===
'' ) {
982 $notice .=
'<div class="mw-diff-empty">' .
983 $this->
msg(
'diff-empty' )->parse() .
987 return $this->
addHeader( $body, $otitle, $ntitle, $multi, $notice );
996 $this->mCacheHit =
true;
998 if ( !$this->isContentOverridden ) {
1001 } elseif ( $this->mOldRev &&
1005 } elseif ( $this->mNewRev &&
1011 if ( $this->mOldRev ===
false || ( $this->mOldRev && $this->mNewRev &&
1012 $this->mOldRev->getId() && $this->mOldRev->getId() == $this->mNewRev->getId() )
1014 if ( Hooks::run(
'DifferenceEngineShowEmptyOldContent', [ $this ] ) ) {
1022 $cache = ObjectCache::getMainWANInstance();
1023 if ( $this->mOldid && $this->mNewid ) {
1027 if ( $key ===
null ) {
1032 if ( !$this->mRefreshCache ) {
1033 $difftext =
$cache->get( $key );
1037 $difftext .=
"\n<!-- diff cache key $key -->\n";
1043 $this->mCacheHit =
false;
1055 $slotDiff = $slotDiffRenderer->getDiff( $slotContents[$role][
'old'],
1056 $slotContents[$role][
'new'] );
1057 if ( $slotDiff && $role !== SlotRecord::MAIN ) {
1062 $difftext .= $slotDiff;
1066 $diffEngine = $this;
1069 if ( !Hooks::run(
'AbortDiffCache', [ &$diffEngine ] ) ) {
1071 } elseif ( $key !==
false && $difftext !==
false ) {
1073 $cache->set( $key, $difftext, 7 * 86400 );
1078 if ( $difftext !==
false ) {
1093 if ( !isset( $diffRenderers[$role] ) ) {
1098 $slotDiff = $diffRenderers[$role]->getDiff( $slotContents[$role][
'old'],
1099 $slotContents[$role][
'new'] );
1104 if ( $role !== SlotRecord::MAIN ) {
1122 $columnCount = $this->mOldRev ? 4 : 2;
1124 return Html::rawElement(
'tr', [
'class' =>
'mw-diff-slot-header',
'lang' => $userLang ],
1125 Html::element(
'th', [
'colspan' => $columnCount ], $headerText ) );
1155 if ( !$this->mOldid || !$this->mNewid ) {
1156 throw new MWException(
'mOldid and mNewid must be set to get diff cache key.' );
1164 "old-{$this->mOldid}",
1165 "rev-{$this->mNewid}"
1168 if (
$engine ===
'wikidiff2' ) {
1169 $params[] = phpversion(
'wikidiff2' );
1170 $params[] = $this->
getConfig()->get(
'WikiDiff2MovedParagraphDetectionCutoff' );
1173 if ( !$this->isSlotDiffRenderer ) {
1175 $params = array_merge(
$params, $slotDiffRenderer->getExtraCacheKeys() );
1193 $this->mOldid = 123456789;
1194 $this->mNewid = 987654321;
1198 if ( $cacheString ) {
1199 return [ $cacheString ];
1212 if ( array_slice(
$params, 0, count( $standardParams ) ) === $standardParams ) {
1236 && $this->isSlotDiffRenderer
1242 throw new Exception( get_class( $this ) .
': could not maintain backwards compatibility. '
1243 .
'Please use a SlotDiffRenderer.' );
1245 return $slotDiffRenderer->getDiff( $old, $new ) . $this->
getDebugString();
1262 ->getSlotDiffRenderer( $this->
getContext() );
1266 throw new Exception(
'The slot diff renderer for text content should be a '
1267 .
'TextSlotDiffRenderer subclass' );
1269 return $slotDiffRenderer->getTextDiff( $otext, $ntext ) . $this->
getDebugString();
1283 wfDeprecated(
"\$wgExternalDiffEngine = '{$wgExternalDiffEngine}'",
'1.27' );
1286 wfDeprecated(
"\$wgExternalDiffEngine = '{$wgExternalDiffEngine}'",
'1.32' );
1290 wfWarn(
'$wgExternalDiffEngine is set to a non-string value, forcing it to false' );
1318 ->getSlotDiffRenderer( $this->
getContext() );
1322 throw new Exception(
'The slot diff renderer for text content should be a '
1323 .
'TextSlotDiffRenderer subclass' );
1325 return $slotDiffRenderer->getTextDiff( $otext, $ntext ) . $this->
getDebugString();
1338 if ( !$this->enableDebugComment ) {
1347 return "<!-- diff generator: " .
1348 implode(
" ", array_map(
"htmlspecialchars", $data ) ) .
1354 if (
$engine ===
'wikidiff2' ) {
1355 return $this->
debug(
'wikidiff2' );
1356 } elseif (
$engine ===
false ) {
1357 return $this->
debug(
'native PHP' );
1359 return $this->
debug(
"external $engine" );
1371 if ( $this->
getEngine() ===
'wikidiff2' &&
1372 version_compare( phpversion(
'wikidiff2' ),
'1.5.1',
'>=' )
1387 return preg_replace_callback(
1388 '/<!--LINE (\d+)-->/',
1389 [ $this,
'localiseLineNumbersCb' ],
1395 if (
$matches[1] ===
'1' && $this->mReducedLineNumbers ) {
1399 return $this->
msg(
'lineno' )->numParams(
$matches[1] )->escaped();
1409 return preg_replace_callback(
1410 '/class="mw-diff-movedpara-(left|right)"/',
1411 [ $this,
'addLocalisedTitleTooltipsCb' ],
1422 'diff-paragraph-moved-toold' :
1423 'diff-paragraph-moved-tonew';
1424 return $matches[0] .
' title="' . $this->
msg( $key )->escaped() .
'"';
1435 !$this->mOldRev || !$this->mNewRev
1436 || !$this->mOldPage || !$this->mNewPage
1437 || !$this->mOldPage->equals( $this->mNewPage )
1442 if ( $this->mOldRev->getTimestamp() > $this->mNewRev->getTimestamp() ) {
1452 $nEdits = $this->mNewPage->countRevisionsBetween( $oldRev,
$newRev, 1000 );
1453 if ( $nEdits > 0 && $nEdits <= 1000 ) {
1455 $users = $this->mNewPage->getAuthorsBetween( $oldRev,
$newRev, $limit );
1456 $numUsers = count( $users );
1478 if ( $numUsers === 0 ) {
1479 $msg =
'diff-multi-sameuser';
1480 } elseif ( $numUsers > $limit ) {
1481 $msg =
'diff-multi-manyusers';
1484 $msg =
'diff-multi-otherusers';
1487 return wfMessage( $msg )->numParams( $numEdits, $numUsers )->parse();
1502 $revtimestamp =
$rev->getTimestamp();
1503 $timestamp =
$lang->userTimeAndDate( $revtimestamp, $user );
1504 $dateofrev =
$lang->userDate( $revtimestamp, $user );
1505 $timeofrev =
$lang->userTime( $revtimestamp, $user );
1508 $rev->
isCurrent() ?
'currentrev-asof' :
'revisionasof',
1514 if ( $complete !==
'complete' ) {
1518 $title =
$rev->getTitle();
1521 [
'oldid' =>
$rev->getId() ] );
1524 $editQuery = [
'action' =>
'edit' ];
1525 if ( !
$rev->isCurrent() ) {
1526 $editQuery[
'oldid'] =
$rev->getId();
1529 $key = $title->quickUserCan(
'edit', $user ) ?
'editold' :
'viewsourceold';
1530 $msg = $this->
msg( $key )->escaped();
1531 $editLink = $this->
msg(
'parentheses' )->rawParams(
1533 $header .=
' ' . Html::rawElement(
1535 [
'class' =>
'mw-diff-edit' ],
1541 [
'class' =>
'history-deleted' ],
1546 $header = Html::rawElement(
'span', [
'class' =>
'history-deleted' ],
$header );
1564 public function addHeader( $diff, $otitle, $ntitle, $multi =
'', $notice =
'' ) {
1567 $header = Html::openElement(
'table', [
1568 'class' => [
'diff',
'diff-contentalign-' . $this->
getDiffLang()->alignStart() ],
1569 'data-mw' =>
'interface',
1571 $userLang = htmlspecialchars( $this->
getLanguage()->getHtmlCode() );
1573 if ( !$diff && !$otitle ) {
1575 <tr class=\"diff-title\" lang=\"{$userLang}\">
1576 <td class=\"diff-ntitle\">{$ntitle}</td>
1582 <col class=\"diff-marker\" />
1583 <col class=\"diff-content\" />
1584 <col class=\"diff-marker\" />
1585 <col class=\"diff-content\" />";
1592 if ( $otitle || $ntitle ) {
1594 <tr class=\"diff-title\" lang=\"{$userLang}\">
1595 <td colspan=\"$colspan\" class=\"diff-otitle\">{$otitle}</td>
1596 <td colspan=\"$colspan\" class=\"diff-ntitle\">{$ntitle}</td>
1601 if ( $multi !=
'' ) {
1602 $header .=
"<tr><td colspan=\"{$multiColspan}\" " .
1603 "class=\"diff-multi\" lang=\"{$userLang}\">{$multi}</td></tr>";
1605 if ( $notice !=
'' ) {
1606 $header .=
"<tr><td colspan=\"{$multiColspan}\" " .
1607 "class=\"diff-notice\" lang=\"{$userLang}\">{$notice}</td></tr>";
1610 return $header . $diff .
"</table>";
1621 $this->mOldContent = $oldContent;
1622 $this->mNewContent = $newContent;
1624 $this->mTextLoaded = 2;
1625 $this->mRevisionsLoaded =
true;
1626 $this->isContentOverridden =
true;
1627 $this->slotDiffRenderers =
null;
1638 if ( $oldRevision ) {
1639 $this->mOldRev =
new Revision( $oldRevision );
1640 $this->mOldid = $oldRevision->getId();
1641 $this->mOldPage = Title::newFromLinkTarget( $oldRevision->getPageAsLinkTarget() );
1644 $this->mOldContent = $oldRevision ? $oldRevision->getContent( SlotRecord::MAIN,
1645 RevisionRecord::FOR_THIS_USER, $this->
getUser() ) :
null;
1647 $this->mOldPage =
null;
1648 $this->mOldRev = $this->mOldid =
false;
1650 $this->mNewRev =
new Revision( $newRevision );
1651 $this->mNewid = $newRevision->getId();
1652 $this->mNewPage = Title::newFromLinkTarget( $newRevision->getPageAsLinkTarget() );
1653 $this->mNewContent = $newRevision->getContent( SlotRecord::MAIN,
1654 RevisionRecord::FOR_THIS_USER, $this->
getUser() );
1656 $this->mRevisionsIdsLoaded = $this->mRevisionsLoaded =
true;
1657 $this->mTextLoaded = !!$oldRevision + 1;
1658 $this->isContentOverridden =
false;
1659 $this->slotDiffRenderers =
null;
1670 wfDeprecated( __METHOD__ .
' with other type than Language for $lang',
'1.32' );
1687 if ( $new ===
'prev' ) {
1689 $newid = intval( $old );
1690 $oldid = $this->
getTitle()->getPreviousRevisionID( $newid );
1691 } elseif ( $new ===
'next' ) {
1693 $oldid = intval( $old );
1694 $newid = $this->
getTitle()->getNextRevisionID( $oldid );
1696 $oldid = intval( $old );
1697 $newid = intval( $new );
1700 return [ $oldid, $newid ];
1707 if ( $this->mRevisionsIdsLoaded ) {
1711 $this->mRevisionsIdsLoaded =
true;
1717 if ( $new ===
'next' && $this->mNewid ===
false ) {
1718 # if no result, NewId points to the newest old revision. The only newer
1719 # revision is cur, which is "0".
1724 'NewDifferenceEngine',
1725 [ $this->
getTitle(), &$this->mOldid, &$this->mNewid, $old, $new ]
1743 if ( $this->mRevisionsLoaded ) {
1744 return $this->isContentOverridden || $this->mNewRev && !is_null( $this->mOldRev );
1748 $this->mRevisionsLoaded =
true;
1753 if ( $this->mNewid ) {
1759 Revision::READ_NORMAL
1763 if ( !$this->mNewRev instanceof
Revision ) {
1768 $this->mNewid = $this->mNewRev->getId();
1769 if ( $this->mNewid ) {
1770 $this->mNewPage = $this->mNewRev->getTitle();
1772 $this->mNewPage =
null;
1776 $this->mOldRev =
false;
1777 if ( $this->mOldid ) {
1779 } elseif ( $this->mOldid === 0 ) {
1780 $rev = $this->mNewRev->getPrevious();
1782 $this->mOldid =
$rev->getId();
1783 $this->mOldRev =
$rev;
1786 $this->mOldid =
false;
1787 $this->mOldRev =
false;
1791 if ( is_null( $this->mOldRev ) ) {
1795 if ( $this->mOldRev && $this->mOldRev->getId() ) {
1796 $this->mOldPage = $this->mOldRev->getTitle();
1798 $this->mOldPage =
null;
1803 if ( $this->mOldid !==
false ) {
1804 $this->mOldTags =
$dbr->selectField(
1807 [
'ts_rev_id' => $this->mOldid ],
1811 $this->mOldTags =
false;
1813 $this->mNewTags =
$dbr->selectField(
1816 [
'ts_rev_id' => $this->mNewid ],
1832 if ( $this->mTextLoaded == 2 ) {
1834 && $this->mNewContent;
1838 $this->mTextLoaded = 2;
1844 if ( $this->mOldRev ) {
1846 if ( $this->mOldContent ===
null ) {
1852 Hooks::run(
'DifferenceEngineLoadTextAfterNewContentIsLoaded', [ $this ] );
1853 if ( $this->mNewContent ===
null ) {
1866 if ( $this->mTextLoaded >= 1 ) {
1870 $this->mTextLoaded = 1;
1878 Hooks::run(
'DifferenceEngineAfterLoadNewText', [ $this ] );
$wgShowHostnames
Expose backend server host names through the API and various HTML comments.
$wgUseRCPatrol
Use RC Patrolling to check for vandalism (from recent changes and watchlists) New pages and new files...
$wgExternalDiffEngine
Name of the external diff engine to use.
deprecatePublicProperty( $property, $version, $class=null, $component=null)
Mark a property as deprecated.
trait DeprecationHelper
Use this trait in classes which have properties for which public access is deprecated.
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
wfIncrStats( $key, $count=1)
Increment a statistics counter.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfMergeErrorArrays(... $args)
Merge arrays in the style of getUserPermissionsErrors, with duplicate removal e.g.
wfHostname()
Fetch server name for use in error reporting etc.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
static flag( $flag, IContextSource $context=null)
Make an "<abbr>" element for a given change flag.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
msg( $key)
Get a Message object with context set Parameters are the same as wfMessage()
getWikiPage()
Get the WikiPage object.
getContext()
Get the base IContextSource object.
setContext(IContextSource $context)
B/C adapter for turning a DifferenceEngine into a SlotDiffRenderer.
DifferenceEngine is responsible for rendering the difference between two revisions as HTML.
getDiffBodyCacheKey()
Returns the cache key for diff body text or content.
bool $unhide
Show rev_deleted content if allowed.
bool $isContentOverridden
Was the content overridden via setContent()? If the content was overridden, most internal state (e....
Revision null $mNewRev
New revision (right pane).
getExtraCacheKeys()
Implements DifferenceEngineSlotDiffRenderer::getExtraCacheKeys().
markAsSlotDiffRenderer()
Mark this DifferenceEngine as a slot renderer (as opposed to a page renderer).
getSlotHeader( $headerText)
Get a slot header for inclusion in a diff body (as a table row).
bool $mRevisionsIdsLoaded
Have the revisions IDs been loaded.
string[] null $mOldTags
Change tags of $mOldRev or null if it does not exist / is not saved.
revisionDeleteLink( $rev)
int $mTextLoaded
How many text blobs have been loaded, 0, 1 or 2?
deletedIdMarker( $id)
Build a wikitext link toward a deleted revision, if viewable.
getDiffBodyForRole( $role)
Get the diff table body for one slot, without header.
getOldid()
Get the ID of old revision (left pane) of the diff.
bool $isSlotDiffRenderer
Temporary hack for B/C while slot diff related methods of DifferenceEngine are being deprecated.
generateTextDiffBody( $otext, $ntext)
Generate a diff, no caching.
loadNewText()
Load the text of the new revision, not the old one.
showDiffPage( $diffOnly=false)
loadText()
Load the text of the revisions, as well as revision data.
int string false null $mNewid
Revision ID for the new revision.
const DIFF_VERSION
Constant to indicate diff cache compatibility.
mapDiffPrevNext( $old, $new)
Maps a revision pair definition as accepted by DifferenceEngine constructor to a pair of actual integ...
Content null $mNewContent
getParserOutput(WikiPage $page, Revision $rev)
getDiffBody()
Get the diff table body, without header.
string[] null $mNewTags
Change tags of $mNewRev or null if it does not exist / is not saved.
loadRevisionData()
Load revision metadata for the specified revisions.
static getEngine()
Process $wgExternalDiffEngine and get a sane, usable engine.
loadRevisionIds()
Load revision IDs.
bool $mRevisionsLoaded
Have the revisions been loaded.
Content null $mOldContent
getNewRevision()
Get the right side of the diff.
showDiff( $otitle, $ntitle, $notice='')
Get the diff text, send it to the OutputPage object Returns false if the diff could not be generated,...
localiseLineNumbers( $text)
Replace line numbers with the text in the user's language.
getSlotContents()
Get the old and new content objects for all slots.
string $mMarkPatrolledLink
Link to action=markpatrolled.
localiseLineNumbersCb( $matches)
setRevisions(RevisionRecord $oldRevision=null, RevisionRecord $newRevision)
Use specified text instead of loading from the database.
deletedLink( $id)
Look up a special:Undelete link to the given deleted revision id, as a workaround for being unable to...
bool $mReducedLineNumbers
If true, line X is not displayed when X is 1, for example to increase readability and conserve space ...
getRevisionHeader(Revision $rev, $complete='')
Get a header for a specified revision.
__construct( $context=null, $old=0, $new=0, $rcid=0, $refreshCache=false, $unhide=false)
#-
Title null $mNewPage
Title of $mNewRev or null if the new revision does not exist or does not belong to a page.
bool $mCacheHit
Was the diff fetched from cache?
getMultiNotice()
If there are revisions between the ones being compared, return a note saying so.
int false null $mOldid
Revision ID for the old revision.
Revision null false $mOldRev
Old revision (left pane).
debug( $generator="internal")
Generate a debug comment indicating diff generating time, server node, and generator backend.
addHeader( $diff, $otitle, $ntitle, $multi='', $notice='')
Add the header to a diff body.
bool $mRefreshCache
Refresh the diff cache.
getDiffBodyCacheKeyParams()
Get the cache key parameters.
getDiff( $otitle, $ntitle, $notice='')
Get complete diff table, including header.
getNewid()
Get the ID of new revision (right pane) of the diff.
renderNewRevision()
Show the new revision of the page.
addLocalisedTitleTooltips( $text)
Add title attributes for tooltips on moved paragraph indicators.
setContent(Content $oldContent, Content $newContent)
Use specified text instead of loading from the database.
generateContentDiffBody(Content $old, Content $new)
Generate a diff, no caching.
localiseDiff( $text)
Localise diff output.
getMarkPatrolledLinkInfo()
Returns an array of meta data needed to build a "mark as patrolled" link and adds the mediawiki....
setReducedLineNumbers( $value=true)
Set reduced line numbers mode.
textDiff( $otext, $ntext)
Generates diff, to be wrapped internally in a logging/instrumentation.
static intermediateEditsMsg( $numEdits, $numUsers, $limit)
Get a notice about how many intermediate edits and users there are.
setTextLanguage( $lang)
Set the language in which the diff text is written.
Title null $mOldPage
Title of $mOldRev or null if the old revision does not exist or does not belong to a page.
SlotDiffRenderer[] $slotDiffRenderers
DifferenceEngine classes for the slots, keyed by role name.
getDiffLang()
Get the language of the difference engine, defaults to page content language.
showDiffStyle()
Add style sheets for diff display.
addLocalisedTitleTooltipsCb(array $matches)
markPatrolledLink()
Build a link to mark a change as patrolled.
$enableDebugComment
Set this to true to add debug info to the HTML output.
getOldRevision()
Get the left side of the diff.
Internationalisation code.
static generateRollback( $rev, IContextSource $context=null, $options=[ 'verify'])
Generate a rollback link for a given revision.
static titleAttrib( $name, $options=null, array $msgParams=[])
Given the id of an interface element, constructs the appropriate title attribute from the system mess...
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
static revComment(Revision $rev, $local=false, $isPublic=false)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
static revUserTools( $rev, $isPublic=false)
Generate a user tool link cluster if the current user is allowed to view it.
static getRevDeleteLink(User $user, Revision $rev, Title $title)
Get a revision-deletion link, or disabled link, or nothing, depending on user permissions & the setti...
Show an error when a user tries to do something they do not have the necessary permissions for.
static getArchiveQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new archived revision objec...
static newFromArchiveRow( $row, $overrides=[])
Make a fake revision object from an archive table row.
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Renders a diff for a single slot (that is, a diff between two content objects).
Renders a slot diff by doing a text diff on the native representation.
Represents a title within MediaWiki.
Class representing a MediaWiki article and history.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify as strings Extensions should add to this list prev or next $refreshCache
also included in $newHeader $rollback
passed in as a query string parameter to the various URLs constructed here(i.e. $nextlink) $rdel also included in $oldHeader $oldminor
returning false will NOT prevent logging a wrapping ErrorException $suppressed
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "<div ...>$1</div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
usually copyright or history_copyright This message must be in HTML not wikitext & $link
the value to return A Title object or null for latest all implement SearchIndexField $engine
also included in $newHeader if any $newminor
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Base interface for content objects.
getContentHandler()
Convenience method that returns the ContentHandler singleton for handling the content model that this...
Interface for objects which can provide a MediaWiki context on request.
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
if(!isset( $args[0])) $lang