21use Wikimedia\WrappedString;
22use 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'];
306 Hooks::run(
'BaseTemplateAfterPortlet', [ $this, $name, &
$content ] );
309 $html = Html::rawElement(
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'];
439 $html = Html::rawElement( isset( $attrs[
'href'] )
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'];
526 return Html::rawElement( $options[
'tag'] ??
'li', $attrs, $html );
533 'placeholder' =>
wfMessage(
'searchsuggest-search' )->text(),
536 return Html::element(
'input', $realAttrs );
546 'value' =>
wfMessage( $mode ==
'go' ?
'searcharticle' :
'searchbutton' )->
text(),
548 $realAttrs = array_merge(
553 return Html::element(
'input', $realAttrs );
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,
574 return Html::rawElement(
'button', $buttonAttrs, Html::element(
'img', $imgAttrs ) );
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 ) {
671 $html .= Html::openElement(
'div', [
672 'id' =>
'footer-bottom',
673 'role' =>
'contentinfo',
674 'lang' => $this->
get(
'userlang' ),
675 'dir' => $this->
get(
'dir' )
677 $footerEnd = Html::closeElement(
'div' );
681 foreach ( $validFooterIcons as $blockName => $footerIcons ) {
682 $html .= Html::openElement(
'div', [
683 'id' => Sanitizer::escapeIdForAttribute(
"f-{$blockName}ico" ),
684 'class' =>
'footer-icons'
686 foreach ( $footerIcons as $icon ) {
687 $html .= $this->
getSkin()->makeFooterIcon( $icon );
689 $html .= Html::closeElement(
'div' );
691 if ( count( $validFooterLinks ) > 0 ) {
692 $html .= Html::openElement(
'ul', [
'id' =>
'f-list',
'class' =>
'footer-places' ] );
693 foreach ( $validFooterLinks as $aLink ) {
694 $html .= Html::rawElement(
696 [
'id' => Sanitizer::escapeIdForAttribute( $aLink ) ],
700 $html .= Html::closeElement(
'ul' );
703 $html .= $this->
getClear() . $footerEnd;
715 return Html::element(
'div', [
'class' =>
'visualClear' ] );
734 $out =
"<div class=\"mw-indicators mw-body-content\">\n";
735 foreach ( $this->data[
'indicators'] as $id =>
$content ) {
736 $out .= Html::rawElement(
739 'id' => Sanitizer::escapeIdForAttribute(
"mw-indicator-$id" ),
740 'class' =>
'mw-indicator',
765 return WrappedString::join(
"\n", [
768 $this->
get(
'bottomscripts' ),
769 $this->
get(
'reporttime' )
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
New base template for a skin's template extended from QuickTemplate this class features helper method...
getFooterLinks( $option=null)
Returns an array of footerlinks trimmed down to only those footer links that are valid.
makeSearchButton( $mode, $attrs=[])
renderAfterPortlet( $name)
getToolbox()
Create an array of common toolbox items from the data in the quicktemplate stored by SkinTemplate.
getTrail()
Get the basic end-page trail including bottomscripts, reporttime, and debug stuff.
printTrail()
Output getTrail.
makeLink( $key, $item, $options=[])
Makes a link, usually used by makeListItem to generate a link for an item in a list used in navigatio...
getPersonalTools()
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
getFooterIcons( $option=null)
Returns an array of footer icons filtered down by options relevant to how the skin wishes to display ...
makeListItem( $key, $item, $options=[])
Generates a list item for a navigation, portlet, portal, sidebar... list.
getMsg( $name,... $params)
Get a Message object with its context set.
getIndicators()
Get the suggested HTML for page status indicators: icons (or short text snippets) usually displayed i...
makeSearchInput( $attrs=[])
getFooter( $iconStyle='icononly', $linkStyle='flat')
Renderer for getFooterIcons and getFooterLinks.
getClear()
Get a div with the core visualClear class, for clearing floats.
getAfterPortlet( $name)
Allows extensions to hook into known portlets and add stuff to them.
static titleAttrib( $name, $options=null, array $msgParams=[])
Given the id of an interface element, constructs the appropriate title attribute from the system mess...
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Generic wrapper for template functions, with interface compatible with what we use of PHPTAL 0....
getSkin()
Get the Skin object related to this object.