MediaWiki  master
BaseTemplate.php
Go to the documentation of this file.
1 <?php
21 use Wikimedia\WrappedString;
22 use Wikimedia\WrappedStringList;
23 
29 abstract class BaseTemplate extends QuickTemplate {
30 
38  public function getMsg( $name, ...$params ) {
39  return $this->getSkin()->msg( $name, ...$params );
40  }
41 
42  public function msg( $str ) {
43  echo $this->getMsg( $str )->escaped();
44  }
45 
54  public function getToolbox() {
55  $toolbox = $this->getSkin()->makeToolbox(
56  $this->data['nav_urls'],
57  $this->data['feeds']
58  );
59 
60  // Merge content that might be added to the toolbox section by hook
61  if ( isset( $this->data['sidebar']['TOOLBOX'] ) ) {
62  $toolbox = array_merge( $toolbox, $this->data['sidebar']['TOOLBOX'] ?? [] );
63  }
64 
65  $this->getHookRunner()->onBaseTemplateToolbox( $this, $toolbox );
66  return $toolbox;
67  }
68 
73  public function getPersonalTools() {
74  return $this->getSkin()->getPersonalToolsForMakeListItem( $this->get( 'personal_urls' ) );
75  }
76 
82  protected function getSidebar( $options = [] ) {
83  // Force the rendering of the following portals
84  $sidebar = $this->data['sidebar'];
85  if ( !isset( $sidebar['SEARCH'] ) ) {
86  $sidebar['SEARCH'] = true;
87  }
88  if ( !isset( $sidebar['TOOLBOX'] ) ) {
89  $sidebar['TOOLBOX'] = true;
90  }
91  if ( !isset( $sidebar['LANGUAGES'] ) ) {
92  $sidebar['LANGUAGES'] = true;
93  }
94 
95  if ( !isset( $options['search'] ) || $options['search'] !== true ) {
96  unset( $sidebar['SEARCH'] );
97  }
98  if ( isset( $options['toolbox'] ) && $options['toolbox'] === false ) {
99  unset( $sidebar['TOOLBOX'] );
100  }
101  if ( isset( $options['languages'] ) && $options['languages'] === false ) {
102  unset( $sidebar['LANGUAGES'] );
103  }
104 
105  $boxes = [];
106  foreach ( $sidebar as $boxName => $content ) {
107  if ( $content === false ) {
108  continue;
109  }
110  switch ( $boxName ) {
111  case 'SEARCH':
112  // Search is a special case, skins should custom implement this
113  $boxes[$boxName] = [
114  'id' => 'p-search',
115  'header' => $this->getMsg( 'search' )->text(),
116  'generated' => false,
117  'content' => true,
118  ];
119  break;
120  case 'TOOLBOX':
121  $msgObj = $this->getMsg( 'toolbox' );
122  $boxes[$boxName] = [
123  'id' => 'p-tb',
124  'header' => $msgObj->exists() ? $msgObj->text() : 'toolbox',
125  'generated' => false,
126  'content' => $this->getToolbox(),
127  ];
128  break;
129  case 'LANGUAGES':
130  if ( $this->data['language_urls'] !== false ) {
131  $msgObj = $this->getMsg( 'otherlanguages' );
132  $boxes[$boxName] = [
133  'id' => 'p-lang',
134  'header' => $msgObj->exists() ? $msgObj->text() : 'otherlanguages',
135  'generated' => false,
136  'content' => $this->data['language_urls'] ?: [],
137  ];
138  }
139  break;
140  default:
141  $msgObj = $this->getMsg( $boxName );
142  $boxes[$boxName] = [
143  'id' => "p-$boxName",
144  'header' => $msgObj->exists() ? $msgObj->text() : $boxName,
145  'generated' => true,
146  'content' => $content,
147  ];
148  break;
149  }
150  }
151 
152  // HACK: Compatibility with extensions still using SkinTemplateToolboxEnd
153  $hookContents = null;
154  if ( isset( $boxes['TOOLBOX'] ) ) {
155  ob_start();
156  // We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
157  // can abort and avoid outputting double toolbox links
158  $this->getHookRunner()->onSkinTemplateToolboxEnd( $this, true );
159  $hookContents = ob_get_contents();
160  ob_end_clean();
161  if ( !trim( $hookContents ) ) {
162  $hookContents = null;
163  }
164  }
165  // END hack
166 
167  if ( isset( $options['htmlOnly'] ) && $options['htmlOnly'] === true ) {
168  foreach ( $boxes as $boxName => $box ) {
169  if ( is_array( $box['content'] ) ) {
170  $content = '<ul>';
171  foreach ( $box['content'] as $key => $val ) {
172  $content .= "\n " . $this->getSkin()->makeListItem( $key, $val );
173  }
174  // HACK, shove the toolbox end onto the toolbox if we're rendering itself
175  if ( $hookContents ) {
176  $content .= "\n $hookContents";
177  }
178  // END hack
179  $content .= "\n</ul>\n";
180  $boxes[$boxName]['content'] = $content;
181  }
182  }
183  } elseif ( $hookContents ) {
184  $boxes['TOOLBOXEND'] = [
185  'id' => 'p-toolboxend',
186  'header' => $boxes['TOOLBOX']['header'],
187  'generated' => false,
188  'content' => "<ul>{$hookContents}</ul>",
189  ];
190  // HACK: Make sure that TOOLBOXEND is sorted next to TOOLBOX
191  $boxes2 = [];
192  foreach ( $boxes as $key => $box ) {
193  if ( $key === 'TOOLBOXEND' ) {
194  continue;
195  }
196  $boxes2[$key] = $box;
197  if ( $key === 'TOOLBOX' ) {
198  $boxes2['TOOLBOXEND'] = $boxes['TOOLBOXEND'];
199  }
200  }
201  $boxes = $boxes2;
202  // END hack
203  }
204 
205  return $boxes;
206  }
207 
211  protected function renderAfterPortlet( $name ) {
212  echo $this->getAfterPortlet( $name );
213  }
214 
223  protected function getAfterPortlet( $name ) {
224  $html = '';
225  $content = '';
226  $this->getHookRunner()->onBaseTemplateAfterPortlet( $this, $name, $content );
227 
228  if ( $content !== '' ) {
229  $html = Html::rawElement(
230  'div',
231  [ 'class' => [ 'after-portlet', 'after-portlet-' . $name ] ],
232  $content
233  );
234  }
235 
236  return $html;
237  }
238 
243  protected function makeLink( $key, $item, $options = [] ) {
244  return $this->getSkin()->makeLink( $key, $item, $options );
245  }
246 
251  public function makeListItem( $key, $item, $options = [] ) {
252  return $this->getSkin()->makeListItem( $key, $item, $options );
253  }
254 
258  protected function makeSearchInput( $attrs = [] ) {
259  return $this->getSkin()->makeSearchInput( $attrs );
260  }
261 
265  protected function makeSearchButton( $mode, $attrs = [] ) {
266  return $this->getSkin()->makeSearchButton( $mode, $attrs );
267  }
268 
278  protected function getFooterLinks( $option = null ) {
279  $footerlinks = $this->get( 'footerlinks' );
280 
281  // Reduce footer links down to only those which are being used
282  $validFooterLinks = [];
283  foreach ( $footerlinks as $category => $links ) {
284  $validFooterLinks[$category] = [];
285  foreach ( $links as $link ) {
286  if ( isset( $this->data[$link] ) && $this->data[$link] ) {
287  $validFooterLinks[$category][] = $link;
288  }
289  }
290  if ( count( $validFooterLinks[$category] ) <= 0 ) {
291  unset( $validFooterLinks[$category] );
292  }
293  }
294 
295  if ( $option == 'flat' ) {
296  // fold footerlinks into a single array using a bit of trickery
297  $validFooterLinks = array_merge( ...array_values( $validFooterLinks ) );
298  }
299 
300  return $validFooterLinks;
301  }
302 
317  protected function getFooterIcons( $option = null ) {
318  // Generate additional footer icons
319  $footericons = $this->get( 'footericons' );
320 
321  if ( $option == 'icononly' ) {
322  // Unset any icons which don't have an image
323  foreach ( $footericons as &$footerIconsBlock ) {
324  foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
325  if ( !is_string( $footerIcon ) && !isset( $footerIcon['src'] ) ) {
326  unset( $footerIconsBlock[$footerIconKey] );
327  }
328  }
329  }
330  // Redo removal of any empty blocks
331  foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
332  if ( count( $footerIconsBlock ) <= 0 ) {
333  unset( $footericons[$footerIconsKey] );
334  }
335  }
336  } elseif ( $option == 'nocopyright' ) {
337  unset( $footericons['copyright']['copyright'] );
338  if ( count( $footericons['copyright'] ) <= 0 ) {
339  unset( $footericons['copyright'] );
340  }
341  }
342 
343  return $footericons;
344  }
345 
355  protected function getFooter( $iconStyle = 'icononly', $linkStyle = 'flat' ) {
356  $validFooterIcons = $this->getFooterIcons( $iconStyle );
357  $validFooterLinks = $this->getFooterLinks( $linkStyle );
358 
359  $html = '';
360 
361  if ( count( $validFooterIcons ) + count( $validFooterLinks ) > 0 ) {
362  $html .= Html::openElement( 'div', [
363  'id' => 'footer-bottom',
364  'class' => 'mw-footer',
365  'role' => 'contentinfo',
366  'lang' => $this->get( 'userlang' ),
367  'dir' => $this->get( 'dir' )
368  ] );
369  $footerEnd = Html::closeElement( 'div' );
370  } else {
371  $footerEnd = '';
372  }
373  foreach ( $validFooterIcons as $blockName => $footerIcons ) {
374  $html .= Html::openElement( 'div', [
375  'id' => Sanitizer::escapeIdForAttribute( "f-{$blockName}ico" ),
376  'class' => 'footer-icons'
377  ] );
378  foreach ( $footerIcons as $icon ) {
379  $html .= $this->getSkin()->makeFooterIcon( $icon );
380  }
381  $html .= Html::closeElement( 'div' );
382  }
383  if ( count( $validFooterLinks ) > 0 ) {
384  $html .= Html::openElement( 'ul', [ 'id' => 'f-list', 'class' => 'footer-places' ] );
385  foreach ( $validFooterLinks as $aLink ) {
386  $html .= Html::rawElement(
387  'li',
388  [ 'id' => Sanitizer::escapeIdForAttribute( $aLink ) ],
389  $this->get( $aLink )
390  );
391  }
392  $html .= Html::closeElement( 'ul' );
393  }
394 
395  $html .= $this->getClear() . $footerEnd;
396 
397  return $html;
398  }
399 
406  protected function getClear() {
407  return Html::element( 'div', [ 'class' => 'visualClear' ] );
408  }
409 
425  public function getIndicators() {
426  $out = "<div class=\"mw-indicators mw-body-content\">\n";
427  foreach ( $this->data['indicators'] as $id => $content ) {
428  $out .= Html::rawElement(
429  'div',
430  [
431  'id' => Sanitizer::escapeIdForAttribute( "mw-indicator-$id" ),
432  'class' => 'mw-indicator',
433  ],
434  $content
435  ) . "\n";
436  }
437  $out .= "</div>\n";
438  return $out;
439  }
440 
444  protected function printTrail() {
445  echo $this->getTrail();
446  }
447 
456  public function getTrail() {
457  return WrappedString::join( "\n", [
459  $this->get( 'bottomscripts' ),
460  $this->get( 'reporttime' )
461  ] );
462  }
463 }
BaseTemplate\getPersonalTools
getPersonalTools()
Definition: BaseTemplate.php:73
BaseTemplate\getFooterLinks
getFooterLinks( $option=null)
Returns an array of footerlinks trimmed down to only those footer links that are valid.
Definition: BaseTemplate.php:278
BaseTemplate\msg
msg( $str)
Definition: BaseTemplate.php:42
MWDebug\getDebugHTML
static getDebugHTML(IContextSource $context)
Returns the HTML to add to the page for the toolbar.
Definition: MWDebug.php:504
BaseTemplate\makeSearchButton
makeSearchButton( $mode, $attrs=[])
Definition: BaseTemplate.php:265
Sanitizer\escapeIdForAttribute
static escapeIdForAttribute( $id, $mode=self::ID_PRIMARY)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid HTM...
Definition: Sanitizer.php:1116
BaseTemplate\getClear
getClear()
Get a div with the core visualClear class, for clearing floats.
Definition: BaseTemplate.php:406
getContext
getContext()
QuickTemplate\getSkin
getSkin()
Get the Skin object related to this object.
Definition: QuickTemplate.php:138
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:315
BaseTemplate\getAfterPortlet
getAfterPortlet( $name)
Allows extensions to hook into known portlets and add stuff to them.
Definition: BaseTemplate.php:223
BaseTemplate\printTrail
printTrail()
Output getTrail.
Definition: BaseTemplate.php:444
BaseTemplate\makeListItem
makeListItem( $key, $item, $options=[])
Definition: BaseTemplate.php:251
BaseTemplate\getIndicators
getIndicators()
Get the suggested HTML for page status indicators: icons (or short text snippets) usually displayed i...
Definition: BaseTemplate.php:425
BaseTemplate\getFooter
getFooter( $iconStyle='icononly', $linkStyle='flat')
Renderer for getFooterIcons and getFooterLinks.
Definition: BaseTemplate.php:355
$content
$content
Definition: router.php:76
BaseTemplate\renderAfterPortlet
renderAfterPortlet( $name)
Definition: BaseTemplate.php:211
BaseTemplate\makeSearchInput
makeSearchInput( $attrs=[])
Definition: BaseTemplate.php:258
QuickTemplate
Generic wrapper for template functions, with interface compatible with what we use of PHPTAL 0....
Definition: QuickTemplate.php:29
BaseTemplate\getToolbox
getToolbox()
Create an array of common toolbox items from the data in the quicktemplate stored by SkinTemplate and...
Definition: BaseTemplate.php:54
BaseTemplate\getTrail
getTrail()
Get the basic end-page trail including bottomscripts, reporttime, and debug stuff.
Definition: BaseTemplate.php:456
BaseTemplate\getMsg
getMsg( $name,... $params)
Get a Message object with its context set.
Definition: BaseTemplate.php:38
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:251
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
BaseTemplate\makeLink
makeLink( $key, $item, $options=[])
Definition: BaseTemplate.php:243
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
BaseTemplate\getFooterIcons
getFooterIcons( $option=null)
Returns an array of footer icons filtered down by options relevant to how the skin wishes to display ...
Definition: BaseTemplate.php:317
BaseTemplate
New base template for a skin's template extended from QuickTemplate this class features helper method...
Definition: BaseTemplate.php:29
BaseTemplate\getSidebar
getSidebar( $options=[])
Definition: BaseTemplate.php:82