Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"require": {
"mck89/peast": "^1.16"
"mck89/peast": "^1.16",
"scssphp/scssphp": "^1.13.0"
},
"require-dev": {
"liquipedia/sqllint": "*",
Expand Down
4 changes: 2 additions & 2 deletions extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ResourceLoaderArticles",
"version": "2.3.0",
"version": "2.4.0",
"author": [
"[https://fo-nttax.de Alex Winkler]"
],
Expand Down Expand Up @@ -57,4 +57,4 @@
}
},
"manifest_version": 2
}
}
2 changes: 1 addition & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
"resourceloaderarticles-success-delete": "Resource successfully deleted",

"resourceloaderarticles-help-page": "Page name of resource (excl. `MediaWiki:Common.[js|css]/`). Valid JS ends with `.js` and valid styling ends with `.css` or `.less`.",
"resourceloaderarticles-help-priority": "Priority for loading order of the resource (higher first), falls back to alphabetic order within a single priority class."
"resourceloaderarticles-help-priority": "Priority for loading order of the resource (higher first), falls back to alphabetic order within a single priority class. Priority is done in two groups: Less/CSS and SCSS. The first group will always be before the second."
}
5 changes: 4 additions & 1 deletion src/Hooks/MainHookHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public function onBeforePageDisplay( $out, $skin ): void {
}

/**
* Set the CONTENT_MODEL_CSS content handler for less files
* Set the CONTENT_MODEL_CSS content handler for less and scss files
*
* @param Title $title
* @param string &$model
Expand All @@ -94,6 +94,9 @@ public function onContentHandlerDefaultModelFor( $title, &$model ) {
if ( str_ends_with( $title->getText(), '.less' ) ) {
$model = CONTENT_MODEL_CSS;
return true;
} elseif ( str_ends_with( $title->getText(), '.scss' ) ) {
$model = CONTENT_MODEL_CSS;
return true;
}
}
}
Expand Down
69 changes: 42 additions & 27 deletions src/ResourceLoader/ResourceLoaderArticlesModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use ResourceLoader;
use ResourceLoaderContext;
use ResourceLoaderWikiModule;
use ScssPhp\ScssPhp\Compiler as SCSSCompiler;

class ResourceLoaderArticlesModule extends ResourceLoaderWikiModule {

Expand All @@ -38,7 +39,11 @@ protected function getPages( ResourceLoaderContext $context ) {
foreach ( $articles as $article ) {
if ( substr( $article, -3 ) === '.js' ) {
$pages[ 'MediaWiki:Common.js/' . $article ] = [ 'type' => 'script' ];
} elseif ( substr( $article, -4 ) === '.css' || substr( $article, -5 ) === '.less' ) {
} elseif (
substr( $article, -4 ) === '.css'
|| substr( $article, -5 ) === '.less'
|| substr( $article, -5 ) === '.scss'
) {
$pages[ 'MediaWiki:Common.css/' . $article ] = [ 'type' => 'style' ];
}
}
Expand Down Expand Up @@ -99,12 +104,12 @@ static function () use ( $contents, $fileName ) {
* @return array
*/
public function getStyles( ResourceLoaderContext $context ) {
$styles = [];
$less = '';
$scss = '';
foreach ( $this->getPages( $context ) as $titleText => $options ) {
if ( $options[ 'type' ] !== 'style' ) {
continue;
}
$media = isset( $options[ 'media' ] ) ? $options[ 'media' ] : 'all';
$style = $this->getContent( $titleText, $context );
if ( strval( $style ) === '' ) {
continue;
Expand All @@ -114,33 +119,43 @@ public function getStyles( ResourceLoaderContext $context ) {
$style = '/* using @import is forbidden */';
}

if ( !isset( $styles[ $media ] ) ) {
$styles[ $media ] = [];
$styles[ $media ][ 0 ] = '';
}
$style = ResourceLoader::makeComment( $titleText ) . $style;
$styles[ $media ][ 0 ] .= $style;
}
foreach ( $styles as $media => $styleItem ) {
/* start of less parser */
try {
$lessc = new Less_Parser;
$lessc->parse( $styleItem[ 0 ] );
$style = $lessc->getCss();
} catch ( exception $e ) {
$style = '/* invalid less: ' . $e->getMessage() . ' */';
}
/* end of less parser */
if ( $this->getFlip( $context ) ) {
$style = CSSJanus::transform( $style, true, false );
if ( substr( $titleText, -5 ) === '.scss' ) {
$scss .= $style;
} else {
$less .= $style;
}
$style = MemoizedCallable::call(
'CSSMin::remap',
[ $style, false, $this->getConfig()->get( 'ScriptPath' ), true ]
);
$styles[ $media ][ 0 ] = $style;
}
return $styles;
/* start of less parser */
try {
$lessc = new Less_Parser;
$lessc->parse( $less );
$compiledLess = $lessc->getCss();
} catch ( \Exception $e ) {
$compiledLess = '/* invalid less: ' . $e->getMessage() . ' */';
}
/* end of less parser */

/* start of scss parser */
try {
$compiler = new SCSSCompiler();
$compiledScss = $compiler->compileString( $scss )->getCss();
} catch ( \Exception $e ) {
$compiledLess = '/* invalid less: ' . $e->getMessage() . ' */';
}
/* end of scss parser */

$css = $compiledLess . $compiledScss;

if ( $this->getFlip( $context ) ) {
$css = CSSJanus::transform( $css, true, false );
}
$css = MemoizedCallable::call(
'CSSMin::remap',
[ $css, false, $this->getConfig()->get( 'ScriptPath' ), true ]
);

return [ 'all' => [ $css ] ];
}

/**
Expand Down
13 changes: 10 additions & 3 deletions src/SpecialPage/SpecialResourceLoaderArticles.php
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,18 @@ public function trimValueCB( $value ) {
*/
public function validatePageCB( $value, $alldata ) {
if (
( $alldata[ 'Type' ] === 'style'
&& !( ( strlen( $value ) > 4 && substr( $value, -4 ) === '.css' )
(
$alldata[ 'Type' ] === 'style'
&& !(
( strlen( $value ) > 4 && substr( $value, -4 ) === '.css' )
|| ( strlen( $value ) > 5 && substr( $value, -5 ) === '.less' )
|| ( strlen( $value ) > 5 && substr( $value, -5 ) === '.scss' )
)
) || ( $alldata[ 'Type' ] === 'script' && !( strlen( $value ) > 3 && substr( $value, -3 ) === '.js' ) )
)
|| (
$alldata[ 'Type' ] === 'script'
&& !( strlen( $value ) > 3 && substr( $value, -3 ) === '.js' )
)
) {
return $this->msg( 'resourceloaderarticles-error-page-invalid' )->text();
}
Expand Down