MediaWiki REL1_34
MonoBookTemplate.php
Go to the documentation of this file.
1<?php
31
38 public function execute() {
39 // Open html, body elements, etc
40 $html = $this->get( 'headelement' );
41 $html .= Html::openElement( 'div', [ 'id' => 'globalWrapper' ] );
42
43 $html .= Html::openElement( 'div', [ 'id' => 'column-content' ] );
44 $html .= Html::rawElement( 'div', [ 'id' => 'content', 'class' => 'mw-body', 'role' => 'main' ],
45 Html::element( 'a', [ 'id' => 'top' ] ) .
46 $this->getIfExists( 'sitenotice', [
47 'wrapper' => 'div',
48 'parameters' => [ 'id' => 'siteNotice', 'class' => 'mw-body-content' ]
49 ] ) .
50 $this->getIndicators() .
51 $this->getIfExists( 'title', [
52 'loose' => true,
53 'wrapper' => 'h1',
54 'parameters' => [
55 'id' => 'firstHeading',
56 'class' => 'firstHeading',
57 'lang' => $this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode()
58 ]
59 ] ) .
60 Html::rawElement( 'div', [ 'id' => 'bodyContent', 'class' => 'mw-body-content' ],
61 Html::rawElement( 'div', [ 'id' => 'siteSub' ], $this->getMsg( 'tagline' )->parse() ) .
62 Html::rawElement(
63 'div',
64 [ 'id' => 'contentSub', 'lang' => $this->get( 'userlang' ), 'dir' => $this->get( 'dir' ) ],
65 $this->get( 'subtitle' )
66 ) .
67 $this->getIfExists( 'undelete', [ 'wrapper' => 'div', 'parameters' => [
68 'id' => 'contentSub2'
69 ] ] ) .
70 $this->getIfExists( 'newtalk', [ 'wrapper' => 'div', 'parameters' => [
71 'class' => 'usermessage'
72 ] ] ) .
73 Html::element( 'div', [ 'id' => 'jump-to-nav' ] ) .
74 Html::element( 'a', [ 'href' => '#column-one', 'class' => 'mw-jump-link' ],
75 $this->getMsg( 'monobook-jumptonavigation' )->text()
76 ) .
77 Html::element( 'a', [ 'href' => '#searchInput', 'class' => 'mw-jump-link' ],
78 $this->getMsg( 'monobook-jumptosearch' )->text()
79 ) .
80 '<!-- start content -->' .
81
82 $this->get( 'bodytext' ) .
83 $this->getIfExists( 'catlinks' ) .
84
85 '<!-- end content -->' .
86 $this->getClear()
87 )
88 );
89 $html .= $this->deprecatedHookHack( 'MonoBookAfterContent' );
90 $html .= $this->getIfExists( 'dataAfterContent' ) . $this->getClear();
91 $html .= Html::closeElement( 'div' );
92
93 $html .= Html::rawElement( 'div',
94 [
95 'id' => 'column-one',
96 'lang' => $this->get( 'userlang' ),
97 'dir' => $this->get( 'dir' )
98 ],
99 Html::element( 'h2', [], $this->getMsg( 'navigation-heading' )->text() ) .
100 $this->getCactions() .
101 $this->getBox( 'personal', $this->getPersonalTools(), 'personaltools' ) .
102 Html::rawElement( 'div', [ 'class' => 'portlet', 'id' => 'p-logo', 'role' => 'banner' ],
103 Html::element( 'a',
104 [
105 'href' => $this->data['nav_urls']['mainpage']['href'],
106 'class' => 'mw-wiki-logo',
107 ]
109 )
110 ) .
111 Html::rawElement( 'div', [ 'id' => 'sidebar' ], $this->getRenderedSidebar() ) .
113 'sidebar',
114 $this->getMsg( 'jumptonavigation' )->text()
115 ) .
117 'p-personal',
118 $this->getMsg( 'monobook-jumptopersonal' )->text()
119 ) .
121 'globalWrapper',
122 $this->getMsg( 'monobook-jumptotop' )->text()
123 )
124 );
125 $html .= '<!-- end of the left (by default at least) column -->';
126
127 $html .= $this->getClear();
128 $html .= $this->getSimpleFooter();
129 $html .= Html::closeElement( 'div' );
130
131 $html .= $this->getTrail();
132
133 $html .= Html::closeElement( 'body' );
134 $html .= Html::closeElement( 'html' );
135
136 // The unholy echo
137 echo $html;
138 }
139
150 protected function getMobileNavigationIcon( $target, $title ) {
151 return Html::element( 'a', [
152 'href' => "#$target",
153 'title' => $title,
154 'class' => 'menu-toggle',
155 'id' => "$target-toggle"
156 ] );
157 }
158
164 protected function getCactions() {
165 $html = '';
166 $allTabs = $this->data['content_actions'];
167 $tabCount = count( $allTabs );
168
169 // Normal cactions
170 if ( $tabCount > 2 ) {
171 $html .= $this->getBox( 'cactions', $allTabs, 'monobook-cactions-label' );
172 } else {
173 // Is redundant with spoof, hide normal cactions entirely in mobile
174 $html .= $this->getBox( 'cactions', $allTabs, 'monobook-cactions-label',
175 [ 'extra-classes' => 'nomobile' ]
176 );
177 }
178
179 // Mobile cactions tabs
180 $tabs = $this->data['content_navigation']['namespaces'];
181 foreach ( $tabs as $tab => $attribs ) {
182 $tabs[$tab]['id'] = $attribs['id'] . '-mobile';
183 $tabs[$tab]['title'] = $attribs['text'];
184 }
185
186 if ( $tabCount !== 1 ) {
187 // Is not special page or stuff, append a 'more'
188 $tabs['more'] = [
189 'text' => $this->getMsg( 'monobook-more-actions' )->text(),
190 'href' => '#p-cactions',
191 'id' => 'ca-more'
192 ];
193 }
194 $tabs['toolbox'] = [
195 'text' => $this->getMsg( 'toolbox' )->text(),
196 'href' => '#p-tb',
197 'id' => 'ca-tools',
198 'title' => $this->getMsg( 'toolbox' )->text()
199 ];
200 if ( $this->data['language_urls'] !== false ) {
201 $tabs['languages'] = [
202 'text' => $this->getMsg( 'otherlanguages' )->text(),
203 'href' => '#p-lang',
204 'id' => 'ca-languages',
205 'title' => $this->getMsg( 'otherlanguages' )->text()
206 ];
207 }
208
209 $html .= $this->getBox( 'cactions-mobile', $tabs, 'monobook-cactions-label' );
210
211 return $html;
212 }
213
219 protected function getRenderedSidebar() {
220 $sidebar = $this->data['sidebar'];
221 $html = '';
222
223 if ( !isset( $sidebar['SEARCH'] ) ) {
224 $sidebar['SEARCH'] = true;
225 }
226 if ( !isset( $sidebar['TOOLBOX'] ) ) {
227 $sidebar['TOOLBOX'] = true;
228 }
229 if ( !isset( $sidebar['LANGUAGES'] ) ) {
230 $sidebar['LANGUAGES'] = true;
231 }
232
233 foreach ( $sidebar as $boxName => $content ) {
234 if ( $content === false ) {
235 continue;
236 }
237
238 // Numeric strings gets an integer when set as key, cast back - T73639
239 $boxName = (string)$boxName;
240
241 if ( $boxName == 'SEARCH' ) {
242 $html .= $this->getSearchBox();
243 } elseif ( $boxName == 'TOOLBOX' ) {
244 $html .= $this->getToolboxBox();
245 } elseif ( $boxName == 'LANGUAGES' ) {
246 $html .= $this->getLanguageBox();
247 } else {
248 $html .= $this->getBox(
249 $boxName,
250 $content,
251 null,
252 [ 'extra-classes' => 'generated-sidebar' ]
253 );
254 }
255 }
256
257 return $html;
258 }
259
265 protected function getSearchBox() {
266 $html = '';
267
268 if ( $this->config->get( 'UseTwoButtonsSearchForm' ) ) {
269 $optionButtons = "\u{00A0} " . $this->makeSearchButton(
270 'fulltext',
271 [ 'id' => 'mw-searchButton', 'class' => 'searchButton' ]
272 );
273 } else {
274 $optionButtons = Html::rawElement( 'div', [],
275 Html::rawElement( 'a', [ 'href' => $this->get( 'searchaction' ), 'rel' => 'search' ],
276 $this->getMsg( 'powersearch-legend' )->escaped()
277 )
278 );
279 }
280 $searchInputId = 'searchInput';
281 $searchForm = Html::rawElement( 'form', [
282 'action' => $this->get( 'wgScript' ),
283 'id' => 'searchform'
284 ],
285 Html::hidden( 'title', $this->get( 'searchtitle' ) ) .
286 $this->makeSearchInput( [ 'id' => $searchInputId ] ) .
287 $this->makeSearchButton( 'go', [ 'id' => 'searchGoButton', 'class' => 'searchButton' ] ) .
288 $optionButtons
289 );
290
291 $html .= $this->getBox( 'search', $searchForm, null, [
292 'search-input-id' => $searchInputId,
293 'role' => 'search',
294 'body-id' => 'searchBody'
295 ] );
296
297 return $html;
298 }
299
305 protected function getToolboxBox() {
306 $html = '';
307 $template = $this;
308
309 $html .= $this->getBox( 'tb', $this->getToolbox(), 'toolbox', [ 'hooks' => [
310 // Deprecated hooks
311 'MonoBookTemplateToolboxEnd' => [ &$template ],
312 'SkinTemplateToolboxEnd' => [ &$template, true ]
313 ] ] );
314
315 $html .= $this->deprecatedHookHack( 'MonoBookAfterToolbox', [ $template ] );
316
317 return $html;
318 }
319
325 protected function getLanguageBox() {
326 $html = '';
327
328 if ( $this->data['language_urls'] !== false ) {
329 $html .= $this->getBox( 'lang', $this->data['language_urls'], 'otherlanguages' );
330 }
331
332 return $html;
333 }
334
346 protected function getBox( $name, $contents, $msg = null, $setOptions = [] ) {
347 $options = array_merge( [
348 'class' => 'portlet',
349 'body-class' => 'pBody',
350 'text-wrapper' => ''
351 ], $setOptions );
352
353 // Do some special stuff for the personal menu
354 if ( $name == 'personal' ) {
355 $prependiture = '';
356
357 // Extension:UniversalLanguageSelector order - T121793
358 if ( array_key_exists( 'uls', $contents ) ) {
359 $prependiture .= $this->makeListItem( 'uls', $contents['uls'] );
360 unset( $contents['uls'] );
361 }
362 if ( !$this->getSkin()->getUser()->isLoggedIn() &&
363 User::groupHasPermission( '*', 'edit' )
364 ) {
365 $prependiture .= Html::rawElement(
366 'li',
367 [ 'id' => 'pt-anonuserpage' ],
368 $this->getMsg( 'notloggedin' )->escaped()
369 );
370 }
371 $options['list-prepend'] = $prependiture;
372 }
373
374 return $this->getPortlet( $name, $contents, $msg, $options );
375 }
376
387 protected function getPortlet( $name, $content, $msg = null, $setOptions = [] ) {
388 // random stuff to override with any provided options
389 $options = array_merge( [
390 // handle role=search a little differently
391 'role' => 'navigation',
392 'search-input-id' => 'searchInput',
393 // extra classes/ids
394 'id' => 'p-' . $name,
395 'class' => 'mw-portlet',
396 'extra-classes' => '',
397 'body-id' => null,
398 'body-class' => 'mw-portlet-body',
399 'body-extra-classes' => '',
400 // wrapper for individual list items
401 'text-wrapper' => [ 'tag' => 'span' ],
402 // old toolbox hook support (use: [ 'SkinTemplateToolboxEnd' => [ &$skin, true ] ])
403 'hooks' => '',
404 // option to stick arbitrary stuff at the beginning of the ul
405 'list-prepend' => ''
406 ], $setOptions );
407
408 // Handle the different $msg possibilities
409 if ( $msg === null ) {
410 $msg = $name;
411 $msgParams = [];
412 } elseif ( is_array( $msg ) ) {
413 $msgString = array_shift( $msg );
414 $msgParams = $msg;
415 $msg = $msgString;
416 } else {
417 $msgParams = [];
418 }
419 $msgObj = $this->getMsg( $msg, $msgParams );
420 if ( $msgObj->exists() ) {
421 $msgString = $msgObj->parse();
422 } else {
423 $msgString = htmlspecialchars( $msg );
424 }
425
426 $labelId = Sanitizer::escapeIdForAttribute( "p-$name-label" );
427
428 if ( is_array( $content ) ) {
429 $contentText = Html::openElement( 'ul',
430 [ 'lang' => $this->get( 'userlang' ), 'dir' => $this->get( 'dir' ) ]
431 );
432 $contentText .= $options['list-prepend'];
433 foreach ( $content as $key => $item ) {
434 if ( is_array( $options['text-wrapper'] ) ) {
435 $contentText .= $this->makeListItem(
436 $key,
437 $item,
438 [ 'text-wrapper' => $options['text-wrapper'] ]
439 );
440 } else {
441 $contentText .= $this->makeListItem(
442 $key,
443 $item
444 );
445 }
446 }
447 // Compatibility with extensions still using SkinTemplateToolboxEnd or similar
448 if ( is_array( $options['hooks'] ) ) {
449 foreach ( $options['hooks'] as $hook => $hookOptions ) {
450 $contentText .= $this->deprecatedHookHack( $hook, $hookOptions );
451 }
452 }
453
454 $contentText .= Html::closeElement( 'ul' );
455 } else {
456 $contentText = $content;
457 }
458
459 // Special handling for role=search
460 $divOptions = [
461 'role' => $options['role'],
462 'class' => $this->mergeClasses( $options['class'], $options['extra-classes'] ),
463 'id' => Sanitizer::escapeIdForAttribute( $options['id'] ),
464 'title' => Linker::titleAttrib( $options['id'] )
465 ];
466 if ( $options['role'] !== 'search' ) {
467 $divOptions['aria-labelledby'] = $labelId;
468 }
469 $labelOptions = [
470 'id' => $labelId,
471 'lang' => $this->get( 'userlang' ),
472 'dir' => $this->get( 'dir' )
473 ];
474 if ( $options['role'] == 'search' ) {
475 $msgString = Html::rawElement( 'label', [ 'for' => $options['search-input-id'] ], $msgString );
476 }
477
478 $bodyDivOptions = [
479 'class' => $this->mergeClasses( $options['body-class'], $options['body-extra-classes'] )
480 ];
481 if ( is_string( $options['body-id'] ) ) {
482 $bodyDivOptions['id'] = $options['body-id'];
483 }
484
485 $html = Html::rawElement( 'div', $divOptions,
486 Html::rawElement( 'h3', $labelOptions, $msgString ) .
487 Html::rawElement( 'div', $bodyDivOptions,
488 $contentText .
489 $this->getAfterPortlet( $name )
490 )
491 );
492
493 return $html;
494 }
495
507 protected function mergeClasses( $class, $extraClasses ) {
508 if ( !is_array( $class ) ) {
509 $class = [ $class ];
510 }
511 if ( !is_array( $extraClasses ) ) {
512 $extraClasses = [ $extraClasses ];
513 }
514
515 return array_merge( $class, $extraClasses );
516 }
517
527 protected function deprecatedHookHack( $hook, $hookOptions = [] ) {
528 $hookContents = '';
529 ob_start();
530 Hooks::run( $hook, $hookOptions );
531 $hookContents = ob_get_contents();
532 ob_end_clean();
533 if ( !trim( $hookContents ) ) {
534 $hookContents = '';
535 }
536
537 return $hookContents;
538 }
539
548 protected function getIfExists( $object, $setOptions = [] ) {
549 $options = [
550 'loose' => false,
551 'wrapper' => 'none',
552 'parameters' => []
553 ];
554 foreach ( $setOptions as $key => $value ) {
555 $options[$key] = $value;
556 }
557
558 $html = '';
559
560 if ( ( $options['loose'] && $this->data[$object] != '' ) ||
561 ( !$options['loose'] && $this->data[$object] ) ) {
562 if ( $options['wrapper'] == 'none' ) {
563 $html .= $this->get( $object );
564 } else {
565 $html .= Html::rawElement(
566 $options['wrapper'],
567 $options['parameters'],
568 $this->get( $object )
569 );
570 }
571 }
572
573 return $html;
574 }
575
581 protected function getSimpleFooter() {
582 $validFooterIcons = $this->getFooterIcons( 'icononly' );
583 $validFooterLinks = $this->getFooterLinks( 'flat' );
584
585 $html = '';
586
587 $html .= Html::openElement( 'div', [
588 'id' => 'footer',
589 'role' => 'contentinfo',
590 'lang' => $this->get( 'userlang' ),
591 'dir' => $this->get( 'dir' )
592 ] );
593
594 foreach ( $validFooterIcons as $blockName => $footerIcons ) {
595 $html .= Html::openElement( 'div', [
596 'id' => Sanitizer::escapeIdForAttribute( "f-{$blockName}ico" ),
597 'class' => 'footer-icons'
598 ] );
599 foreach ( $footerIcons as $icon ) {
600 $html .= $this->getSkin()->makeFooterIcon( $icon );
601 }
602 $html .= Html::closeElement( 'div' );
603 }
604 if ( count( $validFooterLinks ) > 0 ) {
605 $html .= Html::openElement( 'ul', [ 'id' => 'f-list' ] );
606 foreach ( $validFooterLinks as $aLink ) {
607 $html .= Html::rawElement(
608 'li',
609 [ 'id' => Sanitizer::escapeIdForAttribute( $aLink ) ],
610 $this->get( $aLink )
611 );
612 }
613 $html .= Html::closeElement( 'ul' );
614 }
615 $html .= Html::closeElement( 'div' );
616
617 return $html;
618 }
619}
getUser()
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=[])
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.
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=[])
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...
Definition Linker.php:2026
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2195
execute()
Template filter callback for MonoBook skin.
getBox( $name, $contents, $msg=null, $setOptions=[])
Generate a sidebar box using getPortlet(); prefill some common stuff.
getSimpleFooter()
Renderer for getFooterIcons and getFooterLinks as a generic footer block.
getMobileNavigationIcon( $target, $title)
Create a wrapped link to create a mobile toggle/jump icon Needs to be an on-page link (as opposed to ...
getSearchBox()
Generate the search, using config options for buttons (?)
getPortlet( $name, $content, $msg=null, $setOptions=[])
Generates a block of navigation links with a header.
getRenderedSidebar()
Generate the full sidebar.
getLanguageBox()
Generate the languages box.
getIfExists( $object, $setOptions=[])
Simple wrapper for random if-statement-wrapped $this->data things.
mergeClasses( $class, $extraClasses)
Helper function for getPortlet.
getCactions()
Generate the cactions (content actions) tabs, as well as a second set of spoof tabs for mobile.
getToolboxBox()
Generate the toolbox, complete with all three old hooks.
deprecatedHookHack( $hook, $hookOptions=[])
Wrapper to catch output of old hooks expecting to write directly to page We no longer do things that ...
getSkin()
Get the Skin object related to this object.
$content
Definition router.php:78