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