From a8dae2212cc5e23e181023af2ba1891078b14355 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Mon, 12 Feb 2018 20:41:44 +0100 Subject: [PATCH] Allow loading styles for arbitrary OOUI icon packs 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 | 1 + includes/OutputPage.php | 4 +- .../ResourceLoaderOOUIIconPackModule.php | 72 +++++++++++++++ .../ResourceLoaderOOUIImageModule.php | 88 +++++++++++++------ resources/Resources.php | 37 +++++--- 5 files changed, 161 insertions(+), 41 deletions(-) create mode 100644 includes/resourceloader/ResourceLoaderOOUIIconPackModule.php diff --git a/autoload.php b/autoload.php index eb8ba09dd8..b26549e137 100644 --- a/autoload.php +++ b/autoload.php @@ -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', diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 54b3ee5f68..5227aa10da 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -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 index 0000000000..0c70ee1266 --- /dev/null +++ b/includes/resourceloader/ResourceLoaderOOUIIconPackModule.php @@ -0,0 +1,72 @@ +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; + } +} diff --git a/includes/resourceloader/ResourceLoaderOOUIImageModule.php b/includes/resourceloader/ResourceLoaderOOUIImageModule.php index 313d789249..34079c3b7b 100644 --- a/includes/resourceloader/ResourceLoaderOOUIImageModule.php +++ b/includes/resourceloader/ResourceLoaderOOUIImageModule.php @@ -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; + } } diff --git a/resources/Resources.php b/resources/Resources.php index ece1c90bd1..b90ead4c45 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -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, -- 2.20.1