diff --git a/includes/Components/VectorComponentDropdown.php b/includes/Components/VectorComponentDropdown.php new file mode 100644 index 000000000..94e9c43c7 --- /dev/null +++ b/includes/Components/VectorComponentDropdown.php @@ -0,0 +1,55 @@ +id = $id; + $this->label = $label; + $this->class = $class; + $this->icon = $icon; + $this->tooltip = $tooltip; + } + + /** + * @inheritDoc + */ + public function getTemplateData(): array { + $icon = $this->icon; + $headingClass = $icon ? + 'mw-checkbox-hack-button mw-ui-icon mw-ui-button mw-ui-quiet ' . + 'mw-ui-icon-element mw-ui-icon-wikimedia-' . $icon : ''; + + return [ + 'id' => $this->id, + 'label' => $this->label, + 'heading-class' => $headingClass, + 'html-vector-menu-heading-attributes' => '', + 'html-vector-menu-checkbox-attributes' => '', + 'html-vector-heading-icon' => '', + 'class' => $this->class, + 'html-tooltip' => $this->tooltip, + 'checkbox-class' => '', + ]; + } +} diff --git a/includes/Components/VectorComponentMainMenu.php b/includes/Components/VectorComponentMainMenu.php index d0f4a244b..1b7241d5d 100644 --- a/includes/Components/VectorComponentMainMenu.php +++ b/includes/Components/VectorComponentMainMenu.php @@ -92,22 +92,15 @@ class VectorComponentMainMenu implements VectorComponent { $action = $this->optOut; $alert = $this->alert; + $id = 'vector-main-menu'; $pinnableHeader = new VectorComponentPinnableHeader( $this->localizer, false, - 'vector-main-menu', + $id, null ); - $class = $this->getUser()->isAnon() ? 'vector-main-menu-btn-dropdown-anon ' : ''; - $class .= 'vector-main-menu'; return $this->fillMissingData( $this->sidebarData ) + [ - 'id' => 'vector-main-menu', - 'class' => $class, - 'label' => $this->localizer->msg( 'vector-main-menu-label' )->text(), - // @todo: Helper method for making icon classes would be useful. - 'heading-class' => 'mw-checkbox-hack-button mw-ui-icon mw-ui-button ' - . 'mw-ui-quiet mw-ui-icon-wikimedia-menu mw-ui-icon-element', 'data-main-menu-action' => $action ? $action->getTemplateData() : null, // T295555 Add language switch alert message temporarily (to be removed). 'data-vector-language-switch-alert' => $alert ? $alert->getTemplateData() : null, diff --git a/includes/Components/VectorComponentPageTools.php b/includes/Components/VectorComponentPageTools.php index cfad96b28..926361381 100644 --- a/includes/Components/VectorComponentPageTools.php +++ b/includes/Components/VectorComponentPageTools.php @@ -58,16 +58,15 @@ class VectorComponentPageTools implements VectorComponent { */ public function getTemplateData(): array { $menusData = [ $this->toolbox, $this->actionsMenu ]; + $id = 'vector-page-tools'; + $pinnedContainer = new VectorComponentPinnedContainer( $id, $this->isPinned ); + $pinnableElement = new VectorComponentPinnableElement( $id ); - $pinnableDropdownData = [ - 'id' => 'vector-page-tools', - 'class' => 'vector-page-tools', - 'label' => $this->skin->msg( 'toolbox' ), - 'is-pinned' => $this->isPinned, - 'has-multiple-menus' => true, + $data = $pinnableElement->getTemplateData() + + $pinnedContainer->getTemplateData(); + return $data + [ 'data-pinnable-header' => $this->pinnableHeader ? $this->pinnableHeader->getTemplateData() : null, - 'data-menus' => $menusData + 'data-menus' => $menusData, ]; - return $pinnableDropdownData; } } diff --git a/includes/Components/VectorComponentPinnableElement.php b/includes/Components/VectorComponentPinnableElement.php new file mode 100644 index 000000000..754ec3975 --- /dev/null +++ b/includes/Components/VectorComponentPinnableElement.php @@ -0,0 +1,26 @@ +id = $id; + } + + /** + * @inheritDoc + */ + public function getTemplateData(): array { + return [ + 'id' => $this->id, + ]; + } +} diff --git a/includes/Components/VectorComponentPinnedContainer.php b/includes/Components/VectorComponentPinnedContainer.php new file mode 100644 index 000000000..8d58af737 --- /dev/null +++ b/includes/Components/VectorComponentPinnedContainer.php @@ -0,0 +1,32 @@ +id = $id; + $this->isPinned = $isPinned; + } + + /** + * @inheritDoc + */ + public function getTemplateData(): array { + return [ + 'id' => $this->id, + 'is-pinned' => $this->isPinned, + ]; + } +} diff --git a/includes/Components/VectorComponentTableOfContents.php b/includes/Components/VectorComponentTableOfContents.php index 7d58acdca..cfa1469fe 100644 --- a/includes/Components/VectorComponentTableOfContents.php +++ b/includes/Components/VectorComponentTableOfContents.php @@ -10,6 +10,9 @@ class VectorComponentTableOfContents implements VectorComponent { * @inheritDoc */ public function getTemplateData(): array { - return []; + $pinnableElementName = 'vector-toc'; + $pinnedContainer = new VectorComponentPinnedContainer( $pinnableElementName ); + $pinnableElement = new VectorComponentPinnableElement( $pinnableElementName ); + return $pinnableElement->getTemplateData() + $pinnedContainer->getTemplateData(); } } diff --git a/includes/SkinVector.php b/includes/SkinVector.php index 345d126d1..a07c79966 100644 --- a/includes/SkinVector.php +++ b/includes/SkinVector.php @@ -27,6 +27,8 @@ namespace MediaWiki\Skins\Vector; use ExtensionRegistry; use Linker; use MediaWiki\MediaWikiServices; +use MediaWiki\Skins\Vector\Components\VectorComponent; +use MediaWiki\Skins\Vector\Components\VectorComponentDropdown; use MediaWiki\Skins\Vector\Components\VectorComponentLanguageButton; use MediaWiki\Skins\Vector\Components\VectorComponentUserLinks; use RuntimeException; @@ -283,7 +285,7 @@ abstract class SkinVector extends SkinMustache { $returnto = $this->getReturnToParam(); $useCombinedLoginLink = $this->useCombinedLoginLink(); $userMenuOverflowData = Hooks::updateDropdownMenuData( $overflowMenuData ); - $userMenuData = Hooks::updateDropdownMenuData( $this->getUserMenuPortletData( $userMenuData ) ); + $userMenu = $this->getUserMenuDropdown( $userMenuData ); unset( $userMenuOverflowData[ 'label' ] ); if ( $isAnon || $isTempUser ) { @@ -309,7 +311,8 @@ abstract class SkinVector extends SkinMustache { 'is-temp-user' => $isTempUser, 'is-wide' => $moreItems > 3, 'data-user-menu-overflow' => $userMenuOverflowData, - 'data-user-menu' => $userMenuData + 'data-user-menu' => $userMenu->getTemplateData(), + 'html-items' => $userMenuData['html-items'], ]; } @@ -513,9 +516,9 @@ abstract class SkinVector extends SkinMustache { * FIXME: Move to VectorComponentUserMenu * * @param array $portletData - * @return array + * @return VectorComponent */ - private function getUserMenuPortletData( $portletData ) { + private function getUserMenuDropdown( $portletData ): VectorComponent { // T317789: Core can undesirably add an 'emptyPortlet' class that hides the // user menu. This is a result of us manually removing items from the menu // in Hooks::updateUserLinksDropdownItems which can make @@ -543,9 +546,8 @@ abstract class SkinVector extends SkinMustache { // This overrides the tooltip for the user links menu icon which is an ellipsis for anonymous users. $portletData['html-tooltip'] = Linker::tooltip( 'vector-anon-user-menu-title' ); } - $portletData['icon'] = $icon; - $portletData['button'] = true; - $portletData['text-hidden'] = true; - return $portletData; + return new VectorComponentDropdown( + $portletData['id'], $portletData['label'], $portletData['class'], $icon, $portletData['html-tooltip'] ?? '' + ); } } diff --git a/includes/SkinVector22.php b/includes/SkinVector22.php index f9bdb976a..a516ac96d 100644 --- a/includes/SkinVector22.php +++ b/includes/SkinVector22.php @@ -3,6 +3,7 @@ namespace MediaWiki\Skins\Vector; use MediaWiki\MediaWikiServices; +use MediaWiki\Skins\Vector\Components\VectorComponentDropdown; use MediaWiki\Skins\Vector\Components\VectorComponentMainMenu; use MediaWiki\Skins\Vector\Components\VectorComponentPageTools; use MediaWiki\Skins\Vector\Components\VectorComponentPinnableHeader; @@ -71,7 +72,6 @@ class SkinVector22 extends SkinVector { // ToC is pinned by default, hardcoded for now $isTocPinned = true; - $pinnableElementName = 'vector-toc'; $pinnableHeader = new VectorComponentPinnableHeader( $this->getContext(), $isTocPinned, @@ -89,8 +89,6 @@ class SkinVector22 extends SkinVector { $tocData[ 'number-section-count'] >= $this->getConfig()->get( 'VectorTableOfContentsCollapseAtCount' ), - // Needed for PinnedContainer - 'id' => $pinnableElementName, 'is-pinned' => $isTocPinned, 'data-pinnable-header' => $pinnableHeader->getTemplateData(), ] ); @@ -237,6 +235,15 @@ class SkinVector22 extends SkinVector { } } $config = $this->getConfig(); + $mainMenuDropdownClass = $this->getUser()->isAnon() ? 'vector-main-menu-btn-dropdown-anon ' : ''; + $mainMenuDropdownClass .= 'vector-main-menu-dropdown'; + $mainMenuDropdown = new VectorComponentDropdown( + 'vector-main-menu-dropdown', + $this->msg( 'vector-main-menu-label' )->text(), + $mainMenuDropdownClass, + 'menu' + ); + $components = [ 'data-search-box' => new VectorComponentSearchBox( $parentData['data-search-box'], @@ -249,6 +256,7 @@ class SkinVector22 extends SkinVector { Constants::SEARCH_BOX_INPUT_LOCATION_MOVED, $this->getContext() ), + 'data-main-menu-dropdown' => $mainMenuDropdown, 'data-portlets-main-menu' => new VectorComponentMainMenu( $sidebar, $this, @@ -261,6 +269,8 @@ class SkinVector22 extends SkinVector { $isPageToolsPinned, $this ) : null, + 'data-page-tools-dropdown' => $isPageToolsEnabled ? + new VectorComponentDropdown( 'vector-page-tools', $this->msg( 'toolbox' )->text() ) : null, ]; foreach ( $components as $key => $component ) { // Array of components or null values. diff --git a/includes/templates/MainMenuDropdown.mustache b/includes/templates/MainMenuDropdown.mustache index b03e5be62..cd35fee5f 100644 --- a/includes/templates/MainMenuDropdown.mustache +++ b/includes/templates/MainMenuDropdown.mustache @@ -1,4 +1,4 @@ {{! Use `.vector-main-menu.vector-dropdown` to target styles at this element}} -{{>Dropdown/Open}} +{{#data-main-menu-dropdown}}{{>Dropdown/Open}}{{/data-main-menu-dropdown}} {{#data-portlets-main-menu}}{{>MainMenuContents}}{{/data-portlets-main-menu}} -{{>Dropdown/Close}} +{{#data-main-menu-dropdown}}{{>Dropdown/Close}}{{/data-main-menu-dropdown}} diff --git a/includes/templates/PageToolbar.mustache b/includes/templates/PageToolbar.mustache index 5eccf3952..e73e1829a 100644 --- a/includes/templates/PageToolbar.mustache +++ b/includes/templates/PageToolbar.mustache @@ -13,13 +13,15 @@ diff --git a/tests/phpunit/integration/SkinVectorTest.php b/tests/phpunit/integration/SkinVectorTest.php index 9f9bafeca..00ebc9722 100644 --- a/tests/phpunit/integration/SkinVectorTest.php +++ b/tests/phpunit/integration/SkinVectorTest.php @@ -132,7 +132,6 @@ class SkinVectorTest extends MediaWikiIntegrationTestCase { 'pin-label' => '(vector-pin-element-label)', 'label-tag-name' => 'h2' ], - 'id' => 'vector-toc', 'is-pinned' => true, ]; $expectedNestedTocData = array_merge( $nestedTocData, $expectedConfigData ); diff --git a/tests/phpunit/unit/components/VectorComponentTableOfContentsTest.php b/tests/phpunit/unit/components/VectorComponentTableOfContentsTest.php new file mode 100644 index 000000000..389b66c56 --- /dev/null +++ b/tests/phpunit/unit/components/VectorComponentTableOfContentsTest.php @@ -0,0 +1,45 @@ +assertEquals( + [ + 'id' => 'vector-toc', + 'is-pinned' => true, + ], + $toc->getTemplateData() + ); + } +}