Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 98
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 / 98
0.00% covered (danger)
0.00%
0 / 5
306
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 / 32
0.00% covered (danger)
0.00%
0 / 1
20
 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                Html::rawElement(
133                    'div',
134                    [ 'class' => 'cdx-info-chip' ],
135                    Html::element(
136                        'span',
137                        [ 'class' => 'cdx-info-chip--text' ],
138                        wfMessage( 'parsermigration-parsoid-chip-label' )->text()
139                    )
140                )
141            );
142        }
143    }
144
145    /**
146     * @param Skin $skin
147     * @param array &$sidebar Sidebar content
148     * @return void
149     */
150    public function onSidebarBeforeOutput( $skin, &$sidebar ): void {
151        $out = $skin->getOutput();
152        if ( !$out->isArticleRelated() ) {
153            // Only add sidebar links before article-related pages
154            return;
155        }
156
157        $queryStringEnabled = $this->mainConfig->get(
158            'ParserMigrationEnableQueryString'
159        );
160        if ( !$queryStringEnabled ) {
161            // Early exit from those wikis where we don't want the
162            // user to be able to put Parsoid pages into the parser cache.
163            return;
164        }
165
166        $user = $skin->getUser();
167        $title = $skin->getTitle();
168
169        $editToolPref = $this->userOptionsManager->getOption(
170            $user, 'parsermigration'
171        );
172        $userPref = intval( $this->userOptionsManager->getOption(
173            $user, 'parsermigration-parsoid-readviews'
174        ) );
175
176        $shouldShowToggle = false;
177        if ( $editToolPref ) {
178            $sidebar['TOOLBOX']['parsermigration'] = [
179                'href' => $title->getLocalURL( [
180                    'action' => 'parsermigration-edit',
181                ] ),
182                'text' => $skin->msg( 'parsermigration-toolbox-label' )->text(),
183            ];
184            $shouldShowToggle = true;
185        }
186        if ( $this->oracle->isParsoidDefaultFor( $title ) ) {
187            $shouldShowToggle = true;
188        }
189        if ( $userPref === Oracle::USERPREF_ALWAYS ) {
190            $shouldShowToggle = true;
191        }
192
193        if ( $shouldShowToggle ) {
194            $usingParsoid = $this->oracle->shouldUseParsoid( $user, $skin->getRequest(), $title );
195            $sidebar[ 'TOOLBOX' ][ 'parsermigration' ] = [
196                'href' => $title->getLocalURL( [
197                    // Allow toggling 'useParsoid' from the current state
198                    'useparsoid' => $usingParsoid ? '0' : '1',
199                ] ),
200                'text' => $skin->msg(
201                    $usingParsoid ?
202                    'parsermigration-use-legacy-parser-toolbox-label' :
203                    'parsermigration-use-parsoid-toolbox-label'
204                )->text(),
205            ];
206        }
207    }
208}