Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 106
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hooks
0.00% covered (danger)
0.00%
0 / 106
0.00% covered (danger)
0.00%
0 / 5
342
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
 onGetPreferences
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 onArticleParserOptions
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 onParserOutputPostCacheTransform
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
30
 onSidebarBeforeOutput
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3namespace MediaWiki\Extension\ParserMigration;
4
5use Article;
6use MediaWiki\Config\Config;
7use MediaWiki\Hook\ParserOutputPostCacheTransformHook;
8use MediaWiki\Hook\SidebarBeforeOutputHook;
9use MediaWiki\Html\Html;
10use MediaWiki\Page\Hook\ArticleParserOptionsHook;
11use MediaWiki\Parser\ParserOutput;
12use MediaWiki\Preferences\Hook\GetPreferencesHook;
13use MediaWiki\User\Options\UserOptionsManager;
14use MediaWiki\User\User;
15use ParserOptions;
16use Skin;
17
18class Hooks implements
19    GetPreferencesHook,
20    SidebarBeforeOutputHook,
21    ArticleParserOptionsHook,
22    ParserOutputPostCacheTransformHook
23{
24
25    private Config $mainConfig;
26    private UserOptionsManager $userOptionsManager;
27    private Oracle $oracle;
28
29    /**
30     * @param Config $mainConfig
31     * @param UserOptionsManager $userOptionsManager
32     * @param Oracle $oracle
33     */
34    public function __construct(
35        Config $mainConfig,
36        UserOptionsManager $userOptionsManager,
37        Oracle $oracle
38    ) {
39        $this->mainConfig = $mainConfig;
40        $this->userOptionsManager = $userOptionsManager;
41        $this->oracle = $oracle;
42    }
43
44    /**
45     * @param User $user
46     * @param array &$defaultPreferences
47     * @return bool
48     */
49    public function onGetPreferences( $user, &$defaultPreferences ) {
50        $defaultPreferences['parsermigration-parsoid-readviews'] = [
51            'type' => 'select',
52            'label-message' => 'parsermigration-parsoid-readviews-selector-label',
53            'help-message' => 'parsermigration-parsoid-readviews-selector-help',
54            'section' => 'editing/developertools',
55            'options-messages' => [
56                'parsermigration-parsoid-readviews-always' => Oracle::USERPREF_ALWAYS,
57                'parsermigration-parsoid-readviews-default' => Oracle::USERPREF_DEFAULT,
58                'parsermigration-parsoid-readviews-never' => Oracle::USERPREF_NEVER,
59            ],
60        ];
61
62        $defaultPreferences['parsermigration'] = [
63            'type' => 'toggle',
64            'label-message' => 'parsermigration-pref-label',
65            'help-message' => 'parsermigration-pref-help',
66            'section' => 'editing/developertools'
67        ];
68
69        return true;
70    }
71
72    /**
73     * @see https://www.mediawiki.org/wiki/Manual:Hooks/ArticleParserOptions
74     * @param Article $article
75     * @param ParserOptions $popts
76     * @return bool|void
77     */
78    public function onArticleParserOptions(
79        Article $article, ParserOptions $popts
80    ) {
81        // T348257: Allow individual user to opt in to Parsoid read views as a
82        // use option in the ParserMigration section.
83        $context = $article->getContext();
84        if ( $this->oracle->shouldUseParsoid( $context->getUser(), $context->getRequest(), $article->getTitle() ) ) {
85            $popts->setUseParsoid();
86        }
87        return true;
88    }
89
90    /**
91     * This hook is called from ParserOutput::getText() to do
92     * post-cache transforms.
93     *
94     * @since 1.35
95     *
96     * @param ParserOutput $parserOutput
97     * @param string &$text Text being transformed, before core transformations are done
98     * @param array &$options Options array being used for the transformation
99     * @return void This hook must not abort, it must return no value
100     */
101    public function onParserOutputPostCacheTransform( $parserOutput, &$text,
102        &$options
103    ): void {
104        // Make "whether Parsoid was used" visible to client-side JS
105        if ( $options['isParsoidContent'] ?? false ) {
106            $parserOutput->setJsConfigVar( 'parsermigration-parsoid', true );
107            // Add a user notice for named users
108            $named = false;
109            if ( $options['skin'] ) {
110                $named = $options['skin']->getUser()->isNamed();
111            }
112            if ( $named ) {
113                $parserOutput->setJsConfigVar(
114                    'parsermigration-notice-version',
115                    $this->mainConfig->get(
116                        'ParserMigrationUserNoticeVersion'
117                    )
118                );
119                $parserOutput->setJsConfigVar(
120                    'parsermigration-notice-days',
121                    $this->mainConfig->get(
122                        'ParserMigrationUserNoticeDays'
123                    )
124                );
125                $parserOutput->addModules( [ 'ext.parsermigration.notice' ] );
126            }
127            // Add an indicator using an ad-hoc Codex InfoChip
128            // Replace when T357324 blesses a CSS-only InfoChip
129            $parserOutput->addModuleStyles( [ 'ext.parsermigration.indicator' ] );
130            $parserOutput->setIndicator(
131                'parsoid',
132                $this->mainConfig->get( 'ParserMigrationCompactIndicator' ) ?
133                Html::rawElement(
134                    'div',
135                    [
136                        'class' => 'mw-parsoid-icon notheme mw-no-invert',
137                        'title' => wfMessage( 'parsermigration-parsoid-chip-label' )->text(),
138                    ]
139                ) :
140                Html::rawElement(
141                    'div',
142                    [ 'class' => 'cdx-info-chip' ],
143                    Html::element(
144                        'span',
145                        [ 'class' => 'cdx-info-chip--text' ],
146                        wfMessage( 'parsermigration-parsoid-chip-label' )->text()
147                    )
148                )
149            );
150        }
151    }
152
153    /**
154     * @param Skin $skin
155     * @param array &$sidebar Sidebar content
156     * @return void
157     */
158    public function onSidebarBeforeOutput( $skin, &$sidebar ): void {
159        $out = $skin->getOutput();
160        if ( !$out->isArticleRelated() ) {
161            // Only add sidebar links before article-related pages
162            return;
163        }
164
165        $queryStringEnabled = $this->mainConfig->get(
166            'ParserMigrationEnableQueryString'
167        );
168        if ( !$queryStringEnabled ) {
169            // Early exit from those wikis where we don't want the
170            // user to be able to put Parsoid pages into the parser cache.
171            return;
172        }
173
174        $user = $skin->getUser();
175        $title = $skin->getTitle();
176
177        $editToolPref = $this->userOptionsManager->getOption(
178            $user, 'parsermigration'
179        );
180        $userPref = intval( $this->userOptionsManager->getOption(
181            $user, 'parsermigration-parsoid-readviews'
182        ) );
183
184        $shouldShowToggle = false;
185        if ( $editToolPref ) {
186            $sidebar['TOOLBOX']['parsermigration'] = [
187                'href' => $title->getLocalURL( [
188                    'action' => 'parsermigration-edit',
189                ] ),
190                'text' => $skin->msg( 'parsermigration-toolbox-label' )->text(),
191            ];
192            $shouldShowToggle = true;
193        }
194        if ( $this->oracle->isParsoidDefaultFor( $title ) ) {
195            $shouldShowToggle = true;
196        }
197        if ( $userPref === Oracle::USERPREF_ALWAYS ) {
198            $shouldShowToggle = true;
199        }
200
201        if ( $shouldShowToggle ) {
202            $usingParsoid = $this->oracle->shouldUseParsoid( $user, $skin->getRequest(), $title );
203            $sidebar[ 'TOOLBOX' ][ 'parsermigration' ] = [
204                'href' => $title->getLocalURL( [
205                    // Allow toggling 'useParsoid' from the current state
206                    'useparsoid' => $usingParsoid ? '0' : '1',
207                ] ),
208                'text' => $skin->msg(
209                    $usingParsoid ?
210                    'parsermigration-use-legacy-parser-toolbox-label' :
211                    'parsermigration-use-parsoid-toolbox-label'
212                )->text(),
213            ];
214        }
215    }
216}