Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 112
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 / 112
0.00% covered (danger)
0.00%
0 / 5
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
 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 / 46
0.00% covered (danger)
0.00%
0 / 1
42
 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 MediaWiki\Config\Config;
6use MediaWiki\Hook\ParserOutputPostCacheTransformHook;
7use MediaWiki\Hook\SidebarBeforeOutputHook;
8use MediaWiki\Html\Html;
9use MediaWiki\Page\Article;
10use MediaWiki\Page\Hook\ArticleParserOptionsHook;
11use MediaWiki\Parser\ParserOptions;
12use MediaWiki\Parser\ParserOutput;
13use MediaWiki\Preferences\Hook\GetPreferencesHook;
14use MediaWiki\Skin\Skin;
15use MediaWiki\User\Options\UserOptionsManager;
16use MediaWiki\User\User;
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            $userPref = Oracle::USERPREF_DEFAULT;
110            if ( $options['skin'] ?? null ) {
111                $user = $options['skin']->getUser();
112                $named = $user->isNamed();
113                $userPref = intval( $this->userOptionsManager->getOption(
114                    $user, 'parsermigration-parsoid-readviews'
115                ) );
116            }
117            if ( $named ) {
118                $parserOutput->setJsConfigVar(
119                    'parsermigration-notice-version',
120                    $this->mainConfig->get(
121                        'ParserMigrationUserNoticeVersion'
122                    )
123                );
124                $parserOutput->setJsConfigVar(
125                    'parsermigration-notice-days',
126                    $this->mainConfig->get(
127                        'ParserMigrationUserNoticeDays'
128                    )
129                );
130                $parserOutput->addModules( [ 'ext.parsermigration.notice' ] );
131            }
132            if ( $userPref === Oracle::USERPREF_ALWAYS ) {
133                // Add an indicator using an ad-hoc Codex InfoChip
134                // Replace when T357324 blesses a CSS-only InfoChip
135                $parserOutput->addModuleStyles( [ 'ext.parsermigration.indicator' ] );
136                $parserOutput->setIndicator(
137                    'parsoid',
138                    $this->mainConfig->get( 'ParserMigrationCompactIndicator' ) ?
139                    Html::rawElement(
140                        'div',
141                        [
142                            'class' => 'mw-parsoid-icon notheme mw-no-invert',
143                            'title' => wfMessage( 'parsermigration-parsoid-chip-label' )->text(),
144                        ]
145                    ) :
146                    Html::rawElement(
147                        'div',
148                        [ 'class' => 'cdx-info-chip' ],
149                        Html::element(
150                            'span',
151                            [ 'class' => 'cdx-info-chip--text' ],
152                            wfMessage( 'parsermigration-parsoid-chip-label' )->text()
153                        )
154                    )
155                );
156            }
157        }
158    }
159
160    /**
161     * @param Skin $skin
162     * @param array &$sidebar Sidebar content
163     * @return void
164     */
165    public function onSidebarBeforeOutput( $skin, &$sidebar ): void {
166        $out = $skin->getOutput();
167        if ( !$out->isArticleRelated() ) {
168            // Only add sidebar links before article-related pages
169            return;
170        }
171
172        $queryStringEnabled = $this->mainConfig->get(
173            'ParserMigrationEnableQueryString'
174        );
175        if ( !$queryStringEnabled ) {
176            // Early exit from those wikis where we don't want the
177            // user to be able to put Parsoid pages into the parser cache.
178            return;
179        }
180
181        $user = $skin->getUser();
182        $title = $skin->getTitle();
183
184        $editToolPref = $this->userOptionsManager->getOption(
185            $user, 'parsermigration'
186        );
187        $userPref = intval( $this->userOptionsManager->getOption(
188            $user, 'parsermigration-parsoid-readviews'
189        ) );
190
191        $shouldShowToggle = false;
192        if ( $editToolPref ) {
193            $sidebar['TOOLBOX']['parsermigration'] = [
194                'href' => $title->getLocalURL( [
195                    'action' => 'parsermigration-edit',
196                ] ),
197                'text' => $skin->msg( 'parsermigration-toolbox-label' )->text(),
198            ];
199            $shouldShowToggle = true;
200        }
201        if ( $this->oracle->isParsoidDefaultFor( $title ) ) {
202            $shouldShowToggle = true;
203        }
204        if ( $userPref === Oracle::USERPREF_ALWAYS ) {
205            $shouldShowToggle = true;
206        }
207
208        if ( $shouldShowToggle ) {
209            $usingParsoid = $this->oracle->shouldUseParsoid( $user, $skin->getRequest(), $title );
210            $sidebar[ 'TOOLBOX' ][ 'parsermigration' ] = [
211                'href' => $title->getLocalURL( [
212                    // Allow toggling 'useParsoid' from the current state
213                    'useparsoid' => $usingParsoid ? '0' : '1',
214                ] ),
215                'text' => $skin->msg(
216                    $usingParsoid ?
217                    'parsermigration-use-legacy-parser-toolbox-label' :
218                    'parsermigration-use-parsoid-toolbox-label'
219                )->text(),
220            ];
221        }
222    }
223}