Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
MobileFrontendEditorHooks
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 5
380
0.00% covered (danger)
0.00%
0 / 1
 getContentLanguageMessages
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getResourceLoaderMFConfigVars
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 onMakeGlobalVariablesScript
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 onCustomEditor
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
42
 isSupportedEditRequest
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3use MediaWiki\Config\Config;
4use MediaWiki\Context\IContextSource;
5use MediaWiki\Hook\CustomEditorHook;
6use MediaWiki\MediaWikiServices;
7use MediaWiki\Output\Hook\MakeGlobalVariablesScriptHook;
8use MediaWiki\Output\OutputPage;
9use MediaWiki\Registration\ExtensionRegistry;
10use MediaWiki\ResourceLoader\Context;
11use MediaWiki\User\User;
12
13class MobileFrontendEditorHooks implements
14    CustomEditorHook,
15    MakeGlobalVariablesScriptHook
16{
17
18    /**
19     * Return messages in content language, for use in a ResourceLoader module.
20     *
21     * @param Context $context
22     * @param Config $config
23     * @param array $messagesKeys
24     * @return array
25     */
26    public static function getContentLanguageMessages(
27        Context $context, Config $config, array $messagesKeys = []
28    ): array {
29        return array_combine(
30            $messagesKeys,
31            array_map( static function ( $key ) {
32                return wfMessage( $key )->inContentLanguage()->text();
33            }, $messagesKeys )
34        );
35    }
36
37    /**
38     * Generate config for usage inside MobileFrontend
39     * This should be used for variables which:
40     *  - vary with the html
41     *  - variables that should work cross skin including anonymous users
42     *  - used for both, stable and beta mode (don't use
43     *    MobileContext::isBetaGroupMember in this function - T127860)
44     *
45     * @return array
46     */
47    public static function getResourceLoaderMFConfigVars() {
48        $config = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Config' );
49
50        return [
51            'wgMFDefaultEditor' => $config->get( 'MFDefaultEditor' ),
52            'wgMFFallbackEditor' => $config->get( 'MFFallbackEditor' ),
53            'wgMFEnableVEWikitextEditor' => $config->get( 'MFEnableVEWikitextEditor' ),
54        ];
55    }
56
57    /**
58     * Handler for MakeGlobalVariablesScript hook.
59     * For values that depend on the current page, user or request state.
60     *
61     * @see https://www.mediawiki.org/wiki/Manual:Hooks/MakeGlobalVariablesScript
62     * @param array &$vars Variables to be added into the output
63     * @param OutputPage $out OutputPage instance calling the hook
64     */
65    public function onMakeGlobalVariablesScript( &$vars, $out ): void {
66        /** @var MobileContext $mobileContext */
67        $mobileContext = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' );
68        $config = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Config' );
69
70        if ( $mobileContext->shouldDisplayMobileView() ) {
71            // mobile.init
72            $vars['wgMFIsSupportedEditRequest'] = self::isSupportedEditRequest( $out->getContext() );
73            $vars['wgMFScriptPath'] = $config->get( 'MFScriptPath' );
74        }
75    }
76
77    /**
78     * Decide whether to bother showing the wikitext editor at all.
79     * If not, we expect the editor initialisation JS to activate.
80     *
81     * @param Article $article The article being viewed.
82     * @param User $user The user-specific settings.
83     * @return bool Whether to show the wikitext editor or not.
84     */
85    public function onCustomEditor( $article, $user ) {
86        $req = $article->getContext()->getRequest();
87        $title = $article->getTitle();
88        if (
89            !$req->getVal( 'mfnoscript' ) &&
90            self::isSupportedEditRequest( $article->getContext() )
91        ) {
92            $params = $req->getValues();
93            $params['mfnoscript'] = '1';
94            $url = wfScript() . '?' . wfArrayToCgi( $params );
95            $escapedUrl = htmlspecialchars( $url );
96
97            $out = $article->getContext()->getOutput();
98            $titleMsg = $title->exists() ? 'editing' : 'creating';
99            $out->setPageTitleMsg( wfMessage( $titleMsg, $title->getPrefixedText() ) );
100
101            $msg = false;
102            $msgParams = false;
103            if ( $title->inNamespace( NS_FILE ) && !$title->exists() ) {
104                // Is a new file page (enable upload image only) T60311
105                $msg = 'mobile-frontend-editor-uploadenable';
106            } else {
107                $msg = 'mobile-frontend-editor-toload';
108                $urlUtils = MediaWikiServices::getInstance()->getUrlUtils();
109                $msgParams = $urlUtils->expand( $url, PROTO_CURRENT );
110            }
111            $out->showPendingTakeover( $url, $msg, $msgParams );
112
113            $out->setRevisionId( $req->getInt( 'oldid', $article->getRevIdFetched() ) );
114            return false;
115        }
116        return true;
117    }
118
119    /**
120     * Whether the custom editor override should occur
121     *
122     * @param IContextSource $context
123     * @return bool Whether the frontend JS should try to display an editor
124     */
125    protected static function isSupportedEditRequest( IContextSource $context ) {
126        /** @var MobileContext $mobileContext */
127        $mobileContext = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' );
128        if ( !$mobileContext->shouldDisplayMobileView() ) {
129            return false;
130        }
131
132        $extensionRegistry = ExtensionRegistry::getInstance();
133        $editorAvailableSkins = $extensionRegistry->getAttribute( 'MobileFrontendEditorAvailableSkins' );
134        if ( !in_array( $context->getSkin()->getSkinName(), $editorAvailableSkins ) ) {
135            // Mobile editor commonly doesn't work well with other skins than Minerva (it looks horribly
136            // broken without some styles that are only defined by Minerva). So we only enable it for the
137            // skin that wants it.
138            return false;
139        }
140
141        $req = $context->getRequest();
142        $title = $context->getTitle();
143
144        // Various things fall back to WikiEditor
145        if ( $req->getRawVal( 'action' ) === 'submit' ) {
146            // Don't try to take over if the form has already been submitted
147            return false;
148        }
149        if ( $title->inNamespace( NS_SPECIAL ) ) {
150            return false;
151        }
152        if ( $title->getContentModel() !== 'wikitext' ) {
153            // Only load the wikitext editor on wikitext. Otherwise we'll rely on the fallback behaviour
154            // (You can test this on MediaWiki:Common.css) ?action=edit url (T173800)
155            return false;
156        }
157        if ( $req->getCheck( 'undo' ) || $req->getCheck( 'undoafter' ) ) {
158            // Undo needs to show a diff above the editor
159            return false;
160        }
161        if ( $req->getRawVal( 'section' ) === 'new' ) {
162            // New sections need a title field
163            return false;
164        }
165        return true;
166    }
167
168}