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