Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
AxArticleFooterEntrypointRegistrationHandler
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 7
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 isEntrypointAllowedOnSkin
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 isDiffPage
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 isDisambiguationPage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 shouldDisplayFooterEntrypoint
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
72
 onSkinAfterContent
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare( strict_types = 1 );
3
4namespace ContentTranslation\HookHandler;
5
6use MediaWiki\Config\Config;
7use MediaWiki\Config\ConfigFactory;
8use MediaWiki\Context\IContextSource;
9use MediaWiki\Extension\Disambiguator\Lookup;
10use MediaWiki\Hook\SkinAfterContentHook;
11use MediaWiki\Html\Html;
12use MediaWiki\Language\Language;
13use MediaWiki\Output\Hook\BeforePageDisplayHook;
14use MediaWiki\Title\Title;
15use Skin;
16
17/**
18 * Hook handler that registers the "ext.ax.articlefooter.entrypoint" RL module, when the
19 * appropriate conditions are met.
20 *
21 * @author Nik Gkountas
22 * @license GPL-2.0-or-later
23 * @since 2024.07
24 */
25class AxArticleFooterEntrypointRegistrationHandler implements BeforePageDisplayHook, SkinAfterContentHook {
26
27    private const ALLOWED_SKINS = [ 'minerva' ];
28    private Config $contentTranslationConfig;
29    private Language $contentLanguage;
30
31    /**
32     * Either a Lookup from the Disambiguator extension, or null if that is not installed
33     */
34    private ?Lookup $disambiguatorLookup;
35
36    public function __construct(
37        ConfigFactory $configFactory,
38        Language $contentLanguage,
39        ?Lookup $disambiguatorLookup
40    ) {
41        $this->contentTranslationConfig = $configFactory->makeConfig( 'ArticleFooterEntrypoint' );
42        $this->disambiguatorLookup = $disambiguatorLookup;
43        $this->contentLanguage = $contentLanguage;
44    }
45
46    private function isEntrypointAllowedOnSkin( Skin $skin ): bool {
47        $skinName = $skin->getSkinName();
48
49        return in_array( $skinName, self::ALLOWED_SKINS );
50    }
51
52    /**
53     * Check whether the output page is a diff page
54     *
55     * @param IContextSource $context
56     * @return bool
57     */
58    private static function isDiffPage( IContextSource $context ): bool {
59        $request = $context->getRequest();
60        $type = $request->getRawVal( 'type' );
61        $diff = $request->getCheck( 'diff' );
62        $oldId = $request->getCheck( 'oldid' );
63
64        return $type === 'revision' || $diff || $oldId;
65    }
66
67    /**
68     * Uses the Disambiguator extension to test whether the page is a disambiguation page.
69     *
70     * If the Disambiguator extension isn't installed, then the test always fails, i.e. the page is
71     * never a disambiguation page.
72     *
73     * @param Title $title
74     * @return bool
75     */
76    private function isDisambiguationPage( Title $title ): bool {
77        return $this->disambiguatorLookup && $this->disambiguatorLookup->isDisambiguationPage( $title );
78    }
79
80    private function shouldDisplayFooterEntrypoint( Skin $skin ): bool {
81        $title = $skin->getTitle();
82        $action = $skin->getRequest()->getRawVal( 'action' ) ?? 'view';
83
84        $enabledLanguages = $this->contentTranslationConfig->get(
85            'AutomaticTranslationLanguageSearcherEntrypointEnabledLanguages'
86        ) ?? [];
87
88        return in_array( $this->contentLanguage->getCode(), $enabledLanguages ) &&
89            $title->inNamespace( NS_MAIN ) &&
90            $action === 'view' &&
91            !$title->isMainPage() &&
92            $title->exists() &&
93            !self::isDiffPage( $skin ) &&
94            !$this->isDisambiguationPage( $title ) &&
95            $this->isEntrypointAllowedOnSkin( $skin );
96    }
97
98    public function onSkinAfterContent( &$data, $skin ) {
99        if ( $this->shouldDisplayFooterEntrypoint( $skin ) ) {
100            $data .= Html::element( 'div', [ 'class' => 'automatic-translation-entrypoint-container' ] );
101        }
102    }
103
104    public function onBeforePageDisplay( $out, $skin ): void {
105        if ( $this->shouldDisplayFooterEntrypoint( $skin ) ) {
106            $out->addModules( [ 'ext.ax.articlefooter.entrypoint' ] );
107        }
108    }
109}