Thanks link and other links should be styled consistently with other links
[mediawiki.git] / includes / skins / components / SkinComponentMenu.php
blob42991ceec10d82e1b32c79557772dfd0bbd5a580
1 <?php
3 namespace MediaWiki\Skin;
5 use MediaWiki\Html\Html;
6 use MediaWiki\Linker\Linker;
7 use MediaWiki\Message\Message;
8 use MediaWiki\Parser\Sanitizer;
9 use MessageLocalizer;
11 /**
12 * @internal for use inside Skin and SkinTemplate classes only
13 * @unstable
15 class SkinComponentMenu implements SkinComponent {
17 /** @var string */
18 private $name;
20 /** @var array */
21 private $items;
23 /** @var MessageLocalizer */
24 private $localizer;
26 /** @var string */
27 private $content;
29 /** @var array */
30 private $linkOptions;
32 /** @var string */
33 private $htmlAfterContent;
35 /** @var string */
36 private $htmlBeforeContent;
38 /**
39 * @param string $name
40 * @param array $items
41 * @param MessageLocalizer $localizer
42 * @param string $content
43 * @param array $linkOptions
44 * @param string $htmlAfterContent
45 * @param string $htmlBeforeContent
47 public function __construct(
48 string $name,
49 array $items,
50 MessageLocalizer $localizer,
51 string $content = '',
52 array $linkOptions = [],
53 string $htmlAfterContent = '',
54 string $htmlBeforeContent = ''
55 ) {
56 $this->name = $name;
57 $this->items = $items;
58 $this->localizer = $localizer;
59 $this->content = $content;
60 $this->linkOptions = $linkOptions;
61 $this->htmlAfterContent = $htmlAfterContent;
62 $this->htmlBeforeContent = $htmlBeforeContent;
65 private function msg( string $key ): Message {
66 return $this->localizer->msg( $key );
69 /**
70 * @param string $name of the menu e.g. p-personal the name is personal.
72 * @return string that is human-readable corresponding to the menu.
74 private function getMenuLabel( $name ) {
75 // For historic reasons for some menu items, there is no language key corresponding
76 // with its menu key.
77 $mappings = [
78 'tb' => 'toolbox',
79 'personal' => 'personaltools',
80 'lang' => 'otherlanguages',
82 $msgObj = $this->msg( $mappings[ $name ] ?? $name );
83 // If no message exists fallback to plain text (T252727)
84 return $msgObj->exists() ? $msgObj->text() : $name;
87 /**
88 * @inheritDoc
90 public function getTemplateData(): array {
91 $name = $this->name;
92 // Monobook and Vector historically render this portal as an element with ID p-cactions.
93 // To ensure compatibility with gadgets, it is renamed accordingly.
94 // @todo Port p-#cactions to #p-actions and drop these conditionals.
95 if ( $name === 'actions' ) {
96 $name = 'cactions';
99 // The new personal tools without the notifications is user-menu.
100 // A lot of user code and gadgets relies on it being named personal.
101 // This allows it to function as a drop-in replacement.
102 if ( $name === 'user-menu' ) {
103 $name = 'personal';
106 if ( strpos( $name, 'footer' ) === 0 ) {
107 // Retain footer IDs.
108 $id = $name;
109 } else {
110 $id = Sanitizer::escapeIdForAttribute( "p-$name" );
113 $isEmptyContent = !$this->content;
114 $isEmptyAfterContent = !$this->htmlAfterContent;
115 $isEmptyBeforeContent = !$this->htmlBeforeContent;
116 $isEmptyItems = count( $this->items ) === 0;
117 $isEmptyPortlet = ( $isEmptyContent && $isEmptyAfterContent && $isEmptyBeforeContent && $isEmptyItems );
118 $data = [
119 'id' => $id,
120 // Any changes to these classes should be synced with resources/src/mediawiki.util/util.js
121 'class' => 'mw-portlet ' . Sanitizer::escapeClass( "mw-portlet-$name" ),
122 'html-tooltip' => Linker::tooltip( $id ),
123 'html-items' => '',
124 // Will be populated by SkinAfterPortlet hook.
125 'html-after-portal' => '',
126 'html-before-portal' => '',
127 'is-empty' => $isEmptyPortlet,
130 // for output. In production this currently supports the Wikibase 'edit' link.
131 if ( !$isEmptyAfterContent ) {
132 $data['html-after-portal'] = Html::rawElement(
133 'div',
135 'class' => [
136 'after-portlet',
137 Sanitizer::escapeClass( "after-portlet-$name" ),
140 $this->htmlAfterContent
144 if ( !$isEmptyBeforeContent ) {
145 $data['html-before-portal'] = Html::rawElement(
146 'div',
148 'class' => [
149 'before-portlet',
150 Sanitizer::escapeClass( "before-portlet-$name" ),
153 $this->htmlBeforeContent
157 $html = '';
158 $arrayItems = [];
159 foreach ( $this->items as $key => $item ) {
160 $item = new SkinComponentListItem( $key, $item, $this->localizer, [], $this->linkOptions );
161 $itemData = $item->getTemplateData();
162 $html .= $itemData['html-item'];
163 $arrayItems[] = $itemData;
165 $data['html-items'] = $html;
166 $data['array-items'] = $arrayItems;
168 $data['label'] = $this->getMenuLabel( $name );
169 $data['class'] .= $isEmptyPortlet ? ' emptyPortlet' : '';
170 return $data;