Allow loading styles for arbitrary OOUI icon packs
authorBartosz Dziewoński <matma.rex@gmail.com>
Mon, 12 Feb 2018 19:41:44 +0000 (20:41 +0100)
committerBartosz Dziewoński <matma.rex@gmail.com>
Tue, 11 Jun 2019 17:52:23 +0000 (17:52 +0000)
You can now create ResourceLoader modules for arbitrary sets of OOUI
icons. This is an alternative to I8af783666a2b23a938af93c1b56fee619219eaf5.

Update dependencies of OOUI's modules to use custom icon packs instead
of default icon packs.

Bug: T160690
Change-Id: Icf9560da79c91e56c7a3f4c0de01dd057f5aa00d

autoload.php
includes/OutputPage.php
includes/resourceloader/ResourceLoaderOOUIIconPackModule.php [new file with mode: 0644]
includes/resourceloader/ResourceLoaderOOUIImageModule.php
resources/Resources.php

index eb8ba09..b26549e 100644 (file)
@@ -1246,6 +1246,7 @@ $wgAutoloadLocalClasses = [
        'ResourceLoaderLessVarFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLessVarFileModule.php',
        'ResourceLoaderModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderModule.php',
        'ResourceLoaderOOUIFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIFileModule.php',
+       'ResourceLoaderOOUIIconPackModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIIconPackModule.php',
        'ResourceLoaderOOUIImageModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIImageModule.php',
        'ResourceLoaderOOUIModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIModule.php',
        'ResourceLoaderSiteModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSiteModule.php',
index 54b3ee5..5227aa1 100644 (file)
@@ -4214,9 +4214,7 @@ class OutputPage extends ContextSource {
                        'oojs-ui.styles.indicators',
                        'oojs-ui.styles.textures',
                        'mediawiki.widgets.styles',
-                       'oojs-ui.styles.icons-content',
-                       'oojs-ui.styles.icons-alerts',
-                       'oojs-ui.styles.icons-interactions',
+                       'oojs-ui-core.icons',
                ] );
        }
 
diff --git a/includes/resourceloader/ResourceLoaderOOUIIconPackModule.php b/includes/resourceloader/ResourceLoaderOOUIIconPackModule.php
new file mode 100644 (file)
index 0000000..0c70ee1
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Allows loading arbitrary sets of OOUI icons.
+ *
+ * @since 1.34
+ */
+class ResourceLoaderOOUIIconPackModule extends ResourceLoaderOOUIImageModule {
+       public function __construct( $options = [], $localBasePath = null ) {
+               parent::__construct( $options, $localBasePath );
+
+               if ( !isset( $this->definition['icons'] ) || !$this->definition['icons'] ) {
+                       throw new InvalidArgumentException( "Parameter 'icons' must be given." );
+               }
+
+               // A few things check for the "icons" prefix on this value, so specify it even though
+               // we don't use it for actually loading the data, like in the other modules.
+               $this->definition['themeImages'] = 'icons';
+       }
+
+       private function getIcons() {
+               return $this->definition['icons'];
+       }
+
+       protected function loadOOUIDefinition( $theme, $unused ) {
+               // This is shared between instances of this class, so we only have to load the JSON files once
+               static $data = [];
+
+               if ( !isset( $data[$theme] ) ) {
+                       $data[$theme] = [];
+                       // Load and merge the JSON data for all "icons-foo" modules
+                       foreach ( self::$knownImagesModules as $module ) {
+                               if ( substr( $module, 0, 5 ) === 'icons' ) {
+                                       $moreData = $this->readJSONFile( $this->getThemeImagesPath( $theme, $module ) );
+                                       if ( $moreData ) {
+                                               $data[$theme] = array_replace_recursive( $data[$theme], $moreData );
+                                       }
+                               }
+                       }
+               }
+
+               $definition = $data[$theme];
+
+               // Filter out the data for all other icons, leaving only the ones we want for this module
+               $iconsNames = $this->getIcons();
+               foreach ( array_keys( $definition['images'] ) as $iconName ) {
+                       if ( !in_array( $iconName, $iconsNames ) ) {
+                               unset( $definition['images'][$iconName] );
+                       }
+               }
+
+               return $definition;
+       }
+}
index 313d789..34079c3 100644 (file)
@@ -19,7 +19,8 @@
  */
 
 /**
- * Secret special sauce.
+ * Loads the module definition from JSON files in the format that OOUI uses, converting it to the
+ * format we use. (Previously known as secret special sauce.)
  *
  * @since 1.26
  */
@@ -39,36 +40,12 @@ class ResourceLoaderOOUIImageModule extends ResourceLoaderImageModule {
 
                $definition = [];
                foreach ( $themes as $skin => $theme ) {
-                       // Find the path to the JSON file which contains the actual image definitions for this theme
-                       if ( $module ) {
-                               $dataPath = $this->getThemeImagesPath( $theme, $module );
-                       } else {
-                               // Backwards-compatibility for things that probably shouldn't have used this class...
-                               $dataPath =
-                                       $this->definition['rootPath'] . '/' .
-                                       strtolower( $theme ) . '/' .
-                                       $this->definition['name'] . '.json';
-                       }
-                       $localDataPath = $this->localBasePath . '/' . $dataPath;
+                       $data = $this->loadOOUIDefinition( $theme, $module );
 
-                       // If there's no file for this module of this theme, that's okay, it will just use the defaults
-                       if ( !file_exists( $localDataPath ) ) {
+                       if ( !$data ) {
+                               // If there's no file for this module of this theme, that's okay, it will just use the defaults
                                continue;
                        }
-                       $data = json_decode( file_get_contents( $localDataPath ), true );
-
-                       // Expand the paths to images (since they are relative to the JSON file that defines them, not
-                       // our base directory)
-                       $fixPath = function ( &$path ) use ( $dataPath ) {
-                               $path = dirname( $dataPath ) . '/' . $path;
-                       };
-                       array_walk( $data['images'], function ( &$value ) use ( $fixPath ) {
-                               if ( is_string( $value['file'] ) ) {
-                                       $fixPath( $value['file'] );
-                               } elseif ( is_array( $value['file'] ) ) {
-                                       array_walk_recursive( $value['file'], $fixPath );
-                               }
-                       } );
 
                        // Convert into a definition compatible with the parent vanilla ResourceLoaderImageModule
                        foreach ( $data as $key => $value ) {
@@ -107,4 +84,59 @@ class ResourceLoaderOOUIImageModule extends ResourceLoaderImageModule {
 
                parent::loadFromDefinition();
        }
+
+       /**
+        * Load the module definition from the JSON file(s) for the given theme and module.
+        *
+        * @since 1.34
+        * @param string $theme
+        * @param string $module
+        * @return array
+        */
+       protected function loadOOUIDefinition( $theme, $module ) {
+               // Find the path to the JSON file which contains the actual image definitions for this theme
+               if ( $module ) {
+                       $dataPath = $this->getThemeImagesPath( $theme, $module );
+               } else {
+                       // Backwards-compatibility for things that probably shouldn't have used this class...
+                       $dataPath =
+                               $this->definition['rootPath'] . '/' .
+                               strtolower( $theme ) . '/' .
+                               $this->definition['name'] . '.json';
+               }
+
+               return $this->readJSONFile( $dataPath );
+       }
+
+       /**
+        * Read JSON from a file, and transform all paths in it to be relative to the module's base path.
+        *
+        * @since 1.34
+        * @param string $dataPath Path relative to the module's base bath
+        * @return array|false
+        */
+       protected function readJSONFile( $dataPath ) {
+               $localDataPath = $this->localBasePath . '/' . $dataPath;
+
+               if ( !file_exists( $localDataPath ) ) {
+                       return false;
+               }
+
+               $data = json_decode( file_get_contents( $localDataPath ), true );
+
+               // Expand the paths to images (since they are relative to the JSON file that defines them, not
+               // our base directory)
+               $fixPath = function ( &$path ) use ( $dataPath ) {
+                       $path = dirname( $dataPath ) . '/' . $path;
+               };
+               array_walk( $data['images'], function ( &$value ) use ( $fixPath ) {
+                       if ( is_string( $value['file'] ) ) {
+                               $fixPath( $value['file'] );
+                       } elseif ( is_array( $value['file'] ) ) {
+                               array_walk_recursive( $value['file'], $fixPath );
+                       }
+               } );
+
+               return $data;
+       }
 }
index ece1c90..b90ead4 100644 (file)
@@ -2897,12 +2897,10 @@ return [
                'dependencies' => [
                        'oojs',
                        'oojs-ui-core.styles',
+                       'oojs-ui-core.icons',
                        'oojs-ui.styles.indicators',
                        'oojs-ui.styles.textures',
                        'mediawiki.language',
-                       'oojs-ui.styles.icons-content',
-                       'oojs-ui.styles.icons-alerts',
-                       'oojs-ui.styles.icons-interactions',
                ],
                'messages' => [
                        'ooui-field-help',
@@ -2919,6 +2917,11 @@ return [
                'themeStyles' => 'core',
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'oojs-ui-core.icons' => [
+               'class' => ResourceLoaderOOUIIconPackModule::class,
+               'icons' => [ 'add', 'alert', 'notice', 'error', 'check', 'close', 'info', 'search', 'subtract' ],
+               'targets' => [ 'desktop', 'mobile' ],
+       ],
        // Additional widgets and layouts module.
        'oojs-ui-widgets' => [
                'class' => ResourceLoaderOOUIFileModule::class,
@@ -2926,11 +2929,7 @@ return [
                'themeStyles' => 'widgets',
                'dependencies' => [
                        'oojs-ui-core',
-                       'oojs-ui.styles.icons-interactions',
-                       'oojs-ui.styles.icons-content',
-                       'oojs-ui.styles.icons-editing-advanced',
-                       'oojs-ui.styles.icons-movement',
-                       'oojs-ui.styles.icons-moderation',
+                       'oojs-ui-widgets.icons',
                ],
                'messages' => [
                        'ooui-item-remove',
@@ -2952,6 +2951,12 @@ return [
                'themeStyles' => 'widgets',
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'oojs-ui-widgets.icons' => [
+               'class' => ResourceLoaderOOUIIconPackModule::class,
+               // Do not repeat icons already used in 'oojs-ui-core.icons'
+               'icons' => [ 'attachment', 'collapse', 'expand', 'trash', 'upload' ],
+               'targets' => [ 'desktop', 'mobile' ],
+       ],
        // Toolbar and tools module.
        'oojs-ui-toolbars' => [
                'class' => ResourceLoaderOOUIFileModule::class,
@@ -2959,7 +2964,7 @@ return [
                'themeStyles' => 'toolbars',
                'dependencies' => [
                        'oojs-ui-core',
-                       'oojs-ui.styles.icons-movement',
+                       'oojs-ui-toolbars.icons',
                ],
                'messages' => [
                        'ooui-toolbar-more',
@@ -2968,6 +2973,12 @@ return [
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'oojs-ui-toolbars.icons' => [
+               'class' => ResourceLoaderOOUIIconPackModule::class,
+               // Do not repeat icons already used in 'oojs-ui-core.icons': 'check'
+               'icons' => [ 'collapse', 'expand' ],
+               'targets' => [ 'desktop', 'mobile' ],
+       ],
        // Windows and dialogs module.
        'oojs-ui-windows' => [
                'class' => ResourceLoaderOOUIFileModule::class,
@@ -2975,7 +2986,7 @@ return [
                'themeStyles' => 'windows',
                'dependencies' => [
                        'oojs-ui-core',
-                       'oojs-ui.styles.icons-movement',
+                       'oojs-ui-windows.icons',
                ],
                'messages' => [
                        'ooui-dialog-message-accept',
@@ -2987,6 +2998,12 @@ return [
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
+       'oojs-ui-windows.icons' => [
+               'class' => ResourceLoaderOOUIIconPackModule::class,
+               // Do not repeat icons already used in 'oojs-ui-core.icons': 'close'
+               'icons' => [ 'previous' ],
+               'targets' => [ 'desktop', 'mobile' ],
+       ],
 
        'oojs-ui.styles.indicators' => [
                'class' => ResourceLoaderOOUIImageModule::class,