Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
9.09% covered (danger)
9.09%
3 / 33
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
OOUIModule
9.09% covered (danger)
9.09%
3 / 33
16.67% covered (danger)
16.67%
1 / 6
161.26
0.00% covered (danger)
0.00%
0 / 1
 getSkinThemeMap
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getThemePaths
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
 getThemePath
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 getThemeScriptsPath
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getThemeStylesPath
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getThemeImagesPath
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 */
6
7namespace MediaWiki\ResourceLoader;
8
9use InvalidArgumentException;
10use MediaWiki\Registration\ExtensionRegistry;
11
12/**
13 * Convenience methods for dealing with OOUI themes and their relations to MW skins.
14 *
15 * @ingroup ResourceLoader
16 * @internal
17 */
18trait OOUIModule {
19    /** @var string[] */
20    protected static $knownScriptsModules = [ 'core' ];
21    /** @var string[] */
22    protected static $knownStylesModules = [ 'core', 'widgets', 'toolbars', 'windows' ];
23    /** @var string[] */
24    protected static $knownImagesModules = [
25        'indicators',
26        // Extra icons
27        'icons-accessibility',
28        'icons-alerts',
29        'icons-content',
30        'icons-editing-advanced',
31        'icons-editing-citation',
32        'icons-editing-functions',
33        'icons-editing-core',
34        'icons-editing-list',
35        'icons-editing-styling',
36        'icons-interactions',
37        'icons-layout',
38        'icons-location',
39        'icons-media',
40        'icons-moderation',
41        'icons-movement',
42        'icons-user',
43        'icons-wikimedia',
44    ];
45
46    /** @var string[] Note that keys must be lowercase, values TitleCase. */
47    protected static $builtinSkinThemeMap = [
48        'default' => 'WikimediaUI',
49    ];
50
51    /** @var string[][] Note that keys must be TitleCase. */
52    protected static $builtinThemePaths = [
53        'WikimediaUI' => [
54            'scripts' => 'resources/lib/ooui/oojs-ui-wikimediaui.js',
55            'styles' => 'resources/lib/ooui/oojs-ui-{module}-wikimediaui.css',
56            'images' => 'resources/lib/ooui/themes/wikimediaui/{module}.json',
57        ],
58        'Apex' => [
59            'scripts' => 'resources/lib/ooui/oojs-ui-apex.js',
60            'styles' => 'resources/lib/ooui/oojs-ui-{module}-apex.css',
61            'images' => 'resources/lib/ooui/themes/apex/{module}.json',
62        ],
63    ];
64
65    /**
66     * Return a map of skin names (in lowercase) to OOUI theme names, defining which theme a given
67     * skin should use.
68     *
69     * @return array
70     */
71    public static function getSkinThemeMap() {
72        $themeMap = self::$builtinSkinThemeMap;
73        $themeMap += ExtensionRegistry::getInstance()->getAttribute( 'SkinOOUIThemes' );
74        return $themeMap;
75    }
76
77    /**
78     * Return a map of theme names to lists of paths from which a given theme should be loaded.
79     *
80     * Keys are theme names, values are associative arrays. Keys of the inner array are 'scripts',
81     * 'styles', or 'images', and values are paths. Paths may be strings or FilePaths.
82     *
83     * Additionally, the string '{module}' in paths represents the name of the module to load.
84     *
85     * @return array
86     */
87    protected static function getThemePaths() {
88        $themePaths = self::$builtinThemePaths;
89        $themePaths += ExtensionRegistry::getInstance()->getAttribute( 'OOUIThemePaths' );
90
91        [ $defaultLocalBasePath, $defaultRemoteBasePath ] =
92            FileModule::extractBasePaths();
93
94        // Allow custom themes' paths to be relative to the skin/extension that defines them,
95        // like with ResourceModuleSkinStyles
96        foreach ( $themePaths as &$paths ) {
97            [ $localBasePath, $remoteBasePath ] =
98                FileModule::extractBasePaths( $paths );
99            if ( $localBasePath !== $defaultLocalBasePath || $remoteBasePath !== $defaultRemoteBasePath ) {
100                foreach ( $paths as &$path ) {
101                    $path = new FilePath( $path, $localBasePath, $remoteBasePath );
102                }
103            }
104        }
105
106        return $themePaths;
107    }
108
109    /**
110     * Return a path to load given module of given theme from.
111     *
112     * The file at this path may not exist. This should be handled by the caller (throwing an error or
113     * falling back to default theme).
114     *
115     * @param string $theme OOUI theme name, for example 'WikimediaUI' or 'Apex'
116     * @param string $kind Kind of the module: 'scripts', 'styles', or 'images'
117     * @param string $module Module name, for valid values see $knownScriptsModules,
118     *     $knownStylesModules, $knownImagesModules
119     * @return string|FilePath
120     */
121    protected function getThemePath( $theme, $kind, $module ) {
122        $paths = self::getThemePaths();
123        $path = $paths[$theme][$kind];
124        if ( $path instanceof FilePath ) {
125            $path = new FilePath(
126                str_replace( '{module}', $module, $path->getPath() ),
127                $path->getLocalBasePath(),
128                $path->getRemoteBasePath()
129            );
130        } else {
131            $path = str_replace( '{module}', $module, $path );
132        }
133        return $path;
134    }
135
136    /**
137     * @param string $theme See getThemePath()
138     * @param string $module See getThemePath()
139     * @return string|FilePath
140     */
141    protected function getThemeScriptsPath( $theme, $module ) {
142        if ( !in_array( $module, self::$knownScriptsModules ) ) {
143            throw new InvalidArgumentException( "Invalid OOUI scripts module '$module'" );
144        }
145        return $this->getThemePath( $theme, 'scripts', $module );
146    }
147
148    /**
149     * @param string $theme See getThemePath()
150     * @param string $module See getThemePath()
151     * @return string|FilePath
152     */
153    protected function getThemeStylesPath( $theme, $module ) {
154        if ( !in_array( $module, self::$knownStylesModules ) ) {
155            throw new InvalidArgumentException( "Invalid OOUI styles module '$module'" );
156        }
157        return $this->getThemePath( $theme, 'styles', $module );
158    }
159
160    /**
161     * @param string $theme See getThemePath()
162     * @param string $module See getThemePath()
163     * @return string|FilePath
164     */
165    protected function getThemeImagesPath( $theme, $module ) {
166        if ( !in_array( $module, self::$knownImagesModules ) ) {
167            throw new InvalidArgumentException( "Invalid OOUI images module '$module'" );
168        }
169        return $this->getThemePath( $theme, 'images', $module );
170    }
171}