Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
OOUIFileModule
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 4
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 setSkinStylesOverride
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getSkinSpecific
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 extendSkinSpecific
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace MediaWiki\ResourceLoader;
22
23/**
24 * Module which magically loads the right skinScripts and skinStyles for every
25 * skin, using the specified OOUI theme for each.
26 *
27 * @ingroup ResourceLoader
28 * @internal
29 */
30class OOUIFileModule extends FileModule {
31    use OOUIModule;
32
33    /** @var array<string,string|FilePath> */
34    private $themeStyles = [];
35
36    public function __construct( array $options = [] ) {
37        if ( isset( $options['themeScripts'] ) ) {
38            $skinScripts = $this->getSkinSpecific( $options['themeScripts'], 'scripts' );
39            $options['skinScripts'] = $this->extendSkinSpecific( $options['skinScripts'] ?? [], $skinScripts );
40        }
41        if ( isset( $options['themeStyles'] ) ) {
42            $this->themeStyles = $this->getSkinSpecific( $options['themeStyles'], 'styles' );
43        }
44
45        parent::__construct( $options );
46    }
47
48    public function setSkinStylesOverride( array $moduleSkinStyles ): void {
49        parent::setSkinStylesOverride( $moduleSkinStyles );
50
51        $this->skinStyles = $this->extendSkinSpecific( $this->skinStyles, $this->themeStyles );
52    }
53
54    /**
55     * Helper function to generate values for 'skinStyles' and 'skinScripts'.
56     *
57     * @param string $module Module to generate skinStyles/skinScripts for:
58     *   'core', 'widgets', 'toolbars', 'windows'
59     * @param string $which 'scripts' or 'styles'
60     * @return array<string,string|FilePath>
61     */
62    private function getSkinSpecific( $module, $which ): array {
63        $themes = self::getSkinThemeMap();
64
65        return array_combine(
66            array_keys( $themes ),
67            array_map( function ( $theme ) use ( $module, $which ) {
68                if ( $which === 'scripts' ) {
69                    return $this->getThemeScriptsPath( $theme, $module );
70                } else {
71                    return $this->getThemeStylesPath( $theme, $module );
72                }
73            }, array_values( $themes ) )
74        );
75    }
76
77    /**
78     * Prepend theme-specific resources on behalf of the skin.
79     *
80     * The expected order of styles and scripts in the output is:
81     *
82     * 1. Theme-specific resources for a given skin.
83     *
84     * 2. Module-defined resources for a specific skin,
85     *    falling back to module-defined "default" skin resources.
86     *
87     * 3. Skin-defined resources for a specific module, which can either
88     *    append to or replace the "default" (via ResourceModuleSkinStyles in skin.json)
89     *    Note that skins can only define resources for a module if that
90     *    module does not already explicitly provide resources for that skin.
91     *
92     * @param array $skinSpecific Module-defined 'skinScripts' or 'skinStyles'.
93     * @param array $themeSpecific
94     * @return array Modified $skinSpecific
95     */
96    private function extendSkinSpecific( array $skinSpecific, array $themeSpecific ): array {
97        // If the module or skin already set skinStyles/skinScripts, prepend ours
98        foreach ( $skinSpecific as $skin => $files ) {
99            if ( !is_array( $files ) ) {
100                $files = [ $files ];
101            }
102            if ( isset( $themeSpecific[$skin] ) ) {
103                $skinSpecific[$skin] = array_merge( [ $themeSpecific[$skin] ], $files );
104            } elseif ( isset( $themeSpecific['default'] ) ) {
105                $skinSpecific[$skin] = array_merge( [ $themeSpecific['default'] ], $files );
106            }
107        }
108        // If the module has no skinStyles/skinScripts for a skin, then set ours
109        foreach ( $themeSpecific as $skin => $file ) {
110            if ( !isset( $skinSpecific[$skin] ) ) {
111                $skinSpecific[$skin] = [ $file ];
112            }
113        }
114        return $skinSpecific;
115    }
116}