38 protected $origin = self::ORIGIN_CORE_SITEWIDE;
114 $this->localBasePath = static::extractLocalBasePath( $options,
$localBasePath );
116 $this->definition = $options;
123 if ( $this->definition ===
null ) {
128 $this->definition =
null;
130 if ( isset( $options[
'data'] ) ) {
132 $data = json_decode( file_get_contents( $dataPath ),
true );
133 $options = array_merge( $data, $options );
143 $prefix = isset( $options[
'prefix'] ) && $options[
'prefix'];
144 $selector = isset( $options[
'selector'] ) && $options[
'selector'];
146 && $options[
'selectorWithoutVariant'];
148 && $options[
'selectorWithVariant'];
151 throw new InvalidArgumentException(
152 "Given 'selectorWithoutVariant' but no 'selectorWithVariant'."
156 throw new InvalidArgumentException(
157 "Given 'selectorWithVariant' but no 'selectorWithoutVariant'."
161 throw new InvalidArgumentException(
162 "Incompatible 'selector' and 'selectorWithVariant'+'selectorWithoutVariant' given."
166 throw new InvalidArgumentException(
167 "None of 'prefix', 'selector' or 'selectorWithVariant'+'selectorWithoutVariant' given."
171 foreach ( $options as $member => $option ) {
175 if ( !is_array( $option ) ) {
176 throw new InvalidArgumentException(
177 "Invalid list error. '$option' given, array expected."
180 if ( !isset( $option[
'default'] ) ) {
182 $option = [
'default' => $option ];
184 foreach ( $option as $skin => $data ) {
185 if ( !is_array( $data ) ) {
186 throw new InvalidArgumentException(
187 "Invalid list error. '$data' given, array expected."
191 $this->{$member} = $option;
195 $this->{$member} = (bool)$option;
199 case 'selectorWithoutVariant':
200 case 'selectorWithVariant':
201 $this->{$member} = (string)$option;
205 $this->selectorWithoutVariant = $this->selectorWithVariant = (string)$option;
249 $skin = $context->getSkin();
250 if ( $this->imageObjects ===
null ) {
251 $this->loadFromDefinition();
252 $this->imageObjects = [];
254 if ( !isset( $this->imageObjects[$skin] ) ) {
255 $this->imageObjects[$skin] = [];
256 if ( !isset( $this->images[$skin] ) ) {
257 $this->images[$skin] = $this->images[
'default'] ?? [];
259 foreach ( $this->images[$skin] as $name => $options ) {
260 $fileDescriptor = is_array( $options ) ? $options[
'file'] : $options;
262 $allowedVariants = array_merge(
263 ( is_array( $options ) && isset( $options[
'variants'] ) ) ? $options[
'variants'] : [],
264 $this->getGlobalVariants( $context )
266 if ( isset( $this->variants[$skin] ) ) {
267 $variantConfig = array_intersect_key(
268 $this->variants[$skin],
269 array_fill_keys( $allowedVariants,
true )
279 $this->localBasePath,
283 $this->imageObjects[$skin][$image->getName()] = $image;
287 return $this->imageObjects[$skin];
297 $skin = $context->getSkin();
298 if ( $this->globalVariants ===
null ) {
299 $this->loadFromDefinition();
300 $this->globalVariants = [];
302 if ( !isset( $this->globalVariants[$skin] ) ) {
303 $this->globalVariants[$skin] = [];
304 if ( !isset( $this->variants[$skin] ) ) {
305 $this->variants[$skin] = $this->variants[
'default'] ?? [];
307 foreach ( $this->variants[$skin] as $name => $config ) {
308 if ( $config[
'global'] ??
false ) {
309 $this->globalVariants[$skin][] = $name;
314 return $this->globalVariants[$skin];
322 $this->loadFromDefinition();
327 $selectors = $this->getSelectors();
329 foreach ( $this->getImages( $context ) as $name => $image ) {
330 $declarations = $this->getStyleDeclarations( $context, $image, $script );
332 $selectors[
'selectorWithoutVariant'],
334 '{prefix}' => $this->getPrefix(),
339 $rules[] =
"$selector {\n\t$declarations\n}";
341 foreach ( $image->getVariants() as $variant ) {
342 $declarations = $this->getStyleDeclarations( $context, $image, $script, $variant );
344 $selectors[
'selectorWithVariant'],
346 '{prefix}' => $this->getPrefix(),
348 '{variant}' => $variant,
351 $rules[] =
"$selector {\n\t$declarations\n}";
355 $style = implode(
"\n", $rules );
356 return [
'all' => $style ];
376 $imageDataUri = $this->useDataURI ? $image->
getDataUri( $context, $variant,
'original' ) :
false;
377 $primaryUrl = $imageDataUri ?: $image->
getUrl( $context, $script, $variant,
'original' );
378 $declarations = $this->getCssDeclarations(
380 $image->
getUrl( $context, $script, $variant,
'rasterized' )
382 return implode(
"\n\t", $declarations );
398 $primaryUrl =
CSSMin::buildUrlValue( $primary );
401 "background-image: $fallbackUrl;",
402 "background-image: linear-gradient(transparent, transparent), $primaryUrl;",
420 $this->loadFromDefinition();
421 $summary = parent::getDefinitionSummary( $context );
429 'selectorWithoutVariant',
430 'selectorWithVariant',
432 $options[$member] = $this->{$member};
436 'options' => $options,
437 'fileHashes' => $this->getFileHashes( $context ),
448 $this->loadFromDefinition();
450 foreach ( $this->getImages( $context ) as $name => $image ) {
451 $files[] = $image->getPath( $context );
453 $files = array_values( array_unique( $files ) );
454 return array_map( [ __CLASS__,
'safeFileHash' ], $files );
463 return $path->getLocalPath();
466 return "{$this->localBasePath}/$path";
480 if ( $localBasePath ===
null ) {
481 $localBasePath =
$IP;
484 if ( array_key_exists(
'localBasePath', $options ) ) {
485 $localBasePath = (string)$options[
'localBasePath'];
488 return $localBasePath;
495 return self::LOAD_STYLES;
static buildUrlValue( $url)
Build a CSS 'url()' value for the given URL, quoting parentheses (and other funny characters) and esc...
Context object that contains information about the state of a specific ResourceLoader web request.
An object to represent a path to a JavaScript/CSS file, along with a remote and local base path,...
Module for generated and embedded images.
getImage( $name, ResourceLoaderContext $context)
Get a ResourceLoaderImage object for given image.
static extractLocalBasePath(array $options, $localBasePath=null)
Extract a local base path from module definition information.
loadFromDefinition()
Parse definition and external JSON data, if referenced.
ResourceLoaderImage[][] null $imageObjects
getStyles(ResourceLoaderContext $context)
string $localBasePath
Local base path, see __construct()
__construct(array $options=[], $localBasePath=null)
Constructs a new module from an options array.
getDefinitionSummary(ResourceLoaderContext $context)
Get the definition summary for this module.
getSelectors()
Get CSS selector templates used by this module.
array null $globalVariants
getCssDeclarations( $primary, $fallback)
SVG support using a transparent gradient to guarantee cross-browser compatibility (browsers able to u...
getFileHashes(ResourceLoaderContext $context)
Helper method for getDefinitionSummary.
getPrefix()
Get CSS class prefix used by this module.
string null $defaultColor
getStyleDeclarations(ResourceLoaderContext $context, ResourceLoaderImage $image, $script, $variant=null)
This method must not be used by getDefinitionSummary as doing so would cause an infinite loop (we use...
getGlobalVariants(ResourceLoaderContext $context)
Get list of variants in this module that are 'global', i.e., available for every image regardless of ...
getImages(ResourceLoaderContext $context)
Get ResourceLoaderImage objects for all images.
Class encapsulating an image used in a ResourceLoaderImageModule.
getUrl(ResourceLoaderContext $context, $script, $variant, $format)
Get the load.php URL that will produce this image.
getDataUri(ResourceLoaderContext $context, $variant, $format)
Get the data: URI that will produce this image.
Abstraction for ResourceLoader modules, with name registration and maxage functionality.
string null $name
Module name.