Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
79.55% covered (warning)
79.55%
35 / 44
46.15% covered (danger)
46.15%
6 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
GadgetResourceLoaderModule
79.55% covered (warning)
79.55%
35 / 44
46.15% covered (danger)
46.15%
6 / 13
36.20
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGadget
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
3.33
 getPages
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
9.02
 getScript
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 getRequireKey
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 validateScriptFile
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 isPackaged
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDependencies
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getType
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getMessages
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSkins
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 requiresES6
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGroup
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace MediaWiki\Extension\Gadgets;
4
5use InvalidArgumentException;
6use MediaWiki\MainConfigNames;
7use MediaWiki\MediaWikiServices;
8use MediaWiki\ResourceLoader as RL;
9
10/**
11 * Class representing a list of resources for one gadget, basically a wrapper
12 * around the Gadget class.
13 */
14class GadgetResourceLoaderModule extends RL\WikiModule {
15    /**
16     * @var string
17     */
18    private $id;
19
20    /**
21     * @var Gadget
22     */
23    private $gadget;
24
25    public function __construct( array $options ) {
26        $this->id = $options['id'];
27    }
28
29    /**
30     * @return Gadget instance this module is about
31     */
32    private function getGadget() {
33        if ( !$this->gadget ) {
34            /** @var GadgetRepo $repo */
35            $repo = MediaWikiServices::getInstance()->getService( 'GadgetsRepo' );
36            try {
37                $this->gadget = $repo->getGadget( $this->id );
38            } catch ( InvalidArgumentException ) {
39                // Fallback to a placeholder object...
40                $this->gadget = Gadget::newEmptyGadget( $this->id );
41            }
42        }
43
44        return $this->gadget;
45    }
46
47    /**
48     * @param RL\Context $context
49     * @return array
50     */
51    protected function getPages( RL\Context $context ) {
52        // In theory we could support these separately, but
53        // * gadget definitions assume both
54        // * it doesn't make sense to load half a gadget
55        // * it's poor UX to have some gadgets work and some not
56        // * historically this extension is only used when
57        //   a community permits both.
58        $config = $this->getConfig();
59        if ( !$config->get( MainConfigNames::UseSiteJs ) || !$config->get( MainConfigNames::UseSiteCss ) ) {
60            return [];
61        }
62
63        $gadget = $this->getGadget();
64        $pages = [];
65
66        foreach ( $gadget->getStyles() as $style ) {
67            $pages[$style] = [ 'type' => 'style' ];
68        }
69
70        if ( $gadget->supportsResourceLoader() ) {
71            foreach ( $gadget->getScripts() as $script ) {
72                $pages[$script] = [ 'type' => 'script' ];
73            }
74            if ( $gadget->isPackaged() ) {
75                foreach ( $gadget->getVues() as $vue ) {
76                    $pages[$vue] = [ 'type' => 'script-vue' ];
77                }
78                foreach ( $gadget->getJSONs() as $json ) {
79                    $pages[$json] = [ 'type' => 'data' ];
80                }
81            }
82        }
83
84        return $pages;
85    }
86
87    /**
88     * @inheritDoc
89     */
90    public function getScript( RL\Context $context ) {
91        $module = parent::getScript( $context );
92
93        if ( $this->isPackaged() && $this->gadget->getCodexIcons() ) {
94            // Add codex icons to the gadget module
95            $module['files']['icons.json'] = [
96                'type' => 'data',
97                'content' => RL\CodexModule::getIcons( $context, $this->getConfig(), $this->gadget->getCodexIcons() ),
98            ];
99        }
100        return $module;
101    }
102
103    /**
104     * @param string $titleText
105     * @return string
106     */
107    public function getRequireKey( $titleText ): string {
108        /** @var GadgetRepo $repo */
109        $repo = MediaWikiServices::getInstance()->getService( 'GadgetsRepo' );
110        return $repo->titleWithoutPrefix( $titleText, $this->id );
111    }
112
113    /**
114     * @param string $fileName
115     * @param string $contents
116     * @return string
117     */
118    protected function validateScriptFile( $fileName, $contents ) {
119        // Temporary solution to support gadgets in ES6 by disabling validation
120        // for them and putting them in a separate resource group to avoid a syntax error in them
121        // from corrupting core/extension-loaded scripts or other non-ES6 gadgets.
122        if ( $this->requiresES6() ) {
123            return $contents;
124        }
125        return parent::validateScriptFile( $fileName, $contents );
126    }
127
128    /**
129     * Returns whether this gadget is packaged.
130     */
131    public function isPackaged(): bool {
132        return $this->getGadget()->isPackaged();
133    }
134
135    /**
136     * @param RL\Context|null $context
137     * @return string[] Names of resources this module depends on
138     */
139    public function getDependencies( ?RL\Context $context = null ) {
140        return $this->getGadget()->getDependencies();
141    }
142
143    /**
144     * @return string RL\Module::LOAD_STYLES or RL\Module::LOAD_GENERAL
145     */
146    public function getType() {
147        return $this->getGadget()->getType() === 'styles'
148            ? RL\Module::LOAD_STYLES
149            : RL\Module::LOAD_GENERAL;
150    }
151
152    /** @inheritDoc */
153    public function getMessages() {
154        return $this->getGadget()->getMessages();
155    }
156
157    /** @inheritDoc */
158    public function getSkins(): ?array {
159        return $this->getGadget()->getRequiredSkins() ?: null;
160    }
161
162    /** @inheritDoc */
163    public function requiresES6(): bool {
164        return $this->getGadget()->requiresES6();
165    }
166
167    /** @inheritDoc */
168    public function getGroup() {
169        return $this->requiresES6() ? 'es6-gadget' : self::GROUP_SITE;
170    }
171}