From 77f4bab8b749ed43438cc77dd6b2330ef0f99b8a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Fri, 17 Mar 2017 03:14:05 +0100 Subject: [PATCH] Allow skins/extensions to define custom OOUI themes This change follows I39cc2a735d9625c87bf4ede6f5fb0ec441d47dcc. docs/extension.schema.v1.json docs/extension.schema.v2.json includes/registration/ExtensionProcessor.php * The new extension attribute 'OOUIThemePaths' can be used to define custom OOUI themes. See I9187a63e509b601b8558ea82850fa828e5c8cc0a for an example usage. includes/resourceloader/ResourceLoaderOOUIModule.php * Add support for 'OOUIThemePaths'. * Defining 'images' is now optional. I figure custom themes are unlikely to have or need them. * Use ResourceLoaderFilePath objects to allow skin-/extension-defined OOUI module files to use skin/extension's base paths. This was previously used to support $wgResourceModuleSkinStyles, but only for 'skinStyles' - now ResourceLoaderFileModule needs to also handle it for 'skinScripts', and ResourceLoaderImageModule for 'images'). includes/resourceloader/ResourceLoaderFilePath.php * Add getters for local/remote base paths, for when we need to construct a new ResourceLoaderFilePath based on existing one. includes/resourceloader/ResourceLoaderFileModule.php includes/resourceloader/ResourceLoaderImageModule.php includes/resourceloader/ResourceLoaderOOUIImageModule.php * Add or improve handling of ResourceLoaderFilePaths: * Replace `(array)` casts with explicit array wrapping, to avoid casting objects into associative arrays. * Use getLocalPath() instead of string concatenation. tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php * Some basic checks for the above. Bug: T100896 Change-Id: I74362f0fc215b26f1f104ce7bdbbac1e106736ad --- docs/extension.schema.v1.json | 24 +++++++++ docs/extension.schema.v2.json | 24 +++++++++ includes/registration/ExtensionProcessor.php | 9 +++- .../ResourceLoaderFileModule.php | 22 +++++++-- .../resourceloader/ResourceLoaderFilePath.php | 14 ++++++ .../resourceloader/ResourceLoaderImage.php | 28 ++++++++--- .../ResourceLoaderImageModule.php | 16 +++++- .../ResourceLoaderOOUIImageModule.php | 15 +++++- .../ResourceLoaderOOUIModule.php | 40 ++++++++++++--- tests/phpunit/data/rlfilepath/eye.svg | 1 + tests/phpunit/data/rlfilepath/flag-ltr.svg | 1 + tests/phpunit/data/rlfilepath/flag-rtl.svg | 1 + tests/phpunit/data/rlfilepath/script.js | 1 + tests/phpunit/data/rlfilepath/skinStyle.css | 3 ++ tests/phpunit/data/rlfilepath/style.css | 3 ++ tests/phpunit/data/rlfilepath/template.html | 1 + .../ResourceLoaderFileModuleTest.php | 41 ++++++++++++++++ .../ResourceLoaderImageModuleTest.php | 49 +++++++++++++++++++ 18 files changed, 268 insertions(+), 25 deletions(-) create mode 100644 tests/phpunit/data/rlfilepath/eye.svg create mode 100644 tests/phpunit/data/rlfilepath/flag-ltr.svg create mode 100644 tests/phpunit/data/rlfilepath/flag-rtl.svg create mode 100644 tests/phpunit/data/rlfilepath/script.js create mode 100644 tests/phpunit/data/rlfilepath/skinStyle.css create mode 100644 tests/phpunit/data/rlfilepath/style.css create mode 100644 tests/phpunit/data/rlfilepath/template.html diff --git a/docs/extension.schema.v1.json b/docs/extension.schema.v1.json index 86fa1b3da8..9ce016f063 100644 --- a/docs/extension.schema.v1.json +++ b/docs/extension.schema.v1.json @@ -730,6 +730,30 @@ "SkinOOUIThemes": { "type": "object" }, + "OOUIThemePaths": { + "type": "object", + "description": "Map of custom OOUI theme names to paths to load them from. Same format as ResourceLoaderOOUIModule::$builtinThemePaths.", + "patternProperties": { + "^[A-Za-z]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "scripts": { + "type": "string", + "description": "Path to script file." + }, + "styles": { + "type": "string", + "description": "Path to style files. '{module}' will be replaced with the module's name." + }, + "images": { + "type": [ "string", "null" ], + "description": "Path to images (optional). '{module}' will be replaced with the module's name." + } + } + } + } + }, "PasswordPolicy": { "type": "object", "description": "Password policies" diff --git a/docs/extension.schema.v2.json b/docs/extension.schema.v2.json index c1db2b6e4a..9d874f47f4 100644 --- a/docs/extension.schema.v2.json +++ b/docs/extension.schema.v2.json @@ -801,6 +801,30 @@ "type": "object", "description": "Map of skin names to OOUI themes to use. Same format as ResourceLoaderOOUIModule::$builtinSkinThemeMap." }, + "OOUIThemePaths": { + "type": "object", + "description": "Map of custom OOUI theme names to paths to load them from. Same format as ResourceLoaderOOUIModule::$builtinThemePaths.", + "patternProperties": { + "^[A-Za-z]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "scripts": { + "type": "string", + "description": "Path to script file." + }, + "styles": { + "type": "string", + "description": "Path to style files. '{module}' will be replaced with the module's name." + }, + "images": { + "type": [ "string", "null" ], + "description": "Path to images (optional). '{module}' will be replaced with the module's name." + } + } + } + } + }, "PasswordPolicy": { "type": "object", "description": "Password policies" diff --git a/includes/registration/ExtensionProcessor.php b/includes/registration/ExtensionProcessor.php index e71de849c6..6182d5fdc4 100644 --- a/includes/registration/ExtensionProcessor.php +++ b/includes/registration/ExtensionProcessor.php @@ -120,6 +120,7 @@ class ExtensionProcessor implements Processor { 'ResourceFileModulePaths', 'ResourceModules', 'ResourceModuleSkinStyles', + 'OOUIThemePaths', 'QUnitTestModule', 'ExtensionMessagesFiles', 'MessagesDirs', @@ -445,7 +446,7 @@ class ExtensionProcessor implements Processor { } } - foreach ( [ 'ResourceModules', 'ResourceModuleSkinStyles' ] as $setting ) { + foreach ( [ 'ResourceModules', 'ResourceModuleSkinStyles', 'OOUIThemePaths' ] as $setting ) { if ( isset( $info[$setting] ) ) { foreach ( $info[$setting] as $name => $data ) { if ( isset( $data['localBasePath'] ) ) { @@ -459,7 +460,11 @@ class ExtensionProcessor implements Processor { if ( $defaultPaths ) { $data += $defaultPaths; } - $this->globals["wg$setting"][$name] = $data; + if ( $setting === 'OOUIThemePaths' ) { + $this->attributes[$setting][$name] = $data; + } else { + $this->globals["wg$setting"][$name] = $data; + } } } } diff --git a/includes/resourceloader/ResourceLoaderFileModule.php b/includes/resourceloader/ResourceLoaderFileModule.php index 017b39934e..fbc59fe0f4 100644 --- a/includes/resourceloader/ResourceLoaderFileModule.php +++ b/includes/resourceloader/ResourceLoaderFileModule.php @@ -256,11 +256,11 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { case 'debugScripts': case 'styles': case 'packageFiles': - $this->{$member} = (array)$option; + $this->{$member} = is_array( $option ) ? $option : [ $option ]; break; case 'templates': $hasTemplates = true; - $this->{$member} = (array)$option; + $this->{$member} = is_array( $option ) ? $option : [ $option ]; break; // Collated lists of file paths case 'languageScripts': @@ -279,7 +279,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { "'$key' given, string expected." ); } - $this->{$member}[$key] = (array)$value; + $this->{$member}[$key] = is_array( $value ) ? $value : [ $value ]; } break; case 'deprecated': @@ -315,7 +315,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { // Ensure relevant template compiler module gets loaded foreach ( $this->templates as $alias => $templatePath ) { if ( is_int( $alias ) ) { - $alias = $templatePath; + $alias = $this->getPath( $templatePath ); } $suffix = explode( '.', $alias ); $suffix = end( $suffix ); @@ -643,6 +643,18 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { return $summary; } + /** + * @param string|ResourceLoaderFilePath $path + * @return string + */ + protected function getPath( $path ) { + if ( $path instanceof ResourceLoaderFilePath ) { + return $path->getPath(); + } + + return $path; + } + /** * @param string|ResourceLoaderFilePath $path * @return string @@ -1060,7 +1072,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { foreach ( $this->templates as $alias => $templatePath ) { // Alias is optional if ( is_int( $alias ) ) { - $alias = $templatePath; + $alias = $this->getPath( $templatePath ); } $localPath = $this->getLocalPath( $templatePath ); if ( file_exists( $localPath ) ) { diff --git a/includes/resourceloader/ResourceLoaderFilePath.php b/includes/resourceloader/ResourceLoaderFilePath.php index 3cf09d82e1..c01e507455 100644 --- a/includes/resourceloader/ResourceLoaderFilePath.php +++ b/includes/resourceloader/ResourceLoaderFilePath.php @@ -62,6 +62,20 @@ class ResourceLoaderFilePath { return "{$this->remoteBasePath}/{$this->path}"; } + /** + * @return string + */ + public function getLocalBasePath() { + return $this->localBasePath; + } + + /** + * @return string + */ + public function getRemoteBasePath() { + return $this->remoteBasePath; + } + /** * @return string */ diff --git a/includes/resourceloader/ResourceLoaderImage.php b/includes/resourceloader/ResourceLoaderImage.php index c1b3dc34ca..5b39fc7bab 100644 --- a/includes/resourceloader/ResourceLoaderImage.php +++ b/includes/resourceloader/ResourceLoaderImage.php @@ -95,9 +95,9 @@ class ResourceLoaderImage { // Ensure that all files have common extension. $extensions = []; - $descriptor = (array)$this->descriptor; + $descriptor = is_array( $this->descriptor ) ? $this->descriptor : [ $this->descriptor ]; array_walk_recursive( $descriptor, function ( $path ) use ( &$extensions ) { - $extensions[] = pathinfo( $path, PATHINFO_EXTENSION ); + $extensions[] = pathinfo( $this->getLocalPath( $path ), PATHINFO_EXTENSION ); } ); $extensions = array_unique( $extensions ); if ( count( $extensions ) !== 1 ) { @@ -150,31 +150,43 @@ class ResourceLoaderImage { */ public function getPath( ResourceLoaderContext $context ) { $desc = $this->descriptor; - if ( is_string( $desc ) ) { - return $this->basePath . '/' . $desc; + if ( !is_array( $desc ) ) { + return $this->getLocalPath( $desc ); } if ( isset( $desc['lang'] ) ) { $contextLang = $context->getLanguage(); if ( isset( $desc['lang'][$contextLang] ) ) { - return $this->basePath . '/' . $desc['lang'][$contextLang]; + return $this->getLocalPath( $desc['lang'][$contextLang] ); } $fallbacks = Language::getFallbacksFor( $contextLang, Language::STRICT_FALLBACKS ); foreach ( $fallbacks as $lang ) { if ( isset( $desc['lang'][$lang] ) ) { - return $this->basePath . '/' . $desc['lang'][$lang]; + return $this->getLocalPath( $desc['lang'][$lang] ); } } } if ( isset( $desc[$context->getDirection()] ) ) { - return $this->basePath . '/' . $desc[$context->getDirection()]; + return $this->getLocalPath( $desc[$context->getDirection()] ); } if ( isset( $desc['default'] ) ) { - return $this->basePath . '/' . $desc['default']; + return $this->getLocalPath( $desc['default'] ); } else { throw new MWException( 'No matching path found' ); } } + /** + * @param string|ResourceLoaderFilePath $path + * @return string + */ + protected function getLocalPath( $path ) { + if ( $path instanceof ResourceLoaderFilePath ) { + return $path->getLocalPath(); + } + + return "{$this->basePath}/$path"; + } + /** * Get the extension of the image. * diff --git a/includes/resourceloader/ResourceLoaderImageModule.php b/includes/resourceloader/ResourceLoaderImageModule.php index 90b18ebd9c..902fa91b79 100644 --- a/includes/resourceloader/ResourceLoaderImageModule.php +++ b/includes/resourceloader/ResourceLoaderImageModule.php @@ -130,7 +130,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule { $this->definition = null; if ( isset( $options['data'] ) ) { - $dataPath = $this->localBasePath . '/' . $options['data']; + $dataPath = $this->getLocalPath( $options['data'] ); $data = json_decode( file_get_contents( $dataPath ), true ); $options = array_merge( $data, $options ); } @@ -259,7 +259,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule { $this->images[$skin] = $this->images['default'] ?? []; } foreach ( $this->images[$skin] as $name => $options ) { - $fileDescriptor = is_string( $options ) ? $options : $options['file']; + $fileDescriptor = is_array( $options ) ? $options['file'] : $options; $allowedVariants = array_merge( ( is_array( $options ) && isset( $options['variants'] ) ) ? $options['variants'] : [], @@ -452,6 +452,18 @@ class ResourceLoaderImageModule extends ResourceLoaderModule { return array_map( [ __CLASS__, 'safeFileHash' ], $files ); } + /** + * @param string|ResourceLoaderFilePath $path + * @return string + */ + protected function getLocalPath( $path ) { + if ( $path instanceof ResourceLoaderFilePath ) { + return $path->getLocalPath(); + } + + return "{$this->localBasePath}/$path"; + } + /** * Extract a local base path from module definition information. * diff --git a/includes/resourceloader/ResourceLoaderOOUIImageModule.php b/includes/resourceloader/ResourceLoaderOOUIImageModule.php index 34079c3b7b..c6d4cdfde3 100644 --- a/includes/resourceloader/ResourceLoaderOOUIImageModule.php +++ b/includes/resourceloader/ResourceLoaderOOUIImageModule.php @@ -97,6 +97,9 @@ class ResourceLoaderOOUIImageModule extends ResourceLoaderImageModule { // Find the path to the JSON file which contains the actual image definitions for this theme if ( $module ) { $dataPath = $this->getThemeImagesPath( $theme, $module ); + if ( !$dataPath ) { + return false; + } } else { // Backwards-compatibility for things that probably shouldn't have used this class... $dataPath = @@ -116,7 +119,7 @@ class ResourceLoaderOOUIImageModule extends ResourceLoaderImageModule { * @return array|false */ protected function readJSONFile( $dataPath ) { - $localDataPath = $this->localBasePath . '/' . $dataPath; + $localDataPath = $this->getLocalPath( $dataPath ); if ( !file_exists( $localDataPath ) ) { return false; @@ -127,7 +130,15 @@ class ResourceLoaderOOUIImageModule extends ResourceLoaderImageModule { // 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; + if ( $dataPath instanceof ResourceLoaderFilePath ) { + $path = new ResourceLoaderFilePath( + dirname( $dataPath->getPath() ) . '/' . $path, + $dataPath->getLocalBasePath(), + $dataPath->getRemoteBasePath() + ); + } else { + $path = dirname( $dataPath ) . '/' . $path; + } }; array_walk( $data['images'], function ( &$value ) use ( $fixPath ) { if ( is_string( $value['file'] ) ) { diff --git a/includes/resourceloader/ResourceLoaderOOUIModule.php b/includes/resourceloader/ResourceLoaderOOUIModule.php index 899fbbde72..fdcc2135e2 100644 --- a/includes/resourceloader/ResourceLoaderOOUIModule.php +++ b/includes/resourceloader/ResourceLoaderOOUIModule.php @@ -82,7 +82,7 @@ trait ResourceLoaderOOUIModule { * Return a map of theme names to lists of paths from which a given theme should be loaded. * * Keys are theme names, values are associative arrays. Keys of the inner array are 'scripts', - * 'styles', or 'images', and values are string paths. + * 'styles', or 'images', and values are paths. Paths may be strings or ResourceLoaderFilePaths. * * Additionally, the string '{module}' in paths represents the name of the module to load. * @@ -90,29 +90,57 @@ trait ResourceLoaderOOUIModule { */ protected static function getThemePaths() { $themePaths = self::$builtinThemePaths; + $themePaths += ExtensionRegistry::getInstance()->getAttribute( 'OOUIThemePaths' ); + + list( $defaultLocalBasePath, $defaultRemoteBasePath ) = + ResourceLoaderFileModule::extractBasePaths(); + + // Allow custom themes' paths to be relative to the skin/extension that defines them, + // like with ResourceModuleSkinStyles + foreach ( $themePaths as $theme => &$paths ) { + list( $localBasePath, $remoteBasePath ) = + ResourceLoaderFileModule::extractBasePaths( $paths ); + if ( $localBasePath !== $defaultLocalBasePath || $remoteBasePath !== $defaultRemoteBasePath ) { + foreach ( $paths as &$path ) { + $path = new ResourceLoaderFilePath( $path, $localBasePath, $remoteBasePath ); + } + } + } + return $themePaths; } /** * Return a path to load given module of given theme from. * + * The file at this path may not exist. This should be handled by the caller (throwing an error or + * falling back to default theme). + * * @param string $theme OOUI theme name, for example 'WikimediaUI' or 'Apex' * @param string $kind Kind of the module: 'scripts', 'styles', or 'images' * @param string $module Module name, for valid values see $knownScriptsModules, * $knownStylesModules, $knownImagesModules - * @return string + * @return string|ResourceLoaderFilePath */ protected function getThemePath( $theme, $kind, $module ) { $paths = self::getThemePaths(); $path = $paths[$theme][$kind]; - $path = str_replace( '{module}', $module, $path ); + if ( $path instanceof ResourceLoaderFilePath ) { + $path = new ResourceLoaderFilePath( + str_replace( '{module}', $module, $path->getPath() ), + $path->getLocalBasePath(), + $path->getRemoteBasePath() + ); + } else { + $path = str_replace( '{module}', $module, $path ); + } return $path; } /** * @param string $theme See getThemePath() * @param string $module See getThemePath() - * @return string + * @return string|ResourceLoaderFilePath */ protected function getThemeScriptsPath( $theme, $module ) { if ( !in_array( $module, self::$knownScriptsModules ) ) { @@ -124,7 +152,7 @@ trait ResourceLoaderOOUIModule { /** * @param string $theme See getThemePath() * @param string $module See getThemePath() - * @return string + * @return string|ResourceLoaderFilePath */ protected function getThemeStylesPath( $theme, $module ) { if ( !in_array( $module, self::$knownStylesModules ) ) { @@ -136,7 +164,7 @@ trait ResourceLoaderOOUIModule { /** * @param string $theme See getThemePath() * @param string $module See getThemePath() - * @return string + * @return string|ResourceLoaderFilePath */ protected function getThemeImagesPath( $theme, $module ) { if ( !in_array( $module, self::$knownImagesModules ) ) { diff --git a/tests/phpunit/data/rlfilepath/eye.svg b/tests/phpunit/data/rlfilepath/eye.svg new file mode 100644 index 0000000000..be0c4e69d0 --- /dev/null +++ b/tests/phpunit/data/rlfilepath/eye.svg @@ -0,0 +1 @@ +eye \ No newline at end of file diff --git a/tests/phpunit/data/rlfilepath/flag-ltr.svg b/tests/phpunit/data/rlfilepath/flag-ltr.svg new file mode 100644 index 0000000000..d19bed5371 --- /dev/null +++ b/tests/phpunit/data/rlfilepath/flag-ltr.svg @@ -0,0 +1 @@ +flag \ No newline at end of file diff --git a/tests/phpunit/data/rlfilepath/flag-rtl.svg b/tests/phpunit/data/rlfilepath/flag-rtl.svg new file mode 100644 index 0000000000..a58bb92420 --- /dev/null +++ b/tests/phpunit/data/rlfilepath/flag-rtl.svg @@ -0,0 +1 @@ +flag \ No newline at end of file diff --git a/tests/phpunit/data/rlfilepath/script.js b/tests/phpunit/data/rlfilepath/script.js new file mode 100644 index 0000000000..f5d7aa52ab --- /dev/null +++ b/tests/phpunit/data/rlfilepath/script.js @@ -0,0 +1 @@ +mw.test(); diff --git a/tests/phpunit/data/rlfilepath/skinStyle.css b/tests/phpunit/data/rlfilepath/skinStyle.css new file mode 100644 index 0000000000..575d19f7b0 --- /dev/null +++ b/tests/phpunit/data/rlfilepath/skinStyle.css @@ -0,0 +1,3 @@ +body { + color: red; +} diff --git a/tests/phpunit/data/rlfilepath/style.css b/tests/phpunit/data/rlfilepath/style.css new file mode 100644 index 0000000000..e87cc6abcd --- /dev/null +++ b/tests/phpunit/data/rlfilepath/style.css @@ -0,0 +1,3 @@ +body { + color: black; +} diff --git a/tests/phpunit/data/rlfilepath/template.html b/tests/phpunit/data/rlfilepath/template.html new file mode 100644 index 0000000000..7c89b545c5 --- /dev/null +++ b/tests/phpunit/data/rlfilepath/template.html @@ -0,0 +1 @@ +
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php index 5be0f9b79f..a9e7fcfd32 100644 --- a/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php @@ -265,6 +265,47 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase { ); } + /** + * Test reading files from elsewhere than localBasePath using ResourceLoaderFilePath. + * + * This mimics modules modified by skins using 'ResourceModuleSkinStyles' and 'OOUIThemePaths' + * skin attributes. + * + * @covers ResourceLoaderFilePath::getLocalBasePath + * @covers ResourceLoaderFilePath::getRemoteBasePath + */ + public function testResourceLoaderFilePath() { + $basePath = __DIR__ . '/../../data/blahblah'; + $filePath = __DIR__ . '/../../data/rlfilepath'; + $testModule = new ResourceLoaderFileModule( [ + 'localBasePath' => $basePath, + 'remoteBasePath' => 'blahblah', + 'styles' => new ResourceLoaderFilePath( 'style.css', $filePath, 'rlfilepath' ), + 'skinStyles' => [ + 'vector' => new ResourceLoaderFilePath( 'skinStyle.css', $filePath, 'rlfilepath' ), + ], + 'scripts' => new ResourceLoaderFilePath( 'script.js', $filePath, 'rlfilepath' ), + 'templates' => new ResourceLoaderFilePath( 'template.html', $filePath, 'rlfilepath' ), + ] ); + $expectedModule = new ResourceLoaderFileModule( [ + 'localBasePath' => $filePath, + 'remoteBasePath' => 'rlfilepath', + 'styles' => 'style.css', + 'skinStyles' => [ + 'vector' => 'skinStyle.css', + ], + 'scripts' => 'script.js', + 'templates' => 'template.html', + ] ); + + $context = $this->getResourceLoaderContext(); + $this->assertEquals( + $expectedModule->getModuleContent( $context ), + $testModule->getModuleContent( $context ), + "Using ResourceLoaderFilePath works correctly" + ); + } + public static function providerGetTemplates() { $modules = self::getModules(); diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php index 3f5704d6f4..dad9f1ed4f 100644 --- a/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php @@ -144,6 +144,55 @@ class ResourceLoaderImageModuleTest extends ResourceLoaderTestCase { ]; } + /** + * Test reading files from elsewhere than localBasePath using ResourceLoaderFilePath. + * + * This mimics modules modified by skins using 'ResourceModuleSkinStyles' and 'OOUIThemePaths' + * skin attributes. + * + * @covers ResourceLoaderFilePath::getLocalBasePath + * @covers ResourceLoaderFilePath::getRemoteBasePath + */ + public function testResourceLoaderFilePath() { + $basePath = __DIR__ . '/../../data/blahblah'; + $filePath = __DIR__ . '/../../data/rlfilepath'; + $testModule = new ResourceLoaderImageModule( [ + 'localBasePath' => $basePath, + 'remoteBasePath' => 'blahblah', + 'prefix' => 'foo', + 'images' => [ + 'eye' => new ResourceLoaderFilePath( 'eye.svg', $filePath, 'rlfilepath' ), + 'flag' => [ + 'file' => [ + 'ltr' => new ResourceLoaderFilePath( 'flag-ltr.svg', $filePath, 'rlfilepath' ), + 'rtl' => new ResourceLoaderFilePath( 'flag-rtl.svg', $filePath, 'rlfilepath' ), + ], + ], + ], + ] ); + $expectedModule = new ResourceLoaderImageModule( [ + 'localBasePath' => $filePath, + 'remoteBasePath' => 'rlfilepath', + 'prefix' => 'foo', + 'images' => [ + 'eye' => 'eye.svg', + 'flag' => [ + 'file' => [ + 'ltr' => 'flag-ltr.svg', + 'rtl' => 'flag-rtl.svg', + ], + ], + ], + ] ); + + $context = $this->getResourceLoaderContext(); + $this->assertEquals( + $expectedModule->getModuleContent( $context ), + $testModule->getModuleContent( $context ), + "Using ResourceLoaderFilePath works correctly" + ); + } + /** * @dataProvider providerGetModules * @covers ResourceLoaderImageModule::getStyles -- 2.20.1