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