diff --git a/includes/Components/VectorComponentTableOfContents.php b/includes/Components/VectorComponentTableOfContents.php index 0a4275f2b..edcee1a35 100644 --- a/includes/Components/VectorComponentTableOfContents.php +++ b/includes/Components/VectorComponentTableOfContents.php @@ -2,6 +2,8 @@ namespace MediaWiki\Skins\Vector\Components; use Config; +use MediaWiki\Skins\Vector\Constants; +use MediaWiki\Skins\Vector\FeatureManagement\FeatureManager; use MessageLocalizer; /** @@ -31,22 +33,23 @@ class VectorComponentTableOfContents implements VectorComponent { * @param array $tocData * @param MessageLocalizer $localizer * @param Config $config + * @param FeatureManager $featureManager */ public function __construct( array $tocData, MessageLocalizer $localizer, - Config $config + Config $config, + FeatureManager $featureManager ) { $this->tocData = $tocData; $this->localizer = $localizer; - // ToC is pinned by default, hardcoded for now - $this->isPinned = true; + $this->isPinned = $featureManager->isFeatureEnabled( Constants::FEATURE_TOC_PINNED ); $this->config = $config; $this->pinnableHeader = new VectorComponentPinnableHeader( $this->localizer, $this->isPinned, self::ID, - null, + 'toc-pinned', false, 'h2' ); diff --git a/includes/Constants.php b/includes/Constants.php index 100104488..c323b812b 100644 --- a/includes/Constants.php +++ b/includes/Constants.php @@ -220,6 +220,21 @@ final class Constants { */ public const PREF_KEY_PAGE_TOOLS_PINNED = 'vector-page-tools-pinned'; + /** + * @var string + */ + public const REQUIREMENT_TOC_PINNED = 'TOCPinned'; + + /** + * @var string + */ + public const PREF_KEY_TOC_PINNED = 'vector-toc-pinned'; + + /** + * @var string + */ + public const FEATURE_TOC_PINNED = 'TOCPinned'; + /** * @var string */ diff --git a/includes/Hooks.php b/includes/Hooks.php index c64177739..9c927317d 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -628,6 +628,9 @@ class Hooks implements Constants::PREF_KEY_MAIN_MENU_PINNED => [ 'type' => 'api' ], + Constants::PREF_KEY_TOC_PINNED => [ + 'type' => 'api' + ], Constants::PREF_KEY_LIMITED_WIDTH => [ 'type' => 'toggle', 'label-message' => 'vector-prefs-limited-width', diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index e5fc0b6c7..0cc6a3cb8 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -217,6 +217,26 @@ return [ ] ); + // Feature: Table of Contents pinned + // ================================ + $featureManager->registerRequirement( + new UserPreferenceRequirement( + $context->getUser(), + $services->getUserOptionsLookup(), + Constants::PREF_KEY_TOC_PINNED, + Constants::REQUIREMENT_TOC_PINNED, + $context->getTitle() + ) + ); + + $featureManager->registerFeature( + Constants::FEATURE_TOC_PINNED, + [ + Constants::REQUIREMENT_FULLY_INITIALISED, + Constants::REQUIREMENT_TOC_PINNED + ] + ); + // Feature: Main menu pinned // ================================ $featureManager->registerRequirement( diff --git a/includes/SkinVector22.php b/includes/SkinVector22.php index 334c52f27..8c702f8a9 100644 --- a/includes/SkinVector22.php +++ b/includes/SkinVector22.php @@ -349,7 +349,8 @@ class SkinVector22 extends SkinMustache { $dataToc = new VectorComponentTableOfContents( $parentData['data-toc'], $localizer, - $this->getConfig() + $this->getConfig(), + VectorServices::getFeatureManager() ); $tocComponents = [ 'data-toc' => $dataToc, diff --git a/includes/templates/PageTitlebar.mustache b/includes/templates/PageTitlebar.mustache index dbdd0ba1c..70c447985 100644 --- a/includes/templates/PageTitlebar.mustache +++ b/includes/templates/PageTitlebar.mustache @@ -22,6 +22,9 @@ {{#data-page-titlebar-toc-dropdown}}{{>Dropdown/Open}}{{/data-page-titlebar-toc-dropdown}} {{#data-page-titlebar-toc-pinnable-container}} {{>PinnableContainer/Unpinned/Open}} + {{^is-pinned}} + {{#data-toc}}{{>TableOfContents}}{{/data-toc}} + {{/is-pinned}} {{>PinnableContainer/Close}} {{/data-page-titlebar-toc-pinnable-container}} {{#data-page-titlebar-toc-dropdown}}{{>Dropdown/Close}}{{/data-page-titlebar-toc-dropdown}} diff --git a/resources/skins.vector.es6/main.js b/resources/skins.vector.es6/main.js index 28605970c..7150d6566 100644 --- a/resources/skins.vector.es6/main.js +++ b/resources/skins.vector.es6/main.js @@ -8,6 +8,7 @@ const initSectionObserver = require( './sectionObserver.js' ), initTableOfContents = require( './tableOfContents.js' ), pinnableElement = require( './pinnableElement.js' ), + features = require( './features.js' ), deferUntilFrame = require( './deferUntilFrame.js' ), ABTestConfig = require( /** @type {string} */ ( './config.json' ) ).wgVectorWebABTestEnrollment || {}, STICKY_HEADER_VISIBLE_CLASS = 'vector-sticky-header-visible', @@ -111,8 +112,7 @@ function initStickyHeaderABTests( abConfig, isStickyHeaderFeatureAllowed, getEna * @return {void} */ const updateTocLocation = () => { - const TOC_PINNED_CLASS = 'vector-toc-pinned'; - const isPinned = document.body.classList.contains( TOC_PINNED_CLASS ); + const isPinned = features.isEnabled( 'toc-pinned' ); const isStickyHeaderVisible = document.body.classList.contains( STICKY_HEADER_VISIBLE_CLASS ); const isBelowDesktop = belowDesktopMedia.matches; diff --git a/skin.json b/skin.json index f932882d0..437d5dd21 100644 --- a/skin.json +++ b/skin.json @@ -40,8 +40,7 @@ }, "bodyClasses": [ "skin-vector", - "skin-vector-search-vue", - "vector-toc-pinned" + "skin-vector-search-vue" ], "menus": [ "user-interface-preferences", @@ -167,7 +166,9 @@ "DefaultUserOptions": { "vector-limited-width": 1, "vector-page-tools-pinned": 1, - "vector-main-menu-pinned": 1 + "vector-main-menu-pinned": 1, + "vector-toc-pinned": 1 + }, "HookHandlers": { "VectorHooks": { diff --git a/tests/phpunit/unit/components/VectorComponentTableOfContentsTest.php b/tests/phpunit/unit/components/VectorComponentTableOfContentsTest.php index 8f45751bc..5b394ac1a 100644 --- a/tests/phpunit/unit/components/VectorComponentTableOfContentsTest.php +++ b/tests/phpunit/unit/components/VectorComponentTableOfContentsTest.php @@ -23,6 +23,7 @@ namespace MediaWiki\Skins\Vector\Tests\Unit\Components; use HashConfig; use MediaWiki\Skins\Vector\Components\VectorComponentTableOfContents; +use MediaWiki\Skins\Vector\FeatureManagement\FeatureManager; use Message; use MessageLocalizer; @@ -113,7 +114,7 @@ class VectorComponentTableOfContentsTest extends \MediaWikiUnitTestCase { 'data-pinnable-header' => [ 'is-pinned' => true, 'data-name' => 'vector-toc', - 'data-feature-name' => null, + 'data-feature-name' => 'toc-pinned', 'label' => 'vector-toc-label', 'unpin-label' => 'vector-unpin-element-label', 'pin-label' => 'vector-pin-element-label', @@ -188,11 +189,14 @@ class VectorComponentTableOfContentsTest extends \MediaWikiUnitTestCase { $msg->method( 'text' )->willReturn( $key ); return $msg; } ); + $featureManager = $this->createMock( FeatureManager::class ); + $featureManager->method( 'isFeatureEnabled' )->willReturn( true ); $toc = new VectorComponentTableOfContents( $tocData, $localizer, - new HashConfig( $config ) + new HashConfig( $config ), + $featureManager ); $this->assertEquals( $expected, $toc->getTemplateData() ); }