MediaWiki fundraising/REL1_35
BaseTemplate.php
Go to the documentation of this file.
1<?php
21use Wikimedia\WrappedString;
22use Wikimedia\WrappedStringList;
23
31abstract class BaseTemplate extends QuickTemplate {
32
40 public function getMsg( $name, ...$params ) {
41 return $this->getSkin()->msg( $name, ...$params );
42 }
43
44 public function msg( $str ) {
45 echo $this->getMsg( $str )->escaped();
46 }
47
59 public function getToolbox() {
60 $toolbox = $this->getSkin()->makeToolbox(
61 $this->data['nav_urls'],
62 $this->data['feeds']
63 );
64
65 // Merge content that might be added to the toolbox section by hook
66 if ( isset( $this->data['sidebar']['TOOLBOX'] ) ) {
67 $toolbox = array_merge( $toolbox, $this->data['sidebar']['TOOLBOX'] ?? [] );
68 }
69
70 // T253416: Deprecated hook
71 $this->getHookRunner()->onBaseTemplateToolbox( $this, $toolbox );
72 return $toolbox;
73 }
74
79 public function getPersonalTools() {
80 return $this->getSkin()->getPersonalToolsForMakeListItem( $this->get( 'personal_urls' ) );
81 }
82
88 protected function getSidebar( $options = [] ) {
89 // Force the rendering of the following portals
90 $sidebar = $this->data['sidebar'];
91 if ( !isset( $sidebar['SEARCH'] ) ) {
92 $sidebar['SEARCH'] = true;
93 }
94 if ( !isset( $sidebar['TOOLBOX'] ) ) {
95 $sidebar['TOOLBOX'] = true;
96 }
97 if ( !isset( $sidebar['LANGUAGES'] ) ) {
98 $sidebar['LANGUAGES'] = true;
99 }
100
101 if ( !isset( $options['search'] ) || $options['search'] !== true ) {
102 unset( $sidebar['SEARCH'] );
103 }
104 if ( isset( $options['toolbox'] ) && $options['toolbox'] === false ) {
105 unset( $sidebar['TOOLBOX'] );
106 }
107 if ( isset( $options['languages'] ) && $options['languages'] === false ) {
108 unset( $sidebar['LANGUAGES'] );
109 }
110
111 $boxes = [];
112 foreach ( $sidebar as $boxName => $content ) {
113 if ( $content === false ) {
114 continue;
115 }
116 switch ( $boxName ) {
117 case 'SEARCH':
118 // Search is a special case, skins should custom implement this
119 $boxes[$boxName] = [
120 'id' => 'p-search',
121 'header' => $this->getMsg( 'search' )->text(),
122 'generated' => false,
123 'content' => true,
124 ];
125 break;
126 case 'TOOLBOX':
127 $msgObj = $this->getMsg( 'toolbox' );
128 $boxes[$boxName] = [
129 'id' => 'p-tb',
130 'header' => $msgObj->exists() ? $msgObj->text() : 'toolbox',
131 'generated' => false,
132 'content' => $this->getToolbox(),
133 ];
134 break;
135 case 'LANGUAGES':
136 if ( $this->data['language_urls'] !== false ) {
137 $msgObj = $this->getMsg( 'otherlanguages' );
138 $boxes[$boxName] = [
139 'id' => 'p-lang',
140 'header' => $msgObj->exists() ? $msgObj->text() : 'otherlanguages',
141 'generated' => false,
142 'content' => $this->data['language_urls'] ?: [],
143 ];
144 }
145 break;
146 default:
147 $msgObj = $this->getMsg( $boxName );
148 $boxes[$boxName] = [
149 'id' => "p-$boxName",
150 'header' => $msgObj->exists() ? $msgObj->text() : $boxName,
151 'generated' => true,
152 'content' => $content,
153 ];
154 break;
155 }
156 }
157
158 // HACK: Compatibility with extensions still using SkinTemplateToolboxEnd
159 $hookContents = null;
160 if ( isset( $boxes['TOOLBOX'] ) ) {
161 ob_start();
162 // We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
163 // can abort and avoid outputting double toolbox links
164 $this->getHookRunner()->onSkinTemplateToolboxEnd( $this, true );
165 $hookContents = ob_get_contents();
166 ob_end_clean();
167 if ( !trim( $hookContents ) ) {
168 $hookContents = null;
169 }
170 }
171 // END hack
172
173 if ( isset( $options['htmlOnly'] ) && $options['htmlOnly'] === true ) {
174 foreach ( $boxes as $boxName => $box ) {
175 if ( is_array( $box['content'] ) ) {
176 $content = '<ul>';
177 foreach ( $box['content'] as $key => $val ) {
178 $content .= "\n " . $this->getSkin()->makeListItem( $key, $val );
179 }
180 // HACK, shove the toolbox end onto the toolbox if we're rendering itself
181 if ( $hookContents ) {
182 $content .= "\n $hookContents";
183 }
184 // END hack
185 $content .= "\n</ul>\n";
186 $boxes[$boxName]['content'] = $content;
187 }
188 }
189 } elseif ( $hookContents ) {
190 $boxes['TOOLBOXEND'] = [
191 'id' => 'p-toolboxend',
192 'header' => $boxes['TOOLBOX']['header'],
193 'generated' => false,
194 'content' => "<ul>{$hookContents}</ul>",
195 ];
196 // HACK: Make sure that TOOLBOXEND is sorted next to TOOLBOX
197 $boxes2 = [];
198 foreach ( $boxes as $key => $box ) {
199 if ( $key === 'TOOLBOXEND' ) {
200 continue;
201 }
202 $boxes2[$key] = $box;
203 if ( $key === 'TOOLBOX' ) {
204 $boxes2['TOOLBOXEND'] = $boxes['TOOLBOXEND'];
205 }
206 }
207 $boxes = $boxes2;
208 // END hack
209 }
210
211 return $boxes;
212 }
213
218 protected function renderAfterPortlet( $name ) {
219 echo $this->getAfterPortlet( $name );
220 }
221
232 protected function getAfterPortlet( $name ) {
233 $html = '';
234 $content = '';
235 $this->getHookRunner()->onBaseTemplateAfterPortlet( $this, $name, $content );
236 $content .= $this->getSkin()->getAfterPortlet( $name );
237
238 if ( $content !== '' ) {
239 $html = Html::rawElement(
240 'div',
241 [ 'class' => [ 'after-portlet', 'after-portlet-' . $name ] ],
243 );
244 }
245
246 return $html;
247 }
248
253 protected function makeLink( $key, $item, $options = [] ) {
254 return $this->getSkin()->makeLink( $key, $item, $options );
255 }
256
261 public function makeListItem( $key, $item, $options = [] ) {
262 return $this->getSkin()->makeListItem( $key, $item, $options );
263 }
264
268 protected function makeSearchInput( $attrs = [] ) {
269 return $this->getSkin()->makeSearchInput( $attrs );
270 }
271
275 protected function makeSearchButton( $mode, $attrs = [] ) {
276 return $this->getSkin()->makeSearchButton( $mode, $attrs );
277 }
278
288 protected function getFooterLinks( $option = null ) {
289 $footerlinks = $this->get( 'footerlinks' );
290
291 // Reduce footer links down to only those which are being used
292 $validFooterLinks = [];
293 foreach ( $footerlinks as $category => $links ) {
294 $validFooterLinks[$category] = [];
295 foreach ( $links as $link ) {
296 if ( isset( $this->data[$link] ) && $this->data[$link] ) {
297 $validFooterLinks[$category][] = $link;
298 }
299 }
300 if ( count( $validFooterLinks[$category] ) <= 0 ) {
301 unset( $validFooterLinks[$category] );
302 }
303 }
304
305 if ( $option == 'flat' && count( $validFooterLinks ) ) {
306 // fold footerlinks into a single array using a bit of trickery
307 $validFooterLinks = array_merge( ...array_values( $validFooterLinks ) );
308 }
309
310 return $validFooterLinks;
311 }
312
327 protected function getFooterIcons( $option = null ) {
328 // Generate additional footer icons
329 $footericons = $this->get( 'footericons' );
330
331 if ( $option == 'icononly' ) {
332 // Unset any icons which don't have an image
333 foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
334 foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
335 if ( !is_string( $footerIcon ) && !isset( $footerIcon['src'] ) ) {
336 unset( $footerIconsBlock[$footerIconKey] );
337 }
338 }
339 if ( $footerIconsBlock === [] ) {
340 unset( $footericons[$footerIconsKey] );
341 }
342 }
343 } elseif ( $option == 'nocopyright' ) {
344 unset( $footericons['copyright'] );
345 }
346
347 return $footericons;
348 }
349
359 protected function getFooter( $iconStyle = 'icononly', $linkStyle = 'flat' ) {
360 $validFooterIcons = $this->getFooterIcons( $iconStyle );
361 $validFooterLinks = $this->getFooterLinks( $linkStyle );
362
363 $html = '';
364
365 if ( count( $validFooterIcons ) + count( $validFooterLinks ) > 0 ) {
366 $html .= Html::openElement( 'div', [
367 'id' => 'footer-bottom',
368 'class' => 'mw-footer',
369 'role' => 'contentinfo',
370 'lang' => $this->get( 'userlang' ),
371 'dir' => $this->get( 'dir' )
372 ] );
373 $footerEnd = Html::closeElement( 'div' );
374 } else {
375 $footerEnd = '';
376 }
377 foreach ( $validFooterIcons as $blockName => $footerIcons ) {
378 $html .= Html::openElement( 'div', [
379 'id' => Sanitizer::escapeIdForAttribute( "f-{$blockName}ico" ),
380 'class' => 'footer-icons'
381 ] );
382 foreach ( $footerIcons as $icon ) {
383 $html .= $this->getSkin()->makeFooterIcon( $icon );
384 }
385 $html .= Html::closeElement( 'div' );
386 }
387 if ( count( $validFooterLinks ) > 0 ) {
388 $html .= Html::openElement( 'ul', [ 'id' => 'f-list', 'class' => 'footer-places' ] );
389 foreach ( $validFooterLinks as $aLink ) {
390 $html .= Html::rawElement(
391 'li',
392 [ 'id' => Sanitizer::escapeIdForAttribute( $aLink ) ],
393 $this->get( $aLink )
394 );
395 }
396 $html .= Html::closeElement( 'ul' );
397 }
398
399 $html .= $this->getClear() . $footerEnd;
400
401 return $html;
402 }
403
410 protected function getClear() {
411 return Html::element( 'div', [ 'class' => 'visualClear' ] );
412 }
413
429 public function getIndicators() {
430 $out = "<div class=\"mw-indicators mw-body-content\">\n";
431 foreach ( $this->data['indicators'] as $id => $content ) {
432 $out .= Html::rawElement(
433 'div',
434 [
435 'id' => Sanitizer::escapeIdForAttribute( "mw-indicator-$id" ),
436 'class' => 'mw-indicator',
437 ],
439 ) . "\n";
440 }
441 $out .= "</div>\n";
442 return $out;
443 }
444
448 protected function printTrail() {
449 echo $this->getTrail();
450 }
451
460 public function getTrail() {
461 return WrappedString::join( "\n", [
462 MWDebug::getDebugHTML( $this->getSkin()->getContext() ),
463 $this->get( 'bottomscripts' ),
464 $this->get( 'reporttime' )
465 ] );
466 }
467}
getContext()
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 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.
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.
Generic wrapper for template functions, with interface compatible with what we use of PHPTAL 0....
getSkin()
Get the Skin object related to this object.
$content
Definition router.php:76