mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-11-24 07:43:47 +00:00
Merge "[Special:Preferences] [PHP] Add HTMLSkinVersionField form field"
This commit is contained in:
commit
e77bd199f9
92
includes/HTMLForm/Fields/HTMLLegacySkinVersionField.php
Normal file
92
includes/HTMLForm/Fields/HTMLLegacySkinVersionField.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Vector\HTMLForm\Fields;
|
||||
|
||||
use Vector\Constants;
|
||||
use Wikimedia\Assert\Assert;
|
||||
|
||||
/**
|
||||
* The field on Special:Preferences (and Special:GlobalPreferences) that allows the user to
|
||||
* enable/disable the legacy version of the Vector skin. Per
|
||||
* https://phabricator.wikimedia.org/T242381, the field is a checkbox, that, when checked, enables
|
||||
* the legacy version of the Vector skin.
|
||||
*
|
||||
* `HTMLLegacySkinVersionField` adapts the boolean storage type of a checkbox field to the string
|
||||
* storage type of the Vector skin version preference (e.g. see `Constants::SKIN_VERSION_LEGACY`).
|
||||
*
|
||||
* However, we cannot extend `HTMLCheckField` to inherit the behavior of a checkbox field.
|
||||
* `HTMLCheckField::loadDataFromRequest` returns boolean values. Returning non-boolean values in
|
||||
* `HTMLLegacySkinVersionField::loadDataFromRequest` would violate Liskov's Substitution Principle.
|
||||
* Like `HTMLExpiryField`, `HTMLLegacySkinVersionField` proxies to a private instance of
|
||||
* `HTMLCheckField`, adapting parameter and return values where necessary.
|
||||
*
|
||||
* @package Vector\HTMLForm\Fields
|
||||
* @internal
|
||||
*/
|
||||
final class HTMLLegacySkinVersionField extends \HTMLFormField {
|
||||
|
||||
/**
|
||||
* @var \HTMLCheckField $checkField
|
||||
*/
|
||||
private $checkField;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct( $params ) {
|
||||
Assert::precondition(
|
||||
is_bool( $params['default'] ),
|
||||
'The "default" param must be a boolean.'
|
||||
);
|
||||
|
||||
parent::__construct( $params );
|
||||
|
||||
$this->checkField = new \HTMLCheckField( $params );
|
||||
}
|
||||
|
||||
// BEGIN ADAPTER
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getInputHTML( $value ) {
|
||||
return $this->checkField->getInputHTML( $value === Constants::SKIN_VERSION_LEGACY );
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getInputOOUI( $value ) {
|
||||
return $this->checkField->getInputOOUI( (string)( $value === Constants::SKIN_VERSION_LEGACY ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return string If the checkbox is checked, then `Constants::SKIN_VERSION_LEGACY`;
|
||||
* `Constants::SKIN_VERSION_LATEST` otherwise
|
||||
*/
|
||||
public function loadDataFromRequest( $request ) {
|
||||
return $this->checkField->loadDataFromRequest( $request )
|
||||
? Constants::SKIN_VERSION_LEGACY
|
||||
: Constants::SKIN_VERSION_LATEST;
|
||||
}
|
||||
|
||||
// END ADAPTER
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getLabel() {
|
||||
return $this->checkField->getLabel();
|
||||
}
|
||||
|
||||
// Note well that we can't invoke the following methods of `HTMLCheckField` directly because
|
||||
// they're protected and `HTMLSkinVectorField` doesn't extend `HTMLCheckField`.
|
||||
|
||||
/** @inheritDoc */
|
||||
protected function getLabelAlignOOUI() {
|
||||
// See \HTMLCheckField::getLabelAlignOOUI
|
||||
return 'inline';
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
protected function needsLabel() {
|
||||
// See \HTMLCheckField::needsLabel
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ use Skin;
|
|||
use SkinTemplate;
|
||||
use SkinVector;
|
||||
use User;
|
||||
use Vector\HTMLForm\Fields\HTMLLegacySkinVersionField;
|
||||
|
||||
/**
|
||||
* Presentation hook handlers for Vector skin.
|
||||
|
@ -158,7 +159,7 @@ class Hooks {
|
|||
// Preferences to add.
|
||||
$vectorPrefs = [
|
||||
Constants::PREF_KEY_SKIN_VERSION => [
|
||||
'type' => 'toggle',
|
||||
'class' => HTMLLegacySkinVersionField::class,
|
||||
// The checkbox title.
|
||||
'label-message' => 'prefs-vector-enable-vector-1-label',
|
||||
// Show a little informational snippet underneath the checkbox.
|
||||
|
@ -166,11 +167,10 @@ class Hooks {
|
|||
// The tab location and title of the section to insert the checkbox. The bit after the slash
|
||||
// indicates that a prefs-skin-prefs string will be provided.
|
||||
'section' => 'rendering/skin/skin-prefs',
|
||||
// Convert the preference string to a boolean presentation.
|
||||
'default' => self::isSkinVersionLegacy() ? '1' : '0',
|
||||
'default' => self::isSkinVersionLegacy(),
|
||||
// Only show this section when the Vector skin is checked. The JavaScript client also uses
|
||||
// this state to determine whether to show or hide the whole section.
|
||||
'hide-if' => [ '!==', 'wpskin', Constants::SKIN_NAME ]
|
||||
'hide-if' => [ '!==', 'wpskin', Constants::SKIN_NAME ],
|
||||
],
|
||||
Constants::PREF_KEY_SIDEBAR_VISIBLE => [
|
||||
'type' => 'api',
|
||||
|
@ -211,23 +211,15 @@ class Hooks {
|
|||
&$result,
|
||||
$oldPreferences
|
||||
) {
|
||||
$preference = null;
|
||||
$isVectorEnabled = ( $formData[ 'skin' ] ?? '' ) === Constants::SKIN_NAME;
|
||||
if ( $isVectorEnabled && array_key_exists( Constants::PREF_KEY_SKIN_VERSION, $formData ) ) {
|
||||
// A preference was set. However, Special:Preferences converts the result to a boolean when a
|
||||
// version name string is wanted instead. Convert the boolean to a version string in case the
|
||||
// preference display is changed to a list later (e.g., a "_new_ new Vector" / '3' or
|
||||
// 'alpha').
|
||||
$preference = $formData[ Constants::PREF_KEY_SKIN_VERSION ] ?
|
||||
Constants::SKIN_VERSION_LEGACY :
|
||||
Constants::SKIN_VERSION_LATEST;
|
||||
} elseif ( array_key_exists( Constants::PREF_KEY_SKIN_VERSION, $oldPreferences ) ) {
|
||||
|
||||
if ( !$isVectorEnabled && array_key_exists( Constants::PREF_KEY_SKIN_VERSION, $oldPreferences ) ) {
|
||||
// The setting was cleared. However, this is likely because a different skin was chosen and
|
||||
// the skin version preference was hidden.
|
||||
$preference = $oldPreferences[ Constants::PREF_KEY_SKIN_VERSION ];
|
||||
}
|
||||
if ( $preference !== null ) {
|
||||
$user->setOption( Constants::PREF_KEY_SKIN_VERSION, $preference );
|
||||
$user->setOption(
|
||||
Constants::PREF_KEY_SKIN_VERSION,
|
||||
$oldPreferences[ Constants::PREF_KEY_SKIN_VERSION ]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* @file
|
||||
*/
|
||||
|
||||
namespace MediaWiki\Skins\Vector\Tests\Integration;
|
||||
|
||||
use Vector\Constants;
|
||||
use Vector\HTMLForm\Fields\HTMLLegacySkinVersionField;
|
||||
|
||||
/**
|
||||
* @group Vector
|
||||
* @coversDefaultClass \Vector\HTMLForm\Fields\HTMLLegacySkinVersionField
|
||||
*/
|
||||
class HTMLLegacySkinVersionFieldTest extends \MediaWikiTestCase {
|
||||
|
||||
public function provideDefault() {
|
||||
yield [ 'true' ];
|
||||
yield [ 1 ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDefault
|
||||
* @covers ::__construct
|
||||
*/
|
||||
public function testConstructValidatesDefault( $default ) {
|
||||
$this->expectException( \Wikimedia\Assert\PreconditionException::class );
|
||||
|
||||
new HTMLLegacySkinVersionField( [
|
||||
'default' => $default
|
||||
] );
|
||||
}
|
||||
|
||||
public function provideGetInput() {
|
||||
yield [ Constants::SKIN_VERSION_LEGACY, true ];
|
||||
yield [ Constants::SKIN_VERSION_LATEST, false ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGetInput
|
||||
* @covers ::getInputHTML
|
||||
* @covers ::getInputOOUI
|
||||
*/
|
||||
public function testGetInput( $skinVersionValue, $checkValue ) {
|
||||
$params = [
|
||||
'fieldname' => 'VectorSkinVersion',
|
||||
'class' => HTMLLegacySkinVersionField::class,
|
||||
'section' => 'rendering/skin/skin-prefs',
|
||||
'label-message' => 'prefs-vector-enable-vector-1-label',
|
||||
'help-message' => 'prefs-vector-enable-vector-1-help',
|
||||
'default' => true,
|
||||
'hide-if' => [ '!==', 'wpskin', Constants::SKIN_NAME ],
|
||||
];
|
||||
$skinVersionField = new HTMLLegacySkinVersionField( $params );
|
||||
$checkField = new \HTMLCheckField( $params );
|
||||
|
||||
$this->assertSame(
|
||||
$skinVersionField->getInputHTML( $skinVersionValue ),
|
||||
$checkField->getInputHTML( $checkValue ),
|
||||
'::getInputHTML matches HTMLCheckField::getInputHTML with mapped value'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$skinVersionField->getInputOOUI( $skinVersionValue ),
|
||||
$checkField->getInputOOUI( $checkValue ),
|
||||
'::getInputOOUI matches HTMLCheckField::getInputOOUI with mapped value'
|
||||
);
|
||||
}
|
||||
|
||||
public function provideLoadDataFromRequest() {
|
||||
yield [ null, Constants::SKIN_VERSION_LEGACY ];
|
||||
yield [ true, Constants::SKIN_VERSION_LEGACY ];
|
||||
yield [ false, Constants::SKIN_VERSION_LATEST ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideLoadDataFromRequest
|
||||
* @covers ::loadDataFromRequest
|
||||
*/
|
||||
public function testLoadDataFromRequest( $wpVectorSkinVersion, $expectedResult ) {
|
||||
$skinVerionField = new HTMLLegacySkinVersionField( [
|
||||
'fieldname' => 'VectorSkinVersion',
|
||||
'default' => true,
|
||||
] );
|
||||
|
||||
$request = new \WebRequest();
|
||||
$request->setVal( 'wpVectorSkinVersion', $wpVectorSkinVersion );
|
||||
|
||||
$this->assertSame( $skinVerionField->loadDataFromRequest( $request ), $expectedResult );
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
use Vector\Constants;
|
||||
use Vector\FeatureManagement\FeatureManager;
|
||||
use Vector\Hooks;
|
||||
use Vector\HTMLForm\Fields\HTMLLegacySkinVersionField;
|
||||
|
||||
const SKIN_PREFS_SECTION = 'rendering/skin/skin-prefs';
|
||||
|
||||
|
@ -45,7 +46,8 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
* @covers ::onGetPreferences
|
||||
*/
|
||||
public function testOnGetPreferencesShowPreferencesEnabledSkinSectionFoundLegacy() {
|
||||
$this->setFeatureLatestSkinVersionIsEnabled( false );
|
||||
$isLegacy = true;
|
||||
$this->setFeatureLatestSkinVersionIsEnabled( !$isLegacy );
|
||||
|
||||
$prefs = [
|
||||
'foo' => [],
|
||||
|
@ -53,25 +55,24 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
'bar' => []
|
||||
];
|
||||
Hooks::onGetPreferences( $this->getTestUser()->getUser(), $prefs );
|
||||
$this->assertSame(
|
||||
$this->assertEquals(
|
||||
$prefs,
|
||||
[
|
||||
'foo' => [],
|
||||
'skin' => [],
|
||||
'VectorSkinVersion' => [
|
||||
'type' => 'toggle',
|
||||
'class' => HTMLLegacySkinVersionField::class,
|
||||
'label-message' => 'prefs-vector-enable-vector-1-label',
|
||||
'help-message' => 'prefs-vector-enable-vector-1-help',
|
||||
'section' => SKIN_PREFS_SECTION,
|
||||
// '1' is enabled which means Legacy.
|
||||
'default' => '1',
|
||||
'hide-if' => [ '!==', 'wpskin', 'vector' ]
|
||||
'default' => $isLegacy,
|
||||
'hide-if' => [ '!==', 'wpskin', Constants::SKIN_NAME ]
|
||||
],
|
||||
'VectorSidebarVisible' => [
|
||||
'type' => 'api',
|
||||
'default' => true
|
||||
],
|
||||
'bar' => []
|
||||
'bar' => [],
|
||||
],
|
||||
'Preferences are inserted directly after skin.'
|
||||
);
|
||||
|
@ -81,26 +82,26 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
* @covers ::onGetPreferences
|
||||
*/
|
||||
public function testOnGetPreferencesShowPreferencesEnabledSkinSectionMissingLegacy() {
|
||||
$this->setFeatureLatestSkinVersionIsEnabled( false );
|
||||
$isLegacy = false;
|
||||
$this->setFeatureLatestSkinVersionIsEnabled( !$isLegacy );
|
||||
|
||||
$prefs = [
|
||||
'foo' => [],
|
||||
'bar' => []
|
||||
];
|
||||
Hooks::onGetPreferences( $this->getTestUser()->getUser(), $prefs );
|
||||
$this->assertSame(
|
||||
$this->assertEquals(
|
||||
$prefs,
|
||||
[
|
||||
'foo' => [],
|
||||
'bar' => [],
|
||||
'VectorSkinVersion' => [
|
||||
'type' => 'toggle',
|
||||
'class' => HTMLLegacySkinVersionField::class,
|
||||
'label-message' => 'prefs-vector-enable-vector-1-label',
|
||||
'help-message' => 'prefs-vector-enable-vector-1-help',
|
||||
'section' => SKIN_PREFS_SECTION,
|
||||
// '1' is enabled which means Legacy.
|
||||
'default' => '1',
|
||||
'hide-if' => [ '!==', 'wpskin', 'vector' ]
|
||||
'default' => $isLegacy,
|
||||
'hide-if' => [ '!==', 'wpskin', Constants::SKIN_NAME ]
|
||||
],
|
||||
'VectorSidebarVisible' => [
|
||||
'type' => 'api',
|
||||
|
@ -111,88 +112,13 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::onGetPreferences
|
||||
*/
|
||||
public function testOnGetPreferencesShowPreferencesEnabledSkinSectionMissingLatest() {
|
||||
$this->setFeatureLatestSkinVersionIsEnabled( true );
|
||||
|
||||
$prefs = [
|
||||
'foo' => [],
|
||||
'bar' => [],
|
||||
];
|
||||
Hooks::onGetPreferences( $this->getTestUser()->getUser(), $prefs );
|
||||
$this->assertSame(
|
||||
$prefs,
|
||||
[
|
||||
'foo' => [],
|
||||
'bar' => [],
|
||||
'VectorSkinVersion' => [
|
||||
'type' => 'toggle',
|
||||
'label-message' => 'prefs-vector-enable-vector-1-label',
|
||||
'help-message' => 'prefs-vector-enable-vector-1-help',
|
||||
'section' => SKIN_PREFS_SECTION,
|
||||
// '0' is disabled (which means latest).
|
||||
'default' => '0',
|
||||
'hide-if' => [ '!==', 'wpskin', 'vector' ]
|
||||
],
|
||||
'VectorSidebarVisible' => [
|
||||
'type' => 'api',
|
||||
'default' => true
|
||||
],
|
||||
],
|
||||
'Legacy skin version is disabled.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::onPreferencesFormPreSave
|
||||
*/
|
||||
public function testOnPreferencesFormPreSaveVectorEnabledLegacyNewPreference() {
|
||||
$formData = [
|
||||
'skin' => 'vector',
|
||||
// True is Legacy.
|
||||
'VectorSkinVersion' => true,
|
||||
];
|
||||
$form = $this->createMock( HTMLForm::class );
|
||||
$user = $this->createMock( \User::class );
|
||||
$user->expects( $this->once() )
|
||||
->method( 'setOption' )
|
||||
// '1' is Legacy.
|
||||
->with( 'VectorSkinVersion', '1' );
|
||||
$result = true;
|
||||
$oldPreferences = [];
|
||||
|
||||
Hooks::onPreferencesFormPreSave( $formData, $form, $user, $result, $oldPreferences );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::onPreferencesFormPreSave
|
||||
*/
|
||||
public function testOnPreferencesFormPreSaveVectorEnabledLatestNewPreference() {
|
||||
$formData = [
|
||||
'skin' => 'vector',
|
||||
// False is latest.
|
||||
'VectorSkinVersion' => false,
|
||||
];
|
||||
$form = $this->createMock( HTMLForm::class );
|
||||
$user = $this->createMock( \User::class );
|
||||
$user->expects( $this->once() )
|
||||
->method( 'setOption' )
|
||||
// '2' is latest.
|
||||
->with( 'VectorSkinVersion', '2' );
|
||||
$result = true;
|
||||
$oldPreferences = [];
|
||||
|
||||
Hooks::onPreferencesFormPreSave( $formData, $form, $user, $result, $oldPreferences );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::onPreferencesFormPreSave
|
||||
*/
|
||||
public function testOnPreferencesFormPreSaveVectorEnabledNoNewPreference() {
|
||||
$formData = [
|
||||
'skin' => 'vector',
|
||||
'VectorSkinVersion' => Constants::SKIN_VERSION_LEGACY,
|
||||
];
|
||||
$form = $this->createMock( HTMLForm::class );
|
||||
$user = $this->createMock( \User::class );
|
||||
|
@ -209,8 +135,7 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
*/
|
||||
public function testOnPreferencesFormPreSaveVectorDisabledNoOldPreference() {
|
||||
$formData = [
|
||||
// False is latest.
|
||||
'VectorSkinVersion' => false,
|
||||
'VectorSkinVersion' => Constants::SKIN_VERSION_LATEST,
|
||||
];
|
||||
$form = $this->createMock( HTMLForm::class );
|
||||
$user = $this->createMock( \User::class );
|
||||
|
@ -227,8 +152,7 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
*/
|
||||
public function testOnPreferencesFormPreSaveVectorDisabledOldPreference() {
|
||||
$formData = [
|
||||
// False is latest.
|
||||
'VectorSkinVersion' => false,
|
||||
'VectorSkinVersion' => Constants::SKIN_VERSION_LATEST,
|
||||
];
|
||||
$form = $this->createMock( HTMLForm::class );
|
||||
$user = $this->createMock( \User::class );
|
||||
|
@ -248,16 +172,14 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
*/
|
||||
public function testOnLocalUserCreatedLegacy() {
|
||||
$config = new HashConfig( [
|
||||
// '1' is Legacy.
|
||||
'VectorDefaultSkinVersionForNewAccounts' => '1',
|
||||
'VectorDefaultSkinVersionForNewAccounts' => Constants::SKIN_VERSION_LEGACY,
|
||||
] );
|
||||
$this->setService( 'Vector.Config', $config );
|
||||
|
||||
$user = $this->createMock( \User::class );
|
||||
$user->expects( $this->once() )
|
||||
->method( 'setOption' )
|
||||
// '1' is Legacy.
|
||||
->with( 'VectorSkinVersion', '1' );
|
||||
->method( 'setOption' )
|
||||
->with( 'VectorSkinVersion', Constants::SKIN_VERSION_LEGACY );
|
||||
$isAutoCreated = false;
|
||||
Hooks::onLocalUserCreated( $user, $isAutoCreated );
|
||||
}
|
||||
|
@ -267,16 +189,14 @@ class VectorHooksTest extends \MediaWikiTestCase {
|
|||
*/
|
||||
public function testOnLocalUserCreatedLatest() {
|
||||
$config = new HashConfig( [
|
||||
// '2' is latest.
|
||||
'VectorDefaultSkinVersionForNewAccounts' => '2',
|
||||
'VectorDefaultSkinVersionForNewAccounts' => Constants::SKIN_VERSION_LATEST,
|
||||
] );
|
||||
$this->setService( 'Vector.Config', $config );
|
||||
|
||||
$user = $this->createMock( \User::class );
|
||||
$user->expects( $this->once() )
|
||||
->method( 'setOption' )
|
||||
// '2' is latest.
|
||||
->with( 'VectorSkinVersion', '2' );
|
||||
->method( 'setOption' )
|
||||
->with( 'VectorSkinVersion', Constants::SKIN_VERSION_LATEST );
|
||||
$isAutoCreated = false;
|
||||
Hooks::onLocalUserCreated( $user, $isAutoCreated );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue