Merge branch 'release/v1.2.0'
这个提交包含在:
当前提交
d3b256f305
|
@ -0,0 +1,38 @@
|
|||
name: Lint Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ master, develop, feature/** ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
jobs:
|
||||
lint-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Installing PHP
|
||||
uses: shivammathur/setup-php@master
|
||||
with:
|
||||
php-version: '8.0'
|
||||
- name: Get Composer Cache Directory 2
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
- uses: actions/cache@v3
|
||||
id: actions-cache
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-composer-
|
||||
- name: Cache PHP dependencies
|
||||
uses: actions/cache@v3
|
||||
id: vendor-cache
|
||||
with:
|
||||
path: vendor
|
||||
key: ${{ runner.OS }}-build-${{ hashFiles('**/composer.lock') }}
|
||||
- name: Composer install
|
||||
if: steps.vendor-cache.outputs.cache-hit != 'true'
|
||||
run: composer install --no-ansi --no-interaction --no-scripts --no-suggest --prefer-dist
|
||||
- name: Run Test
|
||||
run: composer run test
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "octfx/template-styles-extender",
|
||||
"version": "1.1.8",
|
||||
"version": "1.2.0",
|
||||
"type": "mediawiki-extension",
|
||||
"description": "Extends TemplateStyles with new CSS properties",
|
||||
"homepage": "http://www.mediawiki.org/wiki/Extension:TemplateStylesExtender",
|
||||
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.3.19",
|
||||
"php": ">=8.0",
|
||||
"ext-json": "*",
|
||||
"composer/installers": ">=1.0.1"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "TemplateStylesExtender",
|
||||
"version": "1.1.8",
|
||||
"version": "1.2.0",
|
||||
"author": [
|
||||
"[https://www.mediawiki.org/wiki/User:Octfx Octfx]"
|
||||
],
|
||||
|
@ -11,7 +11,7 @@
|
|||
"requires": {
|
||||
"MediaWiki": ">= 1.39.0",
|
||||
"platform": {
|
||||
"php": ">=7.3.19"
|
||||
"php": ">=8.0"
|
||||
},
|
||||
"extensions": {
|
||||
"TemplateStyles": ">= 1.0"
|
||||
|
@ -48,7 +48,11 @@
|
|||
},
|
||||
"HookHandlers": {
|
||||
"MainHooks": {
|
||||
"class": "MediaWiki\\Extension\\TemplateStylesExtender\\Hooks\\MainHooks"
|
||||
"class": "MediaWiki\\Extension\\TemplateStylesExtender\\Hooks\\MainHooks",
|
||||
"services": [
|
||||
"PermissionManager",
|
||||
"UserFactory"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Hooks": {
|
||||
|
|
|
@ -2,18 +2,45 @@
|
|||
|
||||
namespace MediaWiki\Extension\TemplateStylesExtender\Hooks;
|
||||
|
||||
use MediaWiki\EditPage\EditPage;
|
||||
use MediaWiki\Extension\TemplateStyles\Hooks;
|
||||
use MediaWiki\Extension\TemplateStylesExtender\TemplateStylesExtender;
|
||||
use MediaWiki\Hook\EditPage__attemptSaveHook;
|
||||
use MediaWiki\Hook\ParserFirstCallInitHook;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use MediaWiki\Permissions\PermissionManager;
|
||||
use MediaWiki\Revision\SlotRecord;
|
||||
use MediaWiki\User\UserFactory;
|
||||
use MWException;
|
||||
use Parser;
|
||||
use PermissionsError;
|
||||
use PPFrame;
|
||||
|
||||
/**
|
||||
* phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
|
||||
*/
|
||||
class MainHooks implements ParserFirstCallInitHook, EditPage__attemptSaveHook {
|
||||
|
||||
/**
|
||||
* @var PermissionManager
|
||||
*/
|
||||
private PermissionManager $manager;
|
||||
|
||||
/**
|
||||
* @var UserFactory
|
||||
*/
|
||||
private UserFactory $factory;
|
||||
|
||||
/**
|
||||
* @param PermissionManager $manager
|
||||
* @param UserFactory $factory
|
||||
*/
|
||||
public function __construct( PermissionManager $manager, UserFactory $factory ) {
|
||||
$this->manager = $manager;
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser
|
||||
* @throws MWException
|
||||
*/
|
||||
public function onParserFirstCallInit( $parser ) {
|
||||
|
@ -21,7 +48,14 @@ class MainHooks implements ParserFirstCallInitHook, EditPage__attemptSaveHook {
|
|||
}
|
||||
|
||||
/**
|
||||
* This is a wrapper for <templatestyles> tags, that allows unscoping of css for users with 'editinterface' permissions
|
||||
* This is a wrapper for <templatestyles> tags,
|
||||
* that allows unscoping of css for users with 'editinterface' permissions
|
||||
*
|
||||
* @param string $text
|
||||
* @param string[] $params
|
||||
* @param Parser $parser
|
||||
* @param PPFrame $frame
|
||||
* @return string
|
||||
* @see Hooks::handleTag()
|
||||
*/
|
||||
public static function handleTag( $text, $params, $parser, $frame ): string {
|
||||
|
@ -48,7 +82,7 @@ class MainHooks implements ParserFirstCallInitHook, EditPage__attemptSaveHook {
|
|||
/**
|
||||
* Check if 'wrapclass' was used in the page, if so only users with 'editinterface' permissions may save the page
|
||||
*
|
||||
* @param $editpage_Obj
|
||||
* @param EditPage $editpage_Obj
|
||||
* @return true
|
||||
* @throws PermissionsError
|
||||
*/
|
||||
|
@ -69,13 +103,10 @@ class MainHooks implements ParserFirstCallInitHook, EditPage__attemptSaveHook {
|
|||
|
||||
$permission = TemplateStylesExtender::getConfigValue( 'TemplateStylesExtenderUnscopingPermission' );
|
||||
|
||||
$permManager = MediaWikiServices::getInstance()->getPermissionManager();
|
||||
$user = MediaWikiServices::getInstance()
|
||||
->getUserFactory()
|
||||
->newFromUserIdentity( $editpage_Obj->getContext()->getUser() );
|
||||
$user = $this->factory->newFromUserIdentity( $editpage_Obj->getContext()->getUser() );
|
||||
|
||||
$userCan = $permManager->userHasRight( $user, $permission ) ||
|
||||
$permManager->userCan( $permission, $user, $editpage_Obj->getTitle() );
|
||||
$userCan = $this->manager->userHasRight( $user, $permission ) ||
|
||||
$this->manager->userCan( $permission, $user, $editpage_Obj->getTitle() );
|
||||
|
||||
if ( strpos( $content->getText(), 'wrapclass' ) !== false && !$userCan ) {
|
||||
throw new PermissionsError( $permission, [ 'templatestylesextender-unscope-no-permisson' ] );
|
||||
|
|
|
@ -27,7 +27,7 @@ use Wikimedia\CSS\Sanitizer\StylePropertySanitizer;
|
|||
|
||||
class PropertySanitizerHook {
|
||||
/**
|
||||
* @param StylePropertySanitizer $propertySanitizer
|
||||
* @param StylePropertySanitizer &$propertySanitizer
|
||||
* @param TemplateStylesMatcherFactory $matcherFactory
|
||||
*/
|
||||
public static function onSanitize( &$propertySanitizer, $matcherFactory ): void {
|
||||
|
|
|
@ -67,6 +67,8 @@ class StylesheetSanitizerHook {
|
|||
$extended->addPointerEvents( $extender );
|
||||
$extended->addScrollMarginProperties( $extender, $matcherFactory );
|
||||
$extended->addAspectRatio( $extender, $matcherFactory );
|
||||
$extended->addInlineBlockMarginPaddingProperties( $extender, $matcherFactory );
|
||||
$extended->addInsetProperties( $extender, $matcherFactory );
|
||||
|
||||
$propertySanitizer->setKnownProperties( $extender->getKnownProperties() );
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ declare( strict_types=1 );
|
|||
|
||||
namespace MediaWiki\Extension\TemplateStylesExtender;
|
||||
|
||||
use MediaWiki\Extension\TemplateStylesExtender\Matcher\VarNameMatcher;
|
||||
use Wikimedia\CSS\Grammar\Alternative;
|
||||
use Wikimedia\CSS\Grammar\AnythingMatcher;
|
||||
use Wikimedia\CSS\Grammar\BlockMatcher;
|
||||
|
@ -53,6 +54,67 @@ class MatcherFactoryExtender extends MatcherFactory {
|
|||
return $this->cache[__METHOD__];
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS-color extension enabling RGBA
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color
|
||||
* @return Matcher
|
||||
*/
|
||||
public function color()
|
||||
{
|
||||
if ( !isset( $this->cache[__METHOD__] ) ) {
|
||||
$color = new Alternative( [
|
||||
parent::color(),
|
||||
new TokenMatcher( Token::T_HASH, static function ( Token $t ) {
|
||||
return preg_match( '/^([0-9a-f]{4})|([0-9a-f]{8})$/i', $t->value() );
|
||||
} ),
|
||||
]);
|
||||
$this->cache[__METHOD__] = $color;
|
||||
}
|
||||
return $this->cache[__METHOD__];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds `var` support to color functions
|
||||
* @return Matcher|Matcher[]
|
||||
*/
|
||||
protected function colorFuncs() {
|
||||
if ( !isset( $this->cache[__METHOD__] ) ) {
|
||||
$var = new FunctionMatcher( 'var', new VarNameMatcher() );
|
||||
|
||||
$i = $this->integer();
|
||||
$iVar = new Alternative([ $var, $i ]);
|
||||
|
||||
$n = $this->number();
|
||||
$nVar = new Alternative([ $var, $n ]);
|
||||
|
||||
$p = $this->percentage();
|
||||
$pVar = new Alternative([ $var, $p ]);
|
||||
|
||||
$this->cache[__METHOD__] = [
|
||||
new FunctionMatcher( 'rgb', new Alternative( [
|
||||
Quantifier::hash( $iVar, 3, 3 ),
|
||||
Quantifier::hash( $pVar, 3, 3 ),
|
||||
Quantifier::hash( $var, 1, 3 ),
|
||||
] ) ),
|
||||
new FunctionMatcher( 'rgba', new Alternative( [
|
||||
new Juxtaposition( [ $iVar, $iVar, $iVar, $nVar ], true ),
|
||||
new Juxtaposition( [ $pVar, $pVar, $pVar, $nVar ], true ),
|
||||
Quantifier::hash( $var, 1, 4 ),
|
||||
new Juxtaposition( [ Quantifier::hash( $var, 1, 3 ), $nVar ], true ),
|
||||
] ) ),
|
||||
new FunctionMatcher( 'hsl', new Alternative([
|
||||
new Juxtaposition( [ $nVar, $pVar, $pVar ], true ),
|
||||
Quantifier::hash($var, 1, 3),
|
||||
]) ),
|
||||
new FunctionMatcher( 'hsla', new Alternative([
|
||||
new Juxtaposition( [ $nVar, $pVar, $pVar, $nVar ], true ),
|
||||
Quantifier::hash($var, 1, 4),
|
||||
]) ),
|
||||
];
|
||||
}
|
||||
return $this->cache[__METHOD__];
|
||||
}
|
||||
|
||||
/**
|
||||
* This is in reality a complete copy of the parent hook with line 68 and 110 extended
|
||||
* This can very easily break if there is an update upstream
|
||||
|
|
|
@ -27,11 +27,9 @@ use Wikimedia\CSS\Grammar\FunctionMatcher;
|
|||
use Wikimedia\CSS\Grammar\KeywordMatcher;
|
||||
use Wikimedia\CSS\Grammar\MatcherFactory;
|
||||
use Wikimedia\CSS\Grammar\Quantifier;
|
||||
use Wikimedia\CSS\Grammar\TokenMatcher;
|
||||
use Wikimedia\CSS\Grammar\UnorderedGroup;
|
||||
use Wikimedia\CSS\Objects\CSSObject;
|
||||
use Wikimedia\CSS\Objects\Declaration;
|
||||
use Wikimedia\CSS\Objects\Token;
|
||||
use Wikimedia\CSS\Sanitizer\StylePropertySanitizer;
|
||||
|
||||
class StylePropertySanitizerExtender extends StylePropertySanitizer {
|
||||
|
@ -42,6 +40,13 @@ class StylePropertySanitizerExtender extends StylePropertySanitizer {
|
|||
private static $extendedCssSizing3 = false;
|
||||
private static $extendedCss1Masking = false;
|
||||
|
||||
/**
|
||||
* @param MatcherFactory $matcherFactory
|
||||
*/
|
||||
public function __construct( MatcherFactory $matcherFactory ) {
|
||||
parent::__construct( new MatcherFactoryExtender() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Allow overflow-wrap: anywhere
|
||||
|
@ -87,13 +92,6 @@ class StylePropertySanitizerExtender extends StylePropertySanitizer {
|
|||
|
||||
$props = parent::cssBorderBackground3( $matcherFactory );
|
||||
|
||||
$props['background-color'] = new Alternative( [
|
||||
$matcherFactory->color(),
|
||||
new TokenMatcher( Token::T_HASH, function ( Token $t ) {
|
||||
return preg_match( '/^([0-9a-f]{3}|[0-9a-f]{8})$/i', $t->value() );
|
||||
} ),
|
||||
] );
|
||||
|
||||
$props['border'] = UnorderedGroup::someOf( [
|
||||
new KeywordMatcher( [
|
||||
'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset'
|
||||
|
@ -103,7 +101,7 @@ class StylePropertySanitizerExtender extends StylePropertySanitizer {
|
|||
] ),
|
||||
new Alternative( [
|
||||
$matcherFactory->color(),
|
||||
new FunctionMatcher( 'var', new VarNameMatcher() ),
|
||||
new FunctionMatcher( 'var', new VarNameMatcher() ),
|
||||
] )
|
||||
] );
|
||||
|
||||
|
@ -112,9 +110,9 @@ class StylePropertySanitizerExtender extends StylePropertySanitizer {
|
|||
Quantifier::hash( UnorderedGroup::allOf( [
|
||||
Quantifier::optional( new KeywordMatcher( 'inset' ) ),
|
||||
Quantifier::count( $matcherFactory->length(), 2, 4 ),
|
||||
Quantifier::optional(new Alternative( [
|
||||
Quantifier::optional( new Alternative( [
|
||||
$matcherFactory->color(),
|
||||
new FunctionMatcher( 'var', new VarNameMatcher() ),
|
||||
new FunctionMatcher( 'var', new VarNameMatcher() ),
|
||||
] ) ),
|
||||
] ) )
|
||||
] );
|
||||
|
|
|
@ -51,36 +51,44 @@ class TemplateStylesExtender {
|
|||
* @param MatcherFactory $factory
|
||||
*/
|
||||
public function addVarSelector( StylePropertySanitizer $propertySanitizer, MatcherFactory $factory ): void {
|
||||
$anyProperty = new Alternative( [
|
||||
$factory->color(),
|
||||
$factory->image(),
|
||||
$factory->length(),
|
||||
$factory->integer(),
|
||||
$factory->percentage(),
|
||||
$factory->number(),
|
||||
$factory->angle(),
|
||||
$factory->frequency(),
|
||||
$factory->resolution(),
|
||||
$factory->position(),
|
||||
$factory->cssSingleEasingFunction(),
|
||||
$factory->comma(),
|
||||
$factory->cssWideKeywords(),
|
||||
new KeywordMatcher( [
|
||||
'solid', 'double', 'dotted', 'dashed', 'wavy'
|
||||
] )
|
||||
] );
|
||||
|
||||
$var = new FunctionMatcher(
|
||||
'var',
|
||||
new Juxtaposition( [
|
||||
new WhitespaceMatcher( [ 'significant' => false ] ),
|
||||
new VarNameMatcher(),
|
||||
new WhitespaceMatcher( [ 'significant' => false ] ),
|
||||
Quantifier::optional( new Juxtaposition( [
|
||||
$factory->comma(),
|
||||
new WhitespaceMatcher( [ 'significant' => false ] ),
|
||||
$anyProperty,
|
||||
] ) ),
|
||||
new WhitespaceMatcher( [ 'significant' => false ] ),
|
||||
] )
|
||||
);
|
||||
|
||||
$anyProperty = Quantifier::star(
|
||||
new Alternative( [
|
||||
$var,
|
||||
$factory->color(),
|
||||
$factory->image(),
|
||||
$factory->length(),
|
||||
$factory->integer(),
|
||||
$factory->percentage(),
|
||||
$factory->number(),
|
||||
$factory->angle(),
|
||||
$factory->frequency(),
|
||||
$factory->resolution(),
|
||||
$factory->position(),
|
||||
$factory->cssSingleEasingFunction(),
|
||||
$factory->comma(),
|
||||
$factory->cssWideKeywords(),
|
||||
new KeywordMatcher( [
|
||||
'solid', 'double', 'dotted', 'dashed', 'wavy'
|
||||
] )
|
||||
] )
|
||||
);
|
||||
$anyProperty = Quantifier::star( new Alternative( [
|
||||
$var,
|
||||
$anyProperty,
|
||||
] ) );
|
||||
|
||||
// Match anything*\s?[var anything|anything var]+\s?anything*(!important)?
|
||||
// The problem is, that var() can be used more or less anywhere
|
||||
|
@ -206,6 +214,67 @@ class TemplateStylesExtender {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds padding|margin-inline|block support
|
||||
*
|
||||
* @param StylePropertySanitizer $propertySanitizer
|
||||
* @param MatcherFactory $factory
|
||||
*/
|
||||
public function addInlineBlockMarginPaddingProperties( $propertySanitizer, $factory ): void {
|
||||
$auto = new KeywordMatcher( 'auto' );
|
||||
$autoLengthPct = new Alternative( [ $auto, $factory->lengthPercentage() ] );
|
||||
|
||||
$props = [];
|
||||
|
||||
$props['margin-block-end'] = $autoLengthPct;
|
||||
$props['margin-block-start'] = $autoLengthPct;
|
||||
$props['margin-block'] = Quantifier::count( $autoLengthPct, 1, 2 );
|
||||
$props['margin-inline-end'] = $autoLengthPct;
|
||||
$props['margin-inline-start'] = $autoLengthPct;
|
||||
$props['margin-inline'] = Quantifier::count( $autoLengthPct, 1, 2 );
|
||||
$props['padding-block-end'] = $autoLengthPct;
|
||||
$props['padding-block-start'] = $autoLengthPct;
|
||||
$props['padding-block'] = Quantifier::count( $autoLengthPct, 1, 2 );
|
||||
$props['padding-inline-end'] = $autoLengthPct;
|
||||
$props['padding-inline-start'] = $autoLengthPct;
|
||||
$props['padding-inline'] = Quantifier::count( $autoLengthPct, 1, 2 );
|
||||
|
||||
try {
|
||||
$propertySanitizer->addKnownProperties( $props );
|
||||
} catch ( InvalidArgumentException $e ) {
|
||||
// Fail silently
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds padding|margin-inline|block support
|
||||
*
|
||||
* @param StylePropertySanitizer $propertySanitizer
|
||||
* @param MatcherFactory $factory
|
||||
*/
|
||||
public function addInsetProperties( $propertySanitizer, $factory ): void {
|
||||
$auto = new KeywordMatcher( 'auto' );
|
||||
$autoLengthPct = new Alternative( [ $auto, $factory->lengthPercentage() ] );
|
||||
|
||||
$props = [];
|
||||
|
||||
$props['inset'] = Quantifier::count( $autoLengthPct, 1, 4 );
|
||||
|
||||
$props['inset-block'] = Quantifier::count( $autoLengthPct, 1, 2 );
|
||||
$props['inset-block-end'] = $autoLengthPct;
|
||||
$props['inset-block-start'] = $autoLengthPct;
|
||||
|
||||
$props['inset-inline'] = Quantifier::count( $autoLengthPct, 1, 2 );
|
||||
$props['inset-inline-end'] = $autoLengthPct;
|
||||
$props['inset-inline-start'] = $autoLengthPct;
|
||||
|
||||
try {
|
||||
$propertySanitizer->addKnownProperties( $props );
|
||||
} catch ( InvalidArgumentException $e ) {
|
||||
// Fail silently
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the pointer-events matcher
|
||||
*
|
||||
|
|
正在加载...
在新工单中引用