Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
18.68% covered (danger)
18.68%
17 / 91
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SkinVectorLegacy
18.68% covered (danger)
18.68%
17 / 91
16.67% covered (danger)
16.67%
1 / 6
333.74
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 runOnSkinTemplateNavigationHooks
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 decoratePortletsData
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 decoratePortletData
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
240
 updatePortletClasses
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 getTemplateData
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace MediaWiki\Skins\Vector;
4
5use MediaWiki\Languages\LanguageConverterFactory;
6use MediaWiki\Skin\SkinMustache;
7use MediaWiki\Skin\SkinTemplate;
8use MediaWiki\Skins\Vector\Components\VectorComponentSearchBox;
9use MediaWiki\Skins\Vector\Components\VectorComponentVariants;
10
11/**
12 * @ingroup Skins
13 * @package Vector
14 * @internal
15 */
16class SkinVectorLegacy extends SkinMustache {
17    /** @var int */
18    private const MENU_TYPE_DEFAULT = 0;
19    /** @var int */
20    private const MENU_TYPE_TABS = 1;
21    /** @var int */
22    private const MENU_TYPE_DROPDOWN = 2;
23    private const MENU_TYPE_PORTAL = 3;
24
25    public function __construct(
26        private readonly LanguageConverterFactory $languageConverterFactory,
27        array $options
28    ) {
29        parent::__construct( $options );
30    }
31
32    /**
33     * @inheritDoc
34     */
35    protected function runOnSkinTemplateNavigationHooks( SkinTemplate $skin, &$content_navigation ) {
36        parent::runOnSkinTemplateNavigationHooks( $skin, $content_navigation );
37        Hooks::onSkinTemplateNavigation( $skin, $content_navigation );
38    }
39
40    /**
41     * Performs updates to all portlets.
42     *
43     * @param array $data
44     * @return array
45     */
46    private function decoratePortletsData( array $data ) {
47        foreach ( $data['data-portlets'] as $key => $pData ) {
48            $data['data-portlets'][$key] = $this->decoratePortletData(
49                $key,
50                $pData
51            );
52        }
53        $mainMenuData = $data['data-portlets-sidebar'];
54        $mainMenuData['data-portlets-first'] = $this->decoratePortletData(
55            'navigation', $mainMenuData['data-portlets-first']
56        );
57        $rest = $mainMenuData['array-portlets-rest'];
58        foreach ( $rest as $key => $pData ) {
59            $rest[$key] = $this->decoratePortletData(
60                $pData['id'], $pData
61            );
62        }
63        $mainMenuData['array-portlets-rest'] = $rest;
64        $data['data-portlets-main-menu'] = $mainMenuData;
65        return $data;
66    }
67
68    /**
69     * Performs the following updates to portlet data:
70     * - Adds concept of menu types
71     * - Marks the selected variant in the variant portlet
72     * - modifies tooltips of personal and user-menu portlets
73     * @param string $key
74     * @param array $portletData
75     * @return array
76     */
77    private function decoratePortletData(
78        string $key,
79        array $portletData
80    ): array {
81        $isIconDropdown = false;
82        switch ( $key ) {
83            case 'data-user-menu':
84                $type = self::MENU_TYPE_DROPDOWN;
85                $isIconDropdown = true;
86                break;
87            case 'data-actions':
88            case 'data-variants':
89            case 'data-sticky-header-toc':
90                $type = self::MENU_TYPE_DROPDOWN;
91                break;
92            case 'data-views':
93            case 'data-associated-pages':
94            case 'data-namespaces':
95                $type = self::MENU_TYPE_TABS;
96                break;
97            case 'data-notifications':
98            case 'data-personal':
99            case 'data-user-page':
100            case 'data-vector-user-menu-overflow':
101                $type = self::MENU_TYPE_DEFAULT;
102                break;
103            default:
104                $type = self::MENU_TYPE_PORTAL;
105                break;
106        }
107
108        if ( $key === 'data-personal' ) {
109            // Set tooltip to empty string for the personal menu for both logged-in and logged-out users
110            // to avoid showing the tooltip for legacy version.
111            $portletData['html-tooltip'] = '';
112            $portletData['class'] .= ' vector-user-menu-legacy';
113        }
114
115        // Special casing for Variant to change label to selected.
116        // Hopefully we can revisit and possibly remove this code when the language switcher is moved.
117        if ( $key === 'data-variants' ) {
118            $variant = new VectorComponentVariants(
119                $this->languageConverterFactory,
120                $portletData,
121                $this->getTitle()->getPageLanguage(),
122                $this->msg( 'vector-language-variant-switcher-label' )
123            );
124            $portletData[ 'label' ] = $variant->getTemplateData()[ 'data-variants-dropdown' ][ 'label' ];
125        }
126
127        $portletData = $this->updatePortletClasses(
128            $portletData,
129            $type
130        );
131
132        return $portletData + [
133            'is-dropdown' => $type === self::MENU_TYPE_DROPDOWN,
134            'is-portal' => $type === self::MENU_TYPE_PORTAL,
135        ];
136    }
137
138    /**
139     * Helper for applying Vector menu classes to portlets
140     *
141     * @param array $portletData returned by SkinMustache to decorate
142     * @param int $type representing one of the menu types (see MENU_TYPE_* constants)
143     * @return array modified version of portletData input
144     */
145    private function updatePortletClasses(
146        array $portletData,
147        int $type = self::MENU_TYPE_DEFAULT
148    ) {
149        $extraClasses = [
150            self::MENU_TYPE_DROPDOWN => 'vector-menu-dropdown',
151            self::MENU_TYPE_TABS => 'vector-menu-tabs vector-menu-tabs-legacy',
152            self::MENU_TYPE_PORTAL => 'vector-menu-portal portal',
153            self::MENU_TYPE_DEFAULT => '',
154        ];
155        $portletData['class'] .= ' ' . $extraClasses[$type];
156
157        if ( !isset( $portletData['heading-class'] ) ) {
158            $portletData['heading-class'] = '';
159        }
160
161        $portletData['class'] = trim( $portletData['class'] );
162        $portletData['heading-class'] = trim( $portletData['heading-class'] );
163        return $portletData;
164    }
165
166    /**
167     * @inheritDoc
168     */
169    public function getTemplateData(): array {
170        $parentData = $this->decoratePortletsData( parent::getTemplateData() );
171
172        $components = [
173            'data-search-box' => new VectorComponentSearchBox(
174                $parentData['data-search-box'],
175                false,
176                // is primary mode of search
177                true,
178                'searchform',
179                true,
180                $this->getConfig(),
181                Constants::SEARCH_BOX_INPUT_LOCATION_DEFAULT,
182                $this->getContext()
183            ),
184        ];
185        foreach ( $components as $key => $component ) {
186            $parentData[$key] = $component->getTemplateData();
187        }
188
189        // SkinVector sometimes serves new Vector as part of removing the
190        // skin version user preference. To avoid T302461 we need to unset it here.
191        // This shouldn't be run on SkinVector22.
192        unset( $parentData['data-toc'] );
193        return $parentData;
194    }
195}