21 use Wikimedia\WrappedString;
22 use Wikimedia\WrappedStringList;
38 public function getMsg( $name, ...$params ) {
39 return $this->
getSkin()->msg( $name, ...$params );
42 function msg( $str ) {
43 echo $this->
getMsg( $str )->escaped();
51 echo $this->
getMsg( $str )->parseAsBlock();
63 if ( isset( $this->data[
'nav_urls'][
'whatlinkshere'] )
64 && $this->data[
'nav_urls'][
'whatlinkshere']
66 $toolbox[
'whatlinkshere'] = $this->data[
'nav_urls'][
'whatlinkshere'];
67 $toolbox[
'whatlinkshere'][
'id'] =
't-whatlinkshere';
69 if ( isset( $this->data[
'nav_urls'][
'recentchangeslinked'] )
70 && $this->data[
'nav_urls'][
'recentchangeslinked']
72 $toolbox[
'recentchangeslinked'] = $this->data[
'nav_urls'][
'recentchangeslinked'];
73 $toolbox[
'recentchangeslinked'][
'msg'] =
'recentchangeslinked-toolbox';
74 $toolbox[
'recentchangeslinked'][
'id'] =
't-recentchangeslinked';
75 $toolbox[
'recentchangeslinked'][
'rel'] =
'nofollow';
77 if ( isset( $this->data[
'feeds'] ) && $this->data[
'feeds'] ) {
78 $toolbox[
'feeds'][
'id'] =
'feedlinks';
79 $toolbox[
'feeds'][
'links'] = [];
80 foreach ( $this->data[
'feeds'] as $key => $feed ) {
81 $toolbox[
'feeds'][
'links'][$key] = $feed;
82 $toolbox[
'feeds'][
'links'][$key][
'id'] =
"feed-$key";
83 $toolbox[
'feeds'][
'links'][$key][
'rel'] =
'alternate';
84 $toolbox[
'feeds'][
'links'][$key][
'type'] =
"application/{$key}+xml";
85 $toolbox[
'feeds'][
'links'][$key][
'class'] =
'feedlink';
88 foreach ( [
'contributions',
'log',
'blockip',
'emailuser',
'mute',
89 'userrights',
'upload',
'specialpages' ] as $special
91 if ( isset( $this->data[
'nav_urls'][$special] ) && $this->data[
'nav_urls'][$special] ) {
92 $toolbox[$special] = $this->data[
'nav_urls'][$special];
93 $toolbox[$special][
'id'] =
"t-$special";
96 if ( isset( $this->data[
'nav_urls'][
'print'] ) && $this->data[
'nav_urls'][
'print'] ) {
97 $toolbox[
'print'] = $this->data[
'nav_urls'][
'print'];
98 $toolbox[
'print'][
'id'] =
't-print';
99 $toolbox[
'print'][
'rel'] =
'alternate';
100 $toolbox[
'print'][
'msg'] =
'printableversion';
102 if ( isset( $this->data[
'nav_urls'][
'permalink'] ) && $this->data[
'nav_urls'][
'permalink'] ) {
103 $toolbox[
'permalink'] = $this->data[
'nav_urls'][
'permalink'];
104 $toolbox[
'permalink'][
'id'] =
't-permalink';
106 if ( isset( $this->data[
'nav_urls'][
'info'] ) && $this->data[
'nav_urls'][
'info'] ) {
107 $toolbox[
'info'] = $this->data[
'nav_urls'][
'info'];
108 $toolbox[
'info'][
'id'] =
't-info';
113 Hooks::run(
'BaseTemplateToolbox', [ &$template, &$toolbox ] );
128 $personal_tools = [];
129 foreach ( $this->
get(
'personal_urls' ) as $key => $plink ) {
130 # The class on a personal_urls item is meant to go on the <a> instead
131 # of the <li> so we have to use a single item "links" array instead
132 # of using most of the personal_url's keys directly.
135 [
'single-id' =>
"pt-$key" ],
139 if ( isset( $plink[
'active'] ) ) {
140 $ptool[
'active'] = $plink[
'active'];
151 if ( isset( $plink[$k] ) ) {
152 $ptool[
'links'][0][$k] = $plink[$k];
155 $personal_tools[$key] = $ptool;
157 return $personal_tools;
162 $sidebar = $this->data[
'sidebar'];
163 if ( !isset( $sidebar[
'SEARCH'] ) ) {
164 $sidebar[
'SEARCH'] =
true;
166 if ( !isset( $sidebar[
'TOOLBOX'] ) ) {
167 $sidebar[
'TOOLBOX'] =
true;
169 if ( !isset( $sidebar[
'LANGUAGES'] ) ) {
170 $sidebar[
'LANGUAGES'] =
true;
173 if ( !isset( $options[
'search'] ) || $options[
'search'] !==
true ) {
174 unset( $sidebar[
'SEARCH'] );
176 if ( isset( $options[
'toolbox'] ) && $options[
'toolbox'] ===
false ) {
177 unset( $sidebar[
'TOOLBOX'] );
179 if ( isset( $options[
'languages'] ) && $options[
'languages'] ===
false ) {
180 unset( $sidebar[
'LANGUAGES'] );
184 foreach ( $sidebar as $boxName =>
$content ) {
188 switch ( $boxName ) {
193 'header' => $this->
getMsg(
'search' )->text(),
194 'generated' =>
false,
199 $msgObj = $this->
getMsg(
'toolbox' );
202 'header' => $msgObj->exists() ? $msgObj->text() :
'toolbox',
203 'generated' =>
false,
208 if ( $this->data[
'language_urls'] !==
false ) {
209 $msgObj = $this->
getMsg(
'otherlanguages' );
212 'header' => $msgObj->exists() ? $msgObj->text() :
'otherlanguages',
213 'generated' =>
false,
214 'content' => $this->data[
'language_urls'] ?: [],
219 $msgObj = $this->
getMsg( $boxName );
221 'id' =>
"p-$boxName",
222 'header' => $msgObj->exists() ? $msgObj->text() : $boxName,
231 $hookContents =
null;
232 if ( isset( $boxes[
'TOOLBOX'] ) ) {
238 Hooks::run(
'SkinTemplateToolboxEnd', [ &$template,
true ] );
239 $hookContents = ob_get_contents();
241 if ( !trim( $hookContents ) ) {
242 $hookContents =
null;
247 if ( isset( $options[
'htmlOnly'] ) && $options[
'htmlOnly'] ===
true ) {
248 foreach ( $boxes as $boxName => $box ) {
249 if ( is_array( $box[
'content'] ) ) {
251 foreach ( $box[
'content'] as $key => $val ) {
255 if ( $hookContents ) {
260 $boxes[$boxName][
'content'] =
$content;
263 } elseif ( $hookContents ) {
264 $boxes[
'TOOLBOXEND'] = [
265 'id' =>
'p-toolboxend',
266 'header' => $boxes[
'TOOLBOX'][
'header'],
267 'generated' =>
false,
268 'content' =>
"<ul>{$hookContents}</ul>",
272 foreach ( $boxes as $key => $box ) {
273 if ( $key ===
'TOOLBOXEND' ) {
276 $boxes2[$key] = $box;
277 if ( $key ===
'TOOLBOX' ) {
278 $boxes2[
'TOOLBOXEND'] = $boxes[
'TOOLBOXEND'];
311 [
'class' => [
'after-portlet',
'after-portlet-' . $name ] ],
372 $text = $item[
'text'] ??
wfMessage( $item[
'msg'] ?? $key )->text();
374 $html = htmlspecialchars( $text );
376 if ( isset( $options[
'text-wrapper'] ) ) {
377 $wrapper = $options[
'text-wrapper'];
378 if ( isset( $wrapper[
'tag'] ) ) {
379 $wrapper = [ $wrapper ];
381 while ( count( $wrapper ) > 0 ) {
382 $element = array_pop( $wrapper );
383 $html =
Html::rawElement( $element[
'tag'], $element[
'attributes'] ??
null, $html );
387 if ( isset( $item[
'href'] ) || isset( $options[
'link-fallback'] ) ) {
389 foreach ( [
'single-id',
'text',
'msg',
'tooltiponly',
'context',
'primary',
390 'tooltip-params',
'exists' ] as $k ) {
394 if ( isset( $attrs[
'data'] ) ) {
395 foreach ( $attrs[
'data'] as $key => $value ) {
396 $attrs[
'data-' . $key ] = $value;
398 unset( $attrs[
'data' ] );
401 if ( isset( $item[
'id'] ) && !isset( $item[
'single-id'] ) ) {
402 $item[
'single-id'] = $item[
'id'];
406 if ( isset( $item[
'tooltip-params'] ) ) {
407 $tooltipParams = $item[
'tooltip-params'];
410 if ( isset( $item[
'single-id'] ) ) {
411 $tooltipOption = isset( $item[
'exists'] ) && $item[
'exists'] ===
false ?
'nonexisting' :
null;
413 if ( isset( $item[
'tooltiponly'] ) && $item[
'tooltiponly'] ) {
424 if ( isset( $tip[
'title'] ) && $tip[
'title'] !==
false ) {
425 $attrs[
'title'] = $tip[
'title'];
427 if ( isset( $tip[
'accesskey'] ) && $tip[
'accesskey'] !==
false ) {
428 $attrs[
'accesskey'] = $tip[
'accesskey'];
432 if ( isset( $options[
'link-class'] ) ) {
433 if ( isset( $attrs[
'class'] ) ) {
434 $attrs[
'class'] .=
" {$options['link-class']}";
436 $attrs[
'class'] = $options[
'link-class'];
441 : $options[
'link-fallback'], $attrs, $html );
481 unset( $item[
'redundant'] );
483 if ( isset( $item[
'links'] ) ) {
485 foreach ( $item[
'links'] as $linkKey => $link ) {
486 $links[] = $this->
makeLink( $linkKey, $link, $options );
488 $html = implode(
' ', $links );
492 foreach ( [
'id',
'class',
'active',
'tag',
'itemtitle' ] as $k ) {
495 if ( isset( $item[
'id'] ) && !isset( $item[
'single-id'] ) ) {
499 $link[
'single-id'] = $item[
'id'];
501 if ( isset( $link[
'link-class'] ) ) {
504 $link[
'class'] = $link[
'link-class'];
505 unset( $link[
'link-class'] );
507 $html = $this->
makeLink( $key, $link, $options );
511 foreach ( [
'id',
'class' ] as $attr ) {
512 if ( isset( $item[$attr] ) ) {
513 $attrs[$attr] = $item[$attr];
516 if ( isset( $item[
'active'] ) && $item[
'active'] ) {
517 if ( !isset( $attrs[
'class'] ) ) {
518 $attrs[
'class'] =
'';
520 $attrs[
'class'] .=
' active';
521 $attrs[
'class'] = trim( $attrs[
'class'] );
523 if ( isset( $item[
'itemtitle'] ) ) {
524 $attrs[
'title'] = $item[
'itemtitle'];
533 'placeholder' =>
wfMessage(
'searchsuggest-search' )->text(),
546 'value' =>
wfMessage( $mode ==
'go' ?
'searcharticle' :
'searchbutton' )->text(),
548 $realAttrs = array_merge(
559 $buttonAttrs = array_merge(
564 unset( $buttonAttrs[
'src'] );
565 unset( $buttonAttrs[
'alt'] );
566 unset( $buttonAttrs[
'width'] );
567 unset( $buttonAttrs[
'height'] );
569 'src' => $attrs[
'src'],
570 'alt' => $attrs[
'alt'] ??
wfMessage(
'searchbutton' )->text(),
571 'width' => $attrs[
'width'] ??
null,
572 'height' => $attrs[
'height'] ??
null,
576 throw new MWException(
'Unknown mode passed to BaseTemplate::makeSearchButton' );
590 $footerlinks = $this->
get(
'footerlinks' );
593 $validFooterLinks = [];
594 foreach ( $footerlinks as $category => $links ) {
595 $validFooterLinks[$category] = [];
596 foreach ( $links as $link ) {
597 if ( isset( $this->data[$link] ) && $this->data[$link] ) {
598 $validFooterLinks[$category][] = $link;
601 if ( count( $validFooterLinks[$category] ) <= 0 ) {
602 unset( $validFooterLinks[$category] );
606 if ( $option ==
'flat' ) {
608 $validFooterLinks = array_merge( ...array_values( $validFooterLinks ) );
611 return $validFooterLinks;
628 $footericons = $this->
get(
'footericons' );
630 if ( $option ==
'icononly' ) {
632 foreach ( $footericons as &$footerIconsBlock ) {
633 foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
634 if ( !is_string( $footerIcon ) && !isset( $footerIcon[
'src'] ) ) {
635 unset( $footerIconsBlock[$footerIconKey] );
640 foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
641 if ( count( $footerIconsBlock ) <= 0 ) {
642 unset( $footericons[$footerIconsKey] );
645 } elseif ( $option ==
'nocopyright' ) {
646 unset( $footericons[
'copyright'][
'copyright'] );
647 if ( count( $footericons[
'copyright'] ) <= 0 ) {
648 unset( $footericons[
'copyright'] );
664 protected function getFooter( $iconStyle =
'icononly', $linkStyle =
'flat' ) {
670 if ( count( $validFooterIcons ) + count( $validFooterLinks ) > 0 ) {
672 'id' =>
'footer-bottom',
673 'role' =>
'contentinfo',
674 'lang' => $this->
get(
'userlang' ),
675 'dir' => $this->
get(
'dir' )
681 foreach ( $validFooterIcons as $blockName => $footerIcons ) {
684 'class' =>
'footer-icons'
686 foreach ( $footerIcons as $icon ) {
687 $html .= $this->
getSkin()->makeFooterIcon( $icon );
691 if ( count( $validFooterLinks ) > 0 ) {
692 $html .=
Html::openElement(
'ul', [
'id' =>
'f-list',
'class' =>
'footer-places' ] );
693 foreach ( $validFooterLinks as $aLink ) {
703 $html .= $this->
getClear() . $footerEnd;
734 $out =
"<div class=\"mw-indicators mw-body-content\">\n";
735 foreach ( $this->data[
'indicators'] as $id =>
$content ) {
740 'class' =>
'mw-indicator',
765 return WrappedString::join(
"\n", [
768 $this->
get(
'bottomscripts' ),
769 $this->
get(
'reporttime' )