ResourceLoaderSkinModule: Provide optional mediawiki.skinning styles
All mediawiki.skinning modules are repurposed as variants of the ResourceLoaderSkinModule and those ResourceLoader modules are marked for deprecation. Skins will now be encouraged to use the ResourceLoaderSkinModule class themselves as part of their own style module rather than using a module defined in core. Bug: T118134 Bug: T114695 Change-Id: I4bc8b9b4da1c16eed34f3a517ec695019381e764
This commit is contained in:
parent
c2c789cc59
commit
6845912bcf
3 changed files with 131 additions and 74 deletions
|
|
@ -30,6 +30,95 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
|
||||||
*/
|
*/
|
||||||
public $targets = [ 'desktop', 'mobile' ];
|
public $targets = [ 'desktop', 'mobile' ];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every skin should define which features it would like to reuse for core inside a
|
||||||
|
* ResourceLoader module that has set the class to ResourceLoaderSkinModule.
|
||||||
|
* For a feature to be valid it must be listed here along with the associated resources
|
||||||
|
*
|
||||||
|
* The following features are available:
|
||||||
|
*
|
||||||
|
* "logo":
|
||||||
|
* Adds CSS to style an element with class `mw-wiki-logo` using the value of wgLogo.
|
||||||
|
* This is enabled by default if no features are added.
|
||||||
|
*
|
||||||
|
* "elements":
|
||||||
|
* The base level that only contains the most basic of common skin styles.
|
||||||
|
* Only styles for single elements are included, no styling for complex structures like the
|
||||||
|
* TOC is present. This level is for skins that want to implement the entire style of even
|
||||||
|
* content area structures like the TOC themselves.
|
||||||
|
*
|
||||||
|
* "content":
|
||||||
|
* The most commonly used level for skins implemented from scratch. This level includes all
|
||||||
|
* the single element styles from "elements" as well as styles for complex structures such
|
||||||
|
* as the TOC that are output in the content area by MediaWiki rather than the skin.
|
||||||
|
* Essentially this is the common level that lets skins leave the style of the content area
|
||||||
|
* as it is normally styled, while leaving the rest of the skin up to the skin
|
||||||
|
* implementation.
|
||||||
|
*
|
||||||
|
* "interface":
|
||||||
|
* The highest level, this stylesheet contains extra common styles for classes like
|
||||||
|
* .firstHeading, #contentSub, et cetera which are not outputted by MediaWiki but are common
|
||||||
|
* to skins like MonoBook, Vector, etc... Essentially this level is for styles that are
|
||||||
|
* common to MonoBook clones.
|
||||||
|
*/
|
||||||
|
private const FEATURE_FILES = [
|
||||||
|
'logo' => [],
|
||||||
|
'content' => [
|
||||||
|
'screen' => [ 'resources/src/mediawiki.skinning/content.css' ],
|
||||||
|
],
|
||||||
|
'interface' => [
|
||||||
|
'screen' => [ 'resources/src/mediawiki.skinning/interface.css' ],
|
||||||
|
],
|
||||||
|
'elements' => [
|
||||||
|
'screen' => [ 'resources/src/mediawiki.skinning/elements.css' ],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
|
private $features;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
array $options = [],
|
||||||
|
$localBasePath = null,
|
||||||
|
$remoteBasePath = null
|
||||||
|
) {
|
||||||
|
parent::__construct( $options, $localBasePath, $remoteBasePath );
|
||||||
|
$this->features = $options['features'] ?? [ 'logo' ];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get styles defined in the module definition, plus any enabled feature styles.
|
||||||
|
*
|
||||||
|
* @param ResourceLoaderContext $context
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getStyleFiles( ResourceLoaderContext $context ) {
|
||||||
|
$styles = parent::getStyleFiles( $context );
|
||||||
|
|
||||||
|
list( $defaultLocalBasePath, $defaultRemoteBasePath ) =
|
||||||
|
ResourceLoaderFileModule::extractBasePaths();
|
||||||
|
|
||||||
|
foreach ( $this->features as $feature ) {
|
||||||
|
if ( !isset( self::FEATURE_FILES[$feature] ) ) {
|
||||||
|
throw new InvalidArgumentException( "Feature `$feature` is not recognised" );
|
||||||
|
}
|
||||||
|
foreach ( self::FEATURE_FILES[$feature] as $mediaType => $files ) {
|
||||||
|
if ( !isset( $styles[$mediaType] ) ) {
|
||||||
|
$styles[$mediaType] = [];
|
||||||
|
}
|
||||||
|
foreach ( $files as $filepath ) {
|
||||||
|
$styles[$mediaType][] = new ResourceLoaderFilePath(
|
||||||
|
$filepath,
|
||||||
|
$defaultLocalBasePath,
|
||||||
|
$defaultRemoteBasePath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $styles;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ResourceLoaderContext $context
|
* @param ResourceLoaderContext $context
|
||||||
* @return array
|
* @return array
|
||||||
|
|
@ -39,39 +128,41 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
|
||||||
$styles = parent::getStyles( $context );
|
$styles = parent::getStyles( $context );
|
||||||
$this->normalizeStyles( $styles );
|
$this->normalizeStyles( $styles );
|
||||||
|
|
||||||
$default = !is_array( $logo ) ? $logo : $logo['1x'];
|
$isLogoFeatureEnabled = in_array( 'logo', $this->features );
|
||||||
$styles['all'][] = '.mw-wiki-logo { background-image: ' .
|
if ( $isLogoFeatureEnabled ) {
|
||||||
|
$default = !is_array( $logo ) ? $logo : $logo['1x'];
|
||||||
|
$styles['all'][] = '.mw-wiki-logo { background-image: ' .
|
||||||
CSSMin::buildUrlValue( $default ) .
|
CSSMin::buildUrlValue( $default ) .
|
||||||
'; }';
|
'; }';
|
||||||
|
if ( is_array( $logo ) ) {
|
||||||
if ( is_array( $logo ) ) {
|
if ( isset( $logo['svg'] ) ) {
|
||||||
if ( isset( $logo['svg'] ) ) {
|
$styles['all'][] = '.mw-wiki-logo { ' .
|
||||||
$styles['all'][] = '.mw-wiki-logo { ' .
|
'background-image: -webkit-linear-gradient(transparent, transparent), ' .
|
||||||
'background-image: -webkit-linear-gradient(transparent, transparent), ' .
|
CSSMin::buildUrlValue( $logo['svg'] ) . '; ' .
|
||||||
CSSMin::buildUrlValue( $logo['svg'] ) . '; ' .
|
'background-image: linear-gradient(transparent, transparent), ' .
|
||||||
'background-image: linear-gradient(transparent, transparent), ' .
|
CSSMin::buildUrlValue( $logo['svg'] ) . ';' .
|
||||||
CSSMin::buildUrlValue( $logo['svg'] ) . ';' .
|
'background-size: 135px auto; }';
|
||||||
'background-size: 135px auto; }';
|
} else {
|
||||||
} else {
|
if ( isset( $logo['1.5x'] ) ) {
|
||||||
if ( isset( $logo['1.5x'] ) ) {
|
$styles[
|
||||||
$styles[
|
'(-webkit-min-device-pixel-ratio: 1.5), ' .
|
||||||
'(-webkit-min-device-pixel-ratio: 1.5), ' .
|
'(min--moz-device-pixel-ratio: 1.5), ' .
|
||||||
'(min--moz-device-pixel-ratio: 1.5), ' .
|
'(min-resolution: 1.5dppx), ' .
|
||||||
'(min-resolution: 1.5dppx), ' .
|
'(min-resolution: 144dpi)'
|
||||||
'(min-resolution: 144dpi)'
|
][] = '.mw-wiki-logo { background-image: ' .
|
||||||
][] = '.mw-wiki-logo { background-image: ' .
|
CSSMin::buildUrlValue( $logo['1.5x'] ) . ';' .
|
||||||
CSSMin::buildUrlValue( $logo['1.5x'] ) . ';' .
|
'background-size: 135px auto; }';
|
||||||
'background-size: 135px auto; }';
|
}
|
||||||
}
|
if ( isset( $logo['2x'] ) ) {
|
||||||
if ( isset( $logo['2x'] ) ) {
|
$styles[
|
||||||
$styles[
|
'(-webkit-min-device-pixel-ratio: 2), ' .
|
||||||
'(-webkit-min-device-pixel-ratio: 2), ' .
|
'(min--moz-device-pixel-ratio: 2), ' .
|
||||||
'(min--moz-device-pixel-ratio: 2), ' .
|
'(min-resolution: 2dppx), ' .
|
||||||
'(min-resolution: 2dppx), ' .
|
'(min-resolution: 192dpi)'
|
||||||
'(min-resolution: 192dpi)'
|
][] = '.mw-wiki-logo { background-image: ' .
|
||||||
][] = '.mw-wiki-logo { background-image: ' .
|
CSSMin::buildUrlValue( $logo['2x'] ) . ';' .
|
||||||
CSSMin::buildUrlValue( $logo['2x'] ) . ';' .
|
'background-size: 135px auto; }';
|
||||||
'background-size: 135px auto; }';
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,55 +50,22 @@ return [
|
||||||
'user.options' => [ 'class' => ResourceLoaderUserOptionsModule::class ],
|
'user.options' => [ 'class' => ResourceLoaderUserOptionsModule::class ],
|
||||||
'user.tokens' => [ 'class' => ResourceLoaderUserTokensModule::class ],
|
'user.tokens' => [ 'class' => ResourceLoaderUserTokensModule::class ],
|
||||||
|
|
||||||
/* MediaWiki base skinning modules */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common skin styles, grouped into three graded levels.
|
|
||||||
*
|
|
||||||
* Level 1 "elements":
|
|
||||||
* The base level that only contains the most basic of common skin styles.
|
|
||||||
* Only styles for single elements are included, no styling for complex structures like the
|
|
||||||
* TOC is present. This level is for skins that want to implement the entire style of even
|
|
||||||
* content area structures like the TOC themselves.
|
|
||||||
*
|
|
||||||
* Level 2 "content":
|
|
||||||
* The most commonly used level for skins implemented from scratch. This level includes all
|
|
||||||
* the single element styles from "elements" as well as styles for complex structures such
|
|
||||||
* as the TOC that are output in the content area by MediaWiki rather than the skin.
|
|
||||||
* Essentially this is the common level that lets skins leave the style of the content area
|
|
||||||
* as it is normally styled, while leaving the rest of the skin up to the skin
|
|
||||||
* implementation.
|
|
||||||
*
|
|
||||||
* Level 3 "interface":
|
|
||||||
* The highest level, this stylesheet contains extra common styles for classes like
|
|
||||||
* .firstHeading, #contentSub, et cetera which are not outputted by MediaWiki but are common
|
|
||||||
* to skins like MonoBook, Vector, etc... Essentially this level is for styles that are
|
|
||||||
* common to MonoBook clones.
|
|
||||||
*
|
|
||||||
* These modules are typically loaded by addModuleStyles(), which has absolutely no concept of
|
|
||||||
* dependency management. As a result they contain duplicate stylesheet references instead of
|
|
||||||
* setting 'dependencies' to the lower level the module is based on. For this reason avoid
|
|
||||||
* including more than one of them into your skin as this will result in duplicate CSS.
|
|
||||||
*/
|
|
||||||
'mediawiki.skinning.elements' => [
|
'mediawiki.skinning.elements' => [
|
||||||
'styles' => [
|
'deprecated' => 'Your default skin ResourceLoader class should use '
|
||||||
'resources/src/mediawiki.skinning/elements.css' => [ 'media' => 'screen' ],
|
. 'ResourceLoaderSkinModule::class',
|
||||||
],
|
'class' => ResourceLoaderSkinModule::class,
|
||||||
|
'features' => [ 'elements' ],
|
||||||
],
|
],
|
||||||
'mediawiki.skinning.content' => [
|
'mediawiki.skinning.content' => [
|
||||||
'styles' => [
|
'deprecated' => 'Your default skin ResourceLoader class should use '
|
||||||
'resources/src/mediawiki.skinning/elements.css' => [ 'media' => 'screen' ],
|
. 'ResourceLoaderSkinModule::class',
|
||||||
'resources/src/mediawiki.skinning/content.css' => [ 'media' => 'screen' ],
|
'class' => ResourceLoaderSkinModule::class,
|
||||||
],
|
'features' => [ 'elements', 'content' ],
|
||||||
],
|
],
|
||||||
// Used in the web installer. Test it after modifying this definition!
|
// Used in the web installer. Test it after modifying this definition!
|
||||||
'mediawiki.skinning.interface' => [
|
'mediawiki.skinning.interface' => [
|
||||||
'class' => ResourceLoaderSkinModule::class,
|
'class' => ResourceLoaderSkinModule::class,
|
||||||
'styles' => [
|
'features' => [ 'elements', 'content', 'interface', 'logo' ],
|
||||||
'resources/src/mediawiki.skinning/elements.css' => [ 'media' => 'screen' ],
|
|
||||||
'resources/src/mediawiki.skinning/content.css' => [ 'media' => 'screen' ],
|
|
||||||
'resources/src/mediawiki.skinning/interface.css' => [ 'media' => 'screen' ],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'jquery.makeCollapsible.styles' => [
|
'jquery.makeCollapsible.styles' => [
|
||||||
'targets' => [ 'desktop', 'mobile' ],
|
'targets' => [ 'desktop', 'mobile' ],
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,6 @@ CSS
|
||||||
*/
|
*/
|
||||||
public function testGetStyles( $parent, $logo, $expected ) {
|
public function testGetStyles( $parent, $logo, $expected ) {
|
||||||
$module = $this->getMockBuilder( ResourceLoaderSkinModule::class )
|
$module = $this->getMockBuilder( ResourceLoaderSkinModule::class )
|
||||||
->disableOriginalConstructor()
|
|
||||||
->setMethods( [ 'readStyleFiles', 'getConfig', 'getLogoData' ] )
|
->setMethods( [ 'readStyleFiles', 'getConfig', 'getLogoData' ] )
|
||||||
->getMock();
|
->getMock();
|
||||||
$module->expects( $this->once() )->method( 'readStyleFiles' )
|
$module->expects( $this->once() )->method( 'readStyleFiles' )
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue