Merge "Move Reference Previews user preference into the Cite extension"

This commit is contained in:
jenkins-bot 2024-09-23 10:47:16 +00:00 committed by Gerrit Code Review
commit 3beada9643
11 changed files with 167 additions and 20 deletions

View file

@ -26,6 +26,7 @@
"Hooks": {
"APIQuerySiteInfoGeneralInfo": "main",
"ContentHandlerDefaultModelFor": "main",
"GetPreferences": "main",
"ParserAfterParse": "parser",
"ParserClearState": "parser",
"ParserCloned": "parser",
@ -33,13 +34,15 @@
"EditPage::showEditForm:initial": "main",
"MakeGlobalVariablesScript": "main",
"ResourceLoaderGetConfigVars": "main",
"ResourceLoaderRegisterModules": "main"
"ResourceLoaderRegisterModules": "main",
"UserGetDefaultOptions": "main"
},
"HookHandlers": {
"main": {
"class": "Cite\\Hooks\\CiteHooks",
"services": [
"Cite.ReferencePreviewsContext",
"Cite.GadgetsIntegration",
"UserOptionsLookup"
]
},

View file

@ -79,5 +79,9 @@
"cite-wikieditor-help-content-reference-example-ref-reuse": "<ref name=\"$1\" />",
"cite-wikieditor-help-content-reference-example-ref-extends": "<ref extends=\"$1\">$2</ref>",
"cite-wikieditor-help-content-reference-example-ref-result": "[$1]",
"cite-wikieditor-help-content-reference-example-reflist": "<references />"
"cite-wikieditor-help-content-reference-example-reflist": "<references />",
"popups-prefs-navpopups-gadget-conflict-info": "You have the [[$1|Navigation popups]] gadget enabled, so you won't see previews provided by this feature. Depending on your wiki, the gadget may have a slightly different name. If you continue to experience issues, please review your gadgets and user scripts, including global ones.",
"popups-prefs-reftooltips-and-navpopups-gadget-conflict-info": "You have the [[$1|Navigation popups]] and [[$1|Reference Tooltips]] gadgets enabled, so you won't see previews provided by this feature. Depending on your wiki, the gadgets may have slightly different names. If you continue to experience issues, please review your gadgets and user scripts, including global ones.",
"popups-prefs-reftooltips-gadget-conflict-info": "You have the [[$1|Reference Tooltips]] gadget enabled, so you won't see reference previews but will still see page previews. Depending on your wiki, the gadget may have a slightly different name. If you continue to experience issues, please review your gadgets and user scripts, including global ones.",
"popups-refpreview-user-preference-label": "Enable reference previews (get quick previews of a reference while reading a page)"
}

View file

@ -84,5 +84,9 @@
"cite-wikieditor-help-content-reference-example-ref-reuse": "{{ignored}}",
"cite-wikieditor-help-content-reference-example-ref-extends": "{{ignored}}",
"cite-wikieditor-help-content-reference-example-ref-result": "{{ignored}}",
"cite-wikieditor-help-content-reference-example-reflist": "{{ignored}}"
"cite-wikieditor-help-content-reference-example-reflist": "{{ignored}}",
"popups-prefs-navpopups-gadget-conflict-info": "Help message telling to disable the \"Navigation popups\" gadget in order to allow page and reference previews. The word \"Gadgets\" should be based on {{msg-mw|prefs-gadgets}}.\n\nParameters:\n* $1 Link to the Gadgets tab in the user's preferences",
"popups-prefs-reftooltips-gadget-conflict-info": "Help message telling to disable the \"Reference Tooltips\" gadget in order to allow reference previews. The word \"Gadgets\" should be based on {{msg-mw|prefs-gadgets}}.\n\nParameters:\n* $1 Link to the Gadgets tab in the user's preferences",
"popups-prefs-reftooltips-and-navpopups-gadget-conflict-info": "Help message telling to disable the \"Navigation popups\" and \"Reference Tooltips\" gadgets in order to allow page and reference previews. The word \"Gadgets\" should be based on {{msg-mw|prefs-gadgets}}.\n\nParameters:\n* $1 Link to the Gadgets tab in the user's preferences",
"popups-refpreview-user-preference-label": "Label for the user option to enable or disable reference preview popups"
}

View file

@ -8,6 +8,7 @@ namespace Cite\Hooks;
use ApiQuerySiteinfo;
use Cite\ReferencePreviews\ReferencePreviewsContext;
use Cite\ReferencePreviews\ReferencePreviewsGadgetsIntegration;
use ExtensionRegistry;
use MediaWiki\Api\Hook\APIQuerySiteInfoGeneralInfoHook;
use MediaWiki\Config\Config;
@ -21,6 +22,7 @@ use MediaWiki\ResourceLoader\ResourceLoader;
use MediaWiki\Revision\Hook\ContentHandlerDefaultModelForHook;
use MediaWiki\Title\Title;
use MediaWiki\User\Options\UserOptionsLookup;
use MediaWiki\User\User;
/**
* @license GPL-2.0-or-later
@ -36,13 +38,16 @@ class CiteHooks implements
{
private ReferencePreviewsContext $referencePreviewsContext;
private ReferencePreviewsGadgetsIntegration $gadgetsIntegration;
private UserOptionsLookup $userOptionsLookup;
public function __construct(
ReferencePreviewsContext $referencePreviewsContext,
ReferencePreviewsGadgetsIntegration $gadgetsIntegration,
UserOptionsLookup $userOptionsLookup
) {
$this->referencePreviewsContext = $referencePreviewsContext;
$this->gadgetsIntegration = $gadgetsIntegration;
$this->userOptionsLookup = $userOptionsLookup;
}
@ -172,4 +177,52 @@ class CiteHooks implements
}
}
/**
* Add options to user Preferences page
*
* @param User $user User whose preferences are being modified
* @param array[] &$prefs Preferences description array, to be fed to a HTMLForm object
*/
public function onGetPreferences( $user, &$prefs ) {
$option = [
'type' => 'toggle',
'label-message' => 'popups-refpreview-user-preference-label',
// FIXME: This message is unnecessary and unactionable since we already
// detect specific gadget conflicts.
'help-message' => 'popups-prefs-conflicting-gadgets-info',
// FIXME: copied from Popups
'section' => 'rendering/reading',
];
$isNavPopupsGadgetEnabled = $this->gadgetsIntegration->isNavPopupsGadgetEnabled( $user );
$isRefTooltipsGadgetEnabled = $this->gadgetsIntegration->isRefTooltipsGadgetEnabled( $user );
if ( $isNavPopupsGadgetEnabled && $isRefTooltipsGadgetEnabled ) {
$option[ 'disabled' ] = true;
$option[ 'help-message' ] = [ 'popups-prefs-reftooltips-and-navpopups-gadget-conflict-info',
'Special:Preferences#mw-prefsection-gadgets' ];
} elseif ( $isNavPopupsGadgetEnabled ) {
$option[ 'disabled' ] = true;
$option[ 'help-message' ] = [ 'popups-prefs-navpopups-gadget-conflict-info',
'Special:Preferences#mw-prefsection-gadgets' ];
} elseif ( $isRefTooltipsGadgetEnabled ) {
$option[ 'disabled' ] = true;
$option[ 'help-message' ] = [ 'popups-prefs-reftooltips-gadget-conflict-info',
'Special:Preferences#mw-prefsection-gadgets' ];
}
$prefs += [
ReferencePreviewsContext::REFERENCE_PREVIEWS_PREFERENCE_NAME => $option
];
}
/**
* See https://www.mediawiki.org/wiki/Manual:Hooks/UserGetDefaultOptions
* @param array &$defaultOptions Array of preference keys and their default values.
*/
public static function onUserGetDefaultOptions( &$defaultOptions ) {
// FIXME: Move to extension.json once migration is complete. See T363162
if ( !isset( $defaultOptions[ ReferencePreviewsContext::REFERENCE_PREVIEWS_PREFERENCE_NAME ] ) ) {
$defaultOptions[ ReferencePreviewsContext::REFERENCE_PREVIEWS_PREFERENCE_NAME ] = '1';
}
}
}

View file

@ -18,12 +18,12 @@ class ReferencePreviewsContext {
public function __construct(
Config $config,
ReferencePreviewsGadgetsIntegration $gadgetsIntegration,
UserOptionsLookup $userOptionsLookup
) {
$this->gadgetsIntegration = new ReferencePreviewsGadgetsIntegration( $config );
$this->userOptionsLookup = $userOptionsLookup;
$this->config = $config;
$this->gadgetsIntegration = $gadgetsIntegration;
$this->userOptionsLookup = $userOptionsLookup;
}
/**

View file

@ -5,10 +5,8 @@ namespace Cite\ReferencePreviews;
use InvalidArgumentException;
use MediaWiki\Config\Config;
use MediaWiki\Extension\Gadgets\GadgetRepo;
use MediaWiki\MediaWikiServices;
use MediaWiki\User\User;
use MediaWiki\User\UserIdentity;
use Wikimedia\Services\NoSuchServiceException;
/**
* Gadgets integration
@ -25,17 +23,13 @@ class ReferencePreviewsGadgetsIntegration {
private string $navPopupsGadgetName;
private string $refTooltipsGadgetName;
public function __construct( Config $config ) {
public function __construct( Config $config, ?GadgetRepo $gadgetRepo ) {
$this->navPopupsGadgetName = $this->sanitizeGadgetName(
$config->get( self::CONFIG_NAVIGATION_POPUPS_NAME ) );
$this->refTooltipsGadgetName = $this->sanitizeGadgetName(
$config->get( self::CONFIG_REFERENCE_TOOLTIPS_NAME ) );
try {
$this->gadgetRepo = MediaWikiServices::getInstance()->getService( 'GadgetsRepo' );
} catch ( NoSuchServiceException $e ) {
$this->gadgetRepo = null;
}
$this->gadgetRepo = $gadgetRepo;
}
private function sanitizeGadgetName( string $gadgetName ): string {

View file

@ -1,15 +1,26 @@
<?php
use Cite\ReferencePreviews\ReferencePreviewsContext;
use Cite\ReferencePreviews\ReferencePreviewsGadgetsIntegration;
use MediaWiki\MediaWikiServices;
use MediaWiki\Registration\ExtensionRegistry;
/**
* @codeCoverageIgnore
*/
return [
'Cite.GadgetsIntegration' => static function ( MediaWikiServices $services ): ReferencePreviewsGadgetsIntegration {
return new ReferencePreviewsGadgetsIntegration(
$services->getMainConfig(),
ExtensionRegistry::getInstance()->isLoaded( 'Gadgets' ) ?
$services->getService( 'GadgetsRepo' ) :
null
);
},
'Cite.ReferencePreviewsContext' => static function ( MediaWikiServices $services ): ReferencePreviewsContext {
return new ReferencePreviewsContext(
$services->getMainConfig(),
$services->getService( 'Cite.GadgetsIntegration' ),
$services->getUserOptionsLookup()
);
},

View file

@ -4,9 +4,11 @@ namespace Cite\Tests;
use ApiQuerySiteinfo;
use Cite\Hooks\CiteHooks;
use Cite\ReferencePreviews\ReferencePreviewsGadgetsIntegration;
use MediaWiki\Config\HashConfig;
use MediaWiki\ResourceLoader\ResourceLoader;
use MediaWiki\User\Options\StaticUserOptionsLookup;
use MediaWiki\User\User;
/**
* @covers \Cite\Hooks\CiteHooks
@ -28,6 +30,7 @@ class CiteHooksTest extends \MediaWikiIntegrationTestCase {
( new CiteHooks(
$this->getServiceContainer()->getService( 'Cite.ReferencePreviewsContext' ),
$this->getServiceContainer()->getService( 'Cite.GadgetsIntegration' ),
new StaticUserOptionsLookup( [] )
) )
->onResourceLoaderGetConfigVars( $vars, 'vector', $config );
@ -53,6 +56,7 @@ class CiteHooksTest extends \MediaWikiIntegrationTestCase {
( new CiteHooks(
$this->getServiceContainer()->getService( 'Cite.ReferencePreviewsContext' ),
$this->getServiceContainer()->getService( 'Cite.GadgetsIntegration' ),
new StaticUserOptionsLookup( [] )
) )
->onResourceLoaderRegisterModules( $resourceLoader );
@ -71,6 +75,7 @@ class CiteHooksTest extends \MediaWikiIntegrationTestCase {
( new CiteHooks(
$this->getServiceContainer()->getService( 'Cite.ReferencePreviewsContext' ),
$this->getServiceContainer()->getService( 'Cite.GadgetsIntegration' ),
new StaticUserOptionsLookup( [] )
) )
->onAPIQuerySiteInfoGeneralInfo( $api, $data );
@ -83,4 +88,69 @@ class CiteHooksTest extends \MediaWikiIntegrationTestCase {
yield [ false ];
}
public function testOnGetPreferences_noConflicts() {
$expected = [
'popups-reference-previews' => [
'type' => 'toggle',
'label-message' => 'popups-refpreview-user-preference-label',
'help-message' => 'popups-prefs-conflicting-gadgets-info',
'section' => 'rendering/reading'
]
];
$gadgetsIntegrationMock = $this->createMock( ReferencePreviewsGadgetsIntegration::class );
$prefs = [];
( new CiteHooks(
$this->getServiceContainer()->getService( 'Cite.ReferencePreviewsContext' ),
$gadgetsIntegrationMock,
new StaticUserOptionsLookup( [] )
) )
->onGetPreferences( $this->createMock( User::class ), $prefs );
$this->assertEquals( $expected, $prefs );
}
public function testOnGetPreferences_conflictingGadget() {
$expected = [
'popups-reference-previews' => [
'type' => 'toggle',
'label-message' => 'popups-refpreview-user-preference-label',
// 'help-message' => 'popups-prefs-conflicting-gadgets-info',
'help-message' => [
'popups-prefs-navpopups-gadget-conflict-info',
'Special:Preferences#mw-prefsection-gadgets',
],
'section' => 'rendering/reading',
'disabled' => true
]
];
$gadgetsIntegrationMock = $this->createMock( ReferencePreviewsGadgetsIntegration::class );
$gadgetsIntegrationMock->expects( $this->once() )
->method( 'isNavPopupsGadgetEnabled' )
->willReturn( true );
$prefs = [];
( new CiteHooks(
$this->getServiceContainer()->getService( 'Cite.ReferencePreviewsContext' ),
$gadgetsIntegrationMock,
new StaticUserOptionsLookup( [] )
) )
->onGetPreferences( $this->createMock( User::class ), $prefs );
$this->assertEquals( $expected, $prefs );
}
public function testOnGetPreferences_redundantPreference() {
$prefs = [
'popups-reference-previews' => [
'type' => 'toggle',
'label-message' => 'from-another-extension',
]
];
$expected = $prefs;
( new CiteHooks(
$this->getServiceContainer()->getService( 'Cite.ReferencePreviewsContext' ),
$this->getServiceContainer()->getService( 'Cite.GadgetsIntegration' ),
new StaticUserOptionsLookup( [] )
) )
->onGetPreferences( $this->createMock( User::class ), $prefs );
$this->assertEquals( $expected, $prefs );
}
}

View file

@ -40,6 +40,7 @@ class ReferencePreviewsContextTest extends MediaWikiIntegrationTestCase {
$this->assertSame( $expected,
( new ReferencePreviewsContext(
$config,
$this->getServiceContainer()->getService( 'Cite.GadgetsIntegration' ),
$userOptLookup
) )
->isReferencePreviewsEnabled( $user, $skin ),
@ -80,6 +81,7 @@ class ReferencePreviewsContextTest extends MediaWikiIntegrationTestCase {
$this->assertSame( $expected,
( new ReferencePreviewsContext(
$config,
$this->getServiceContainer()->getService( 'Cite.GadgetsIntegration' ),
$userOptLookup
) )
->isReferencePreviewsEnabled( $user, $skin ),

View file

@ -39,9 +39,12 @@ class ReferencePreviewsGadgetsIntegrationTest extends MediaWikiIntegrationTestCa
}
public function testConflictsWithNavPopupsGadgetIfGadgetsExtensionIsNotLoaded() {
$integration = new ReferencePreviewsGadgetsIntegration( $this->getConfig() );
$this->assertFalse(
$integration->isNavPopupsGadgetEnabled( $this->createNoOpMock( User::class ) ),
( new ReferencePreviewsGadgetsIntegration(
$this->getConfig(),
null
) )
->isNavPopupsGadgetEnabled( $this->createNoOpMock( User::class ) ),
'No conflict is identified.'
);
}
@ -153,12 +156,13 @@ class ReferencePreviewsGadgetsIntegrationTest extends MediaWikiIntegrationTestCa
GadgetRepo $repoMock,
bool $expected
): void {
$this->setService( 'GadgetsRepo', $repoMock );
$integration = new ReferencePreviewsGadgetsIntegration( $config );
$this->assertSame(
$expected,
$integration->isNavPopupsGadgetEnabled( $user ),
( new ReferencePreviewsGadgetsIntegration(
$config,
$repoMock
) )
->isNavPopupsGadgetEnabled( $user ),
( $expected ? 'A' : 'No' ) . ' conflict is identified.'
);
}

View file

@ -4,6 +4,7 @@ namespace Cite\Tests\Unit;
use Cite\Hooks\CiteHooks;
use Cite\ReferencePreviews\ReferencePreviewsContext;
use Cite\ReferencePreviews\ReferencePreviewsGadgetsIntegration;
use MediaWiki\Title\Title;
use MediaWiki\User\Options\StaticUserOptionsLookup;
@ -22,6 +23,7 @@ class CiteHooksUnitTest extends \MediaWikiUnitTestCase {
( new CiteHooks(
$this->createMock( ReferencePreviewsContext::class ),
$this->createMock( ReferencePreviewsGadgetsIntegration::class ),
new StaticUserOptionsLookup( [] )
) )
->onContentHandlerDefaultModelFor( $title, $model );