MediaWiki REL1_37
BaseTemplate.php
Go to the documentation of this file.
1<?php
21use Wikimedia\WrappedString;
22use Wikimedia\WrappedStringList;
23
33abstract class BaseTemplate extends QuickTemplate {
34
41 public static function getCopyrightIconHTML( Config $config, Skin $skin ): string {
42 $out = '';
43 $footerIcons = $config->get( 'FooterIcons' );
44 $copyright = $footerIcons['copyright']['copyright'] ?? null;
45 // T291325: $wgFooterIcons['copyright']['copyright'] can return an array.
46 if ( $copyright !== null ) {
47 $out = $skin->makeFooterIcon( $copyright );
48 } elseif ( $config->get( 'RightsIcon' ) ) {
49 $icon = htmlspecialchars( $config->get( 'RightsIcon' ) );
50 $url = $config->get( 'RightsUrl' );
51 if ( $url ) {
52 $out .= '<a href="' . htmlspecialchars( $url ) . '">';
53 }
54 $text = htmlspecialchars( $config->get( 'RightsText' ) );
55 $out .= "<img src=\"$icon\" alt=\"$text\" width=\"88\" height=\"31\" />";
56 if ( $url ) {
57 $out .= '</a>';
58 }
59 }
60 return $out;
61 }
62
68 public static function getPoweredByHTML( Config $config ): string {
69 $resourceBasePath = $config->get( 'ResourceBasePath' );
70 $url1 = htmlspecialchars(
71 "$resourceBasePath/resources/assets/poweredby_mediawiki_88x31.png"
72 );
73 $url1_5 = htmlspecialchars(
74 "$resourceBasePath/resources/assets/poweredby_mediawiki_132x47.png"
75 );
76 $url2 = htmlspecialchars(
77 "$resourceBasePath/resources/assets/poweredby_mediawiki_176x62.png"
78 );
79 $text = '<a href="https://www.mediawiki.org/"><img src="' . $url1
80 . '" srcset="' . $url1_5 . ' 1.5x, ' . $url2 . ' 2x" '
81 . 'height="31" width="88" alt="Powered by MediaWiki" loading="lazy" /></a>';
82 return $text;
83 }
84
92 public function getMsg( $name, ...$params ) {
93 return $this->getSkin()->msg( $name, ...$params );
94 }
95
96 public function msg( $str ) {
97 echo $this->getMsg( $str )->escaped();
98 }
99
111 public function getToolbox() {
112 wfDeprecated( __METHOD__, '1.35' );
113
114 $toolbox = $this->getSkin()->makeToolbox(
115 $this->data['nav_urls'],
116 $this->data['feeds']
117 );
118
119 // Merge content that might be added to the toolbox section by hook
120 if ( isset( $this->data['sidebar']['TOOLBOX'] ) ) {
121 $toolbox = array_merge( $toolbox, $this->data['sidebar']['TOOLBOX'] ?? [] );
122 }
123
124 return $toolbox;
125 }
126
131 public function getPersonalTools() {
132 return $this->getSkin()->getPersonalToolsForMakeListItem( $this->get( 'personal_urls' ) );
133 }
134
140 protected function getSidebar( $options = [] ) {
141 // Force the rendering of the following portals
142 $sidebar = $this->data['sidebar'];
143 if ( !isset( $sidebar['SEARCH'] ) ) {
144 $sidebar['SEARCH'] = true;
145 }
146 if ( !isset( $sidebar['TOOLBOX'] ) ) {
147 $sidebar['TOOLBOX'] = true;
148 }
149 if ( !isset( $sidebar['LANGUAGES'] ) ) {
150 $sidebar['LANGUAGES'] = true;
151 }
152
153 if ( !isset( $options['search'] ) || $options['search'] !== true ) {
154 unset( $sidebar['SEARCH'] );
155 }
156 if ( isset( $options['toolbox'] ) && $options['toolbox'] === false ) {
157 unset( $sidebar['TOOLBOX'] );
158 }
159 if ( isset( $options['languages'] ) && $options['languages'] === false ) {
160 unset( $sidebar['LANGUAGES'] );
161 }
162
163 $boxes = [];
164 foreach ( $sidebar as $boxName => $content ) {
165 if ( $content === false ) {
166 continue;
167 }
168 switch ( $boxName ) {
169 case 'SEARCH':
170 // Search is a special case, skins should custom implement this
171 $boxes[$boxName] = [
172 'id' => 'p-search',
173 'header' => $this->getMsg( 'search' )->text(),
174 'generated' => false,
175 'content' => true,
176 ];
177 break;
178 case 'TOOLBOX':
179 $msgObj = $this->getMsg( 'toolbox' );
180 $boxes[$boxName] = [
181 'id' => 'p-tb',
182 'header' => $msgObj->exists() ? $msgObj->text() : 'toolbox',
183 'generated' => false,
184 'content' => $content,
185 ];
186 break;
187 case 'LANGUAGES':
188 if ( $this->data['language_urls'] !== false ) {
189 $msgObj = $this->getMsg( 'otherlanguages' );
190 $boxes[$boxName] = [
191 'id' => 'p-lang',
192 'header' => $msgObj->exists() ? $msgObj->text() : 'otherlanguages',
193 'generated' => false,
194 'content' => $this->data['language_urls'] ?: [],
195 ];
196 }
197 break;
198 default:
199 $msgObj = $this->getMsg( $boxName );
200 $boxes[$boxName] = [
201 'id' => "p-$boxName",
202 'header' => $msgObj->exists() ? $msgObj->text() : $boxName,
203 'generated' => true,
204 'content' => $content,
205 ];
206 break;
207 }
208 }
209
210 if ( isset( $options['htmlOnly'] ) && $options['htmlOnly'] === true ) {
211 foreach ( $boxes as $boxName => $box ) {
212 if ( is_array( $box['content'] ) ) {
213 $content = '<ul>';
214 foreach ( $box['content'] as $key => $val ) {
215 $content .= "\n " . $this->getSkin()->makeListItem( $key, $val );
216 }
217 $content .= "\n</ul>\n";
218 $boxes[$boxName]['content'] = $content;
219 }
220 }
221 }
222
223 return $boxes;
224 }
225
230 protected function renderAfterPortlet( $name ) {
231 wfDeprecated( __METHOD__, '1.35' );
232 echo $this->getAfterPortlet( $name );
233 }
234
245 protected function getAfterPortlet( $name ) {
246 wfDeprecated( __METHOD__, '1.35' );
247 $html = '';
248 $content = '';
249 $this->getHookRunner()->onBaseTemplateAfterPortlet( $this, $name, $content );
250 $content .= $this->getSkin()->getAfterPortlet( $name );
251
252 if ( $content !== '' ) {
253 $html = Html::rawElement(
254 'div',
255 [ 'class' => [ 'after-portlet', 'after-portlet-' . $name ] ],
257 );
258 }
259
260 return $html;
261 }
262
267 protected function makeLink( $key, $item, $options = [] ) {
268 return $this->getSkin()->makeLink( $key, $item, $options );
269 }
270
275 public function makeListItem( $key, $item, $options = [] ) {
276 return $this->getSkin()->makeListItem( $key, $item, $options );
277 }
278
282 protected function makeSearchInput( $attrs = [] ) {
283 return $this->getSkin()->makeSearchInput( $attrs );
284 }
285
289 protected function makeSearchButton( $mode, $attrs = [] ) {
290 return $this->getSkin()->makeSearchButton( $mode, $attrs );
291 }
292
302 protected function getFooterLinks( $option = null ) {
303 $footerlinks = $this->get( 'footerlinks' );
304
305 // Reduce footer links down to only those which are being used
306 $validFooterLinks = [];
307 foreach ( $footerlinks as $category => $links ) {
308 $validFooterLinks[$category] = [];
309 foreach ( $links as $link ) {
310 if ( isset( $this->data[$link] ) && $this->data[$link] ) {
311 $validFooterLinks[$category][] = $link;
312 }
313 }
314 if ( count( $validFooterLinks[$category] ) <= 0 ) {
315 unset( $validFooterLinks[$category] );
316 }
317 }
318
319 if ( $option == 'flat' && count( $validFooterLinks ) ) {
320 // fold footerlinks into a single array using a bit of trickery
321 $validFooterLinks = array_merge( ...array_values( $validFooterLinks ) );
322 }
323
324 return $validFooterLinks;
325 }
326
341 protected function getFooterIcons( $option = null ) {
342 wfDeprecated( __METHOD__, '1.35' );
343 // Generate additional footer icons
344 $footericons = $this->get( 'footericons' );
345
346 if ( $option == 'icononly' ) {
347 // Unset any icons which don't have an image
348 foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
349 foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
350 if ( !is_string( $footerIcon ) && !isset( $footerIcon['src'] ) ) {
351 unset( $footerIconsBlock[$footerIconKey] );
352 }
353 }
354 if ( $footerIconsBlock === [] ) {
355 unset( $footericons[$footerIconsKey] );
356 }
357 }
358 } elseif ( $option == 'nocopyright' ) {
359 unset( $footericons['copyright'] );
360 }
361
362 return $footericons;
363 }
364
374 protected function getFooter( $iconStyle = 'icononly', $linkStyle = 'flat' ) {
375 $validFooterIcons = $this->getFooterIcons( $iconStyle );
376 $validFooterLinks = $this->getFooterLinks( $linkStyle );
377
378 $html = '';
379
380 if ( count( $validFooterIcons ) + count( $validFooterLinks ) > 0 ) {
381 $html .= Html::openElement( 'div', [
382 'id' => 'footer-bottom',
383 'class' => 'mw-footer',
384 'role' => 'contentinfo',
385 'lang' => $this->get( 'userlang' ),
386 'dir' => $this->get( 'dir' )
387 ] );
388 $footerEnd = Html::closeElement( 'div' );
389 } else {
390 $footerEnd = '';
391 }
392 foreach ( $validFooterIcons as $blockName => $footerIcons ) {
393 $html .= Html::openElement( 'div', [
394 'id' => Sanitizer::escapeIdForAttribute( "f-{$blockName}ico" ),
395 'class' => 'footer-icons'
396 ] );
397 foreach ( $footerIcons as $icon ) {
398 $html .= $this->getSkin()->makeFooterIcon( $icon );
399 }
400 $html .= Html::closeElement( 'div' );
401 }
402 if ( count( $validFooterLinks ) > 0 ) {
403 $html .= Html::openElement( 'ul', [ 'id' => 'f-list', 'class' => 'footer-places' ] );
404 foreach ( $validFooterLinks as $aLink ) {
405 $html .= Html::rawElement(
406 'li',
407 [ 'id' => Sanitizer::escapeIdForAttribute( $aLink ) ],
408 $this->get( $aLink )
409 );
410 }
411 $html .= Html::closeElement( 'ul' );
412 }
413
414 $html .= $this->getClear() . $footerEnd;
415
416 return $html;
417 }
418
425 protected function getClear() {
426 return Html::element( 'div', [ 'class' => 'visualClear' ] );
427 }
428
444 public function getIndicators() {
445 $out = "<div class=\"mw-indicators\">\n";
446 foreach ( $this->data['indicators'] as $id => $content ) {
447 $out .= Html::rawElement(
448 'div',
449 [
450 'id' => Sanitizer::escapeIdForAttribute( "mw-indicator-$id" ),
451 'class' => 'mw-indicator',
452 ],
454 ) .
455 // Add whitespace between the <div>s because
456 // they get displayed with display: inline-block
457 "\n";
458 }
459 $out .= "</div>\n";
460 return $out;
461 }
462
466 protected function printTrail() {
467 echo $this->getTrail();
468 }
469
478 public function getTrail() {
479 return WrappedString::join( "\n", [
480 MWDebug::getDebugHTML( $this->getSkin()->getContext() ),
481 $this->get( 'bottomscripts' ),
482 $this->get( 'reporttime' )
483 ] );
484 }
485}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
getContext()
Extended QuickTemplate with additional MediaWiki-specific helper methods.
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 and...
getTrail()
Get the basic end-page trail including bottomscripts, reporttime, and debug stuff.
printTrail()
Output getTrail.
makeLink( $key, $item, $options=[])
getSidebar( $options=[])
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=[])
getMsg( $name,... $params)
Get a Message object with its context set.
static getCopyrightIconHTML(Config $config, Skin $skin)
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.
static getPoweredByHTML(Config $config)
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.
PHP-based skin template that holds data.
The main skin class which provides methods and properties for all other skins.
Definition Skin.php:44
makeFooterIcon( $icon, $withImage='withImage')
Renders a $wgFooterIcons icon according to the method's arguments.
Definition Skin.php:1020
Interface for configuration instances.
Definition Config.php:30
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
$content
Definition router.php:76