From 03dfe2c3be0f904061bf9bbd30122bfe599fd38f Mon Sep 17 00:00:00 2001 From: Jack Phoenix Date: Fri, 8 Jul 2016 19:46:20 +0300 Subject: [PATCH] Adding a bunch of hooks from wikiHow into DifferenceEngine, 2nd try Now with less fatals and more functionality! At least I sure hope so. Unlike the first time around (https://gerrit.wikimedia.org/r/206642), the DifferenceEngineRenderRevisionAddParserOutput and DifferenceEngineShowEmptyOldContent hooks now only affect things if a hooked function returns false. Since by default nothing is hooked into these brand new hooks, the behavior should stay exactly the same as before this patch and things like bug T139435 shouldn't happen anymore. These hooks allow things such as: * adding CSS(/JS) into the OutputPage when viewing diffs * adding extra HTML content (such as avatars) into diff views * hiding the bottom "mark as patrolled" link * altering the parser output that is used by DifferenceEngine * and more Example extension using these hooks is wikiHow's /extensions/wikihow/hooks/, specifically the file DiffHooks.php (but the hooks are setup in WikihowHooks.php). Live example of the DiffHooks stuff in action can be found at wikiHow.com, for example: http://www.wikihow.com/index.php?title=Set-Your-Homepage&diff=17112892&oldid=15888129 (user avatars, additional CSS, changes to the old/new revision header texts/links) Bug: T139526 Change-Id: I10293be4581140c3edf0e4b538b04b31cb6f5730 --- docs/hooks.txt | 79 ++++++++++++++++++++++++++++++ includes/diff/DifferenceEngine.php | 44 ++++++++++++++--- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/docs/hooks.txt b/docs/hooks.txt index d65fb7861f..78f9cdb192 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -1140,6 +1140,85 @@ $page: SpecialPage object for DeletedContributions $row: the DB row for this line &$classes: the classes to add to the surrounding
  • +'DifferenceEngineMarkPatrolledLink': Allows extensions to change the "mark as patrolled" link +which is shown both on the diff header as well as on the bottom of a page, usually +wrapped in a span element which has class="patrollink". +$differenceEngine: DifferenceEngine object +&$markAsPatrolledLink: The "mark as patrolled" link HTML (string) +$rcid: Recent change ID (rc_id) for this change (int) +$token: Patrol token; $rcid is used in generating this variable + +'DifferenceEngineMarkPatrolledRCID': Allows extensions to possibly change the rcid parameter. +For example the rcid might be set to zero due to the user being the same as the +performer of the change but an extension might still want to show it under certain +conditions. +&$rcid: rc_id (int) of the change or 0 +$differenceEngine: DifferenceEngine object +$change: RecentChange object +$user: User object representing the current user + +'DifferenceEngineNewHeader': Allows extensions to change the $newHeader variable, which +contains information about the new revision, such as the revision's author, whether +the revision was marked as a minor edit or not, etc. +$differenceEngine: DifferenceEngine object +&$newHeader: The string containing the various #mw-diff-otitle[1-5] divs, which +include things like revision author info, revision comment, RevisionDelete link and more +$formattedRevisionTools: Array containing revision tools, some of which may have +been injected with the DiffRevisionTools hook +$nextlink: String containing the link to the next revision (if any); also included in $newHeader +$rollback: Rollback link (string) to roll this revision back to the previous one, if any +$newminor: String indicating if the new revision was marked as a minor edit +$diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating +whether we should show just the diff; passed in as a query string parameter to the +various URLs constructed here (i.e. $nextlink) +$rdel: RevisionDelete link for the new revision, if the current user is allowed +to use the RevisionDelete feature +$unhide: Boolean parameter indicating whether to show RevisionDeleted revisions + +'DifferenceEngineOldHeader': Allows extensions to change the $oldHeader variable, which +contains information about the old revision, such as the revision's author, whether +the revision was marked as a minor edit or not, etc. +$differenceEngine: DifferenceEngine object +&$oldHeader: The string containing the various #mw-diff-otitle[1-5] divs, which +include things like revision author info, revision comment, RevisionDelete link and more +$prevlink: String containing the link to the previous revision (if any); also included in $oldHeader +$oldminor: String indicating if the old revision was marked as a minor edit +$diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating +whether we should show just the diff; passed in as a query string parameter to the +various URLs constructed here (i.e. $prevlink) +$ldel: RevisionDelete link for the old revision, if the current user is allowed +to use the RevisionDelete feature +$unhide: Boolean parameter indicating whether to show RevisionDeleted revisions + +'DifferenceEngineOldHeaderNoOldRev': Change the $oldHeader variable in cases when +there is no old revision +&$oldHeader: empty string by default + +'DifferenceEngineRenderRevisionAddParserOutput': Allows extensions to change the parser output. +Return false to not add parser output via OutputPage's addParserOutput method. +$differenceEngine: DifferenceEngine object +$out: OutputPage object +$parserOutput: ParserOutput object +$wikiPage: WikiPage object + +DifferenceEngineRenderRevisionShowFinalPatrolLink': An extension can hook into this hook +point and return false to not show the final "mark as patrolled" link on the bottom +of a page. +This hook has no arguments. + +'DifferenceEngineShowDiff': Allows extensions to affect the diff text which +eventually gets sent to the OutputPage object. +$differenceEngine: DifferenceEngine object + +'DifferenceEngineShowEmptyOldContent': Allows extensions to change the diff table +body (without header) in cases when there is no old revision or the old and new +revisions are identical. +$differenceEngine: DifferenceEngine object + +'DifferenceEngineShowDiffPage': Add additional output via the available OutputPage +object into the diff view +$out: OutputPage object + 'DiffRevisionTools': Override or extend the revision tools available from the diff view, i.e. undo, etc. $newRev: Revision object of the "new" revision diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php index 6bb88747de..84f2acabf0 100644 --- a/includes/diff/DifferenceEngine.php +++ b/includes/diff/DifferenceEngine.php @@ -236,12 +236,14 @@ class DifferenceEngine extends ContextSource { } public function showDiffPage( $diffOnly = false ) { - # Allow frames except in certain special cases $out = $this->getOutput(); $out->allowClickjacking(); $out->setRobotPolicy( 'noindex,nofollow' ); + // Allow extensions to add any extra output here + Hooks::run( 'DifferenceEngineShowDiffPage', [ $out ] ); + if ( !$this->loadRevisionData() ) { $this->showMissingRevision(); @@ -283,6 +285,8 @@ class DifferenceEngine extends ContextSource { $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) ); $samePage = true; $oldHeader = ''; + // Allow extensions to change the $oldHeader variable + Hooks::run( 'DifferenceEngineOldHeaderNoOldRev', [ &$oldHeader ] ); } else { Hooks::run( 'DiffViewHeader', [ $this, $this->mOldRev, $this->mNewRev ] ); @@ -352,6 +356,10 @@ class DifferenceEngine extends ContextSource { '
    ' . $oldChangeTags[0] . '
    ' . '
    ' . $prevlink . '
    '; + // Allow extensions to change the $oldHeader variable + Hooks::run( 'DifferenceEngineOldHeader', [ $this, &$oldHeader, $prevlink, $oldminor, + $diffOnly, $ldel, $this->unhide ] ); + if ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) { $deleted = true; // old revisions text is hidden if ( $this->mOldRev->isDeleted( Revision::DELETED_RESTRICTED ) ) { @@ -413,6 +421,10 @@ class DifferenceEngine extends ContextSource { '
    ' . $newChangeTags[0] . '
    ' . '
    ' . $nextlink . $this->markPatrolledLink() . '
    '; + // Allow extensions to change the $newHeader variable + Hooks::run( 'DifferenceEngineNewHeader', [ $this, &$newHeader, $formattedRevisionTools, + $nextlink, $rollback, $newminor, $diffOnly, $rdel, $this->unhide ] ); + if ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) { $deleted = true; // new revisions text is hidden if ( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) ) { @@ -485,6 +497,9 @@ class DifferenceEngine extends ContextSource { 'token' => $linkInfo['token'], ] ) . ']'; + // Allow extensions to change the markpatrolled link + Hooks::run( 'DifferenceEngineMarkPatrolledLink', [ $this, + &$this->mMarkPatrolledLink, $linkInfo['rcid'], $linkInfo['token'] ] ); } } return $this->mMarkPatrolledLink; @@ -528,6 +543,13 @@ class DifferenceEngine extends ContextSource { // If the user could patrol this it already would be patrolled $rcid = 0; } + + // Allow extensions to possibly change the rcid here + // For example the rcid might be set to zero due to the user + // being the same as the performer of the change but an extension + // might still want to show it under certain conditions + Hooks::run( 'DifferenceEngineMarkPatrolledRCID', [ &$rcid, $this, $change, $user ] ); + // Build the link if ( $rcid ) { $this->getOutput()->preventClickjacking(); @@ -615,15 +637,20 @@ class DifferenceEngine extends ContextSource { # WikiPage::getParserOutput() should not return false, but just in case if ( $parserOutput ) { - $out->addParserOutput( $parserOutput ); + // Allow extensions to change parser output here + if ( Hooks::run( 'DifferenceEngineRenderRevisionAddParserOutput', [ $this, $out, $parserOutput, $wikiPage ] ) ) { + $out->addParserOutput( $parserOutput ); + } } } } # @codingStandardsIgnoreEnd - # Add redundant patrol link on bottom... - $out->addHTML( $this->markPatrolledLink() ); - + // Allow extensions to optionally not show the final patrolled link + if ( Hooks::run( 'DifferenceEngineRenderRevisionShowFinalPatrolLink' ) ) { + # Add redundant patrol link on bottom... + $out->addHTML( $this->markPatrolledLink() ); + } } protected function getParserOutput( WikiPage $page, Revision $rev ) { @@ -649,6 +676,9 @@ class DifferenceEngine extends ContextSource { * @return bool */ public function showDiff( $otitle, $ntitle, $notice = '' ) { + // Allow extensions to affect the output here + Hooks::run( 'DifferenceEngineShowDiff', [ $this ] ); + $diff = $this->getDiff( $otitle, $ntitle, $notice ); if ( $diff === false ) { $this->showMissingRevision(); @@ -718,7 +748,9 @@ class DifferenceEngine extends ContextSource { if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev && $this->mOldRev->getId() == $this->mNewRev->getId() ) ) { - return ''; + if ( Hooks::run( 'DifferenceEngineShowEmptyOldContent', [ $this ] ) ) { + return ''; + } } // Cacheable? $key = false; -- 2.20.1