From 028f9d8375dea76d90dcd7e6f49ce6ee1a756fa2 Mon Sep 17 00:00:00 2001 From: Ori Livneh Date: Thu, 19 Sep 2013 16:43:46 -0700 Subject: [PATCH] Implement LESS image embedding This patch adds two custom LESS functions: embeddable() and embed(). Both functions take a single image file reference as their sole argument. - embeddable() is a predicate function (= returns a LESS boolean value) that checks whether an image is suitable for embedding. An image is suitable if it exists, has an appropriate MIME type, and is not too large. - embed() generates a CSS url() value that contains the reference image encoded as a data URI. The existence of the predicate function allows embeddable() to be used as a mixin guard. This provides an elegant means of generating a single rule when the image is not embeddable and multiple rules (the data URI & fallback) when it is. This technique is used to implement a .background-image mixin, included in this patch. Change-Id: I3e06b6d6e8630b7923fa42b3daf1ced3e656bbe7 --- includes/DefaultSettings.php | 47 ++++++++++++++++++- .../mediawiki.less/mediawiki.mixins.less | 9 +++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index c85623c9f7..7a1eb22818 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -3313,7 +3313,52 @@ $wgResourceLoaderLESSVars = array(); * * @since 1.22 */ -$wgResourceLoaderLESSFunctions = array(); +$wgResourceLoaderLESSFunctions = array( + /** + * Check if an image file reference is suitable for embedding. + * An image is embeddable if it (a) exists, (b) has a suitable MIME-type, + * (c) does not exceed IE<9 size limit of 32kb. This is a LESS predicate + * function; it returns a LESS boolean value and can thus be used as a + * mixin guard. + * + * @par Example: + * @code + * .background-image(@url) when(embeddable(@url)) { + * background-image: url(@url) !ie; + * } + * @endcode + */ + 'embeddable' => function( $frame, $less ) { + $base = pathinfo( $less->parser->sourceName, PATHINFO_DIRNAME ); + $url = $frame[2][0]; + $file = realpath( $base . '/' . $url ); + $embeddable = ( $file + && strpos( $url, '//' ) === false + && filesize( $file ) < CSSMin::EMBED_SIZE_LIMIT + && CSSMin::getMimeType( $file ) !== false ) ? 'true' : 'false'; + return array( 'keyword', $embeddable ); + }, + + /** + * Convert an image URI to a base64-encoded data URI. + * + * @par Example: + * @code + * .fancy-button { + * background-image: embed('../images/button-bg.png'); + * } + * @endcode + */ + 'embed' => function( $frame, $less ) { + $base = pathinfo( $less->parser->sourceName, PATHINFO_DIRNAME ); + $url = $frame[2][0]; + $file = realpath( $base . '/' . $url ); + + $data = CSSMin::encodeImageAsDataURI( $file ); + $less->embeddedImages[ $file ] = filemtime( $file ); + return 'url(' . $data . ')'; + }, +); /** * Default import paths for LESS modules. LESS files referenced in @import diff --git a/resources/mediawiki.less/mediawiki.mixins.less b/resources/mediawiki.less/mediawiki.mixins.less index c0a1104718..032028fbea 100644 --- a/resources/mediawiki.less/mediawiki.mixins.less +++ b/resources/mediawiki.less/mediawiki.mixins.less @@ -10,4 +10,11 @@ * See for more information about how to write mixins. */ -// No mixins yet! +.background-image(@url) when (embeddable(@url)) { + background-image: embed(@url); + background-image: url(@url)!ie; +} + +.background-image(@url) when not (embeddable(@url)) { + background-image: url(@url); +} -- 2.20.1