28 if ( isset( $this->sidebar[
'wikibase-otherprojects'] ) ) {
29 $this->otherProjects = $this->sidebar[
'wikibase-otherprojects'];
30 unset( $this->sidebar[
'wikibase-otherprojects'] );
33 if ( isset( $this->sidebar[
'coll-print_export'] ) ) {
34 $this->collectionPortlet = $this->sidebar[
'coll-print_export'];
35 unset( $this->sidebar[
'coll-print_export'] );
42 $html = $this->
get(
'headelement' );
44 $html .= Html::openElement(
'div', [
'id' =>
'mw-wrapper',
'class' => $userLinks[
'class'] ] );
46 $html .= Html::rawElement(
'div', [
'id' =>
'mw-header-container',
'class' =>
'ts-container' ],
47 Html::rawElement(
'div', [
'id' =>
'mw-header',
'class' =>
'ts-inner' ],
49 $this->
getLogo(
'p-logo-text',
'text' ) .
57 $html .= Html::element(
'div', [
'id' =>
'menus-cover' ] );
59 $html .= Html::rawElement(
'div', [
'id' =>
'mw-content-container',
'class' =>
'ts-container' ],
60 Html::rawElement(
'div', [
'id' =>
'mw-content-block',
'class' =>
'ts-inner' ],
61 Html::rawElement(
'div', [
'id' =>
'mw-content-wrapper' ],
65 Html::rawElement(
'div', [
'id' =>
'mw-site-navigation' ],
66 $this->
getLogo(
'p-logo',
'image' ) .
73 $this->pileOfTools[
'general'],
78 Html::rawElement(
'div', [
'id' =>
'mw-related-navigation' ],
87 $html .= Html::rawElement(
'div', [
'id' =>
'mw-footer-container',
'class' =>
'ts-container' ],
88 Html::rawElement(
'div', [
'id' =>
'mw-footer',
'class' =>
'ts-inner' ],
93 $html .= Html::closeElement(
'div' );
98 $html .= $this->
get(
'bottomscripts' );
99 $html .= $this->
get(
'reporttime' );
101 $html .= Html::closeElement(
'body' );
102 $html .= Html::closeElement(
'html' );
115 $html = Html::rawElement(
117 [
'id' =>
'content',
'class' =>
'mw-body',
'role' =>
'main' ],
123 'id' =>
'firstHeading',
124 'class' =>
'firstHeading',
125 'lang' => $this->
get(
'pageLanguage' )
127 $this->
get(
'title' )
129 Html::rawElement(
'div', [
'id' =>
'bodyContentOuter' ],
130 Html::rawElement(
'div', [
'id' =>
'siteSub' ], $this->
getMsg(
'tagline' )->parse() ) .
131 Html::rawElement(
'div', [
'id' =>
'mw-page-header-links' ],
134 $this->pileOfTools[
'namespaces'],
135 'timeless-namespaces',
136 [
'extra-classes' =>
'tools-inline' ]
140 $this->pileOfTools[
'more'],
142 [
'extra-classes' =>
'tools-inline' ]
147 $this->pileOfTools[
'page-primary'],
148 'timeless-pagetools',
149 [
'extra-classes' =>
'tools-inline' ]
153 Html::rawElement(
'div', [
'class' =>
'mw-body-content',
'id' =>
'bodyContent' ],
155 $this->
get(
'bodytext' ) .
161 return Html::rawElement(
'div', [
'id' =>
'mw-content' ], $html );
193 $options = array_merge( [
194 'role' =>
'navigation',
196 'id' =>
'p-' . $name,
197 'class' => [
'mw-portlet',
'emptyPortlet' => !
$content ],
198 'extra-classes' =>
'',
200 'body-class' =>
'mw-portlet-body',
201 'body-extra-classes' =>
'',
203 'text-wrapper' => [
'tag' =>
'span' ],
209 if ( $msg ===
null ) {
212 } elseif ( is_array( $msg ) ) {
213 $msgString = array_shift( $msg );
219 $msgObj = $this->
getMsg( $msg, $msgParams );
220 if ( $msgObj->exists() ) {
221 $msgString = $msgObj->parse();
223 $msgString = htmlspecialchars( $msg );
226 $labelId = Sanitizer::escapeIdForAttribute(
"p-$name-label" );
229 $contentText = Html::openElement(
'ul',
230 [
'lang' => $this->
get(
'userlang' ),
'dir' => $this->
get(
'dir' ) ]
232 $contentText .= $options[
'list-prepend'];
233 foreach (
$content as $key => $item ) {
234 if ( is_array( $options[
'text-wrapper'] ) ) {
238 [
'text-wrapper' => $options[
'text-wrapper'] ]
247 $contentText .= Html::closeElement(
'ul' );
253 'role' => $options[
'role'],
254 'class' => $this->
mergeClasses( $options[
'class'], $options[
'extra-classes'] ),
255 'id' => Sanitizer::escapeIdForAttribute( $options[
'id'] ),
257 'aria-labelledby' => $labelId
261 'lang' => $this->
get(
'userlang' ),
262 'dir' => $this->
get(
'dir' )
266 'class' => $this->
mergeClasses( $options[
'body-class'], $options[
'body-extra-classes'] )
268 if ( is_string( $options[
'body-id'] ) ) {
269 $bodyDivOptions[
'id'] = $options[
'body-id'];
272 $html = Html::rawElement(
'div', $divOptions,
273 Html::rawElement(
'h3', $labelOptions, $msgString ) .
274 Html::rawElement(
'div', $bodyDivOptions,
295 if ( !is_array( $class ) ) {
298 if ( !is_array( $extraClasses ) ) {
299 $extraClasses = [ $extraClasses ];
302 return array_merge( $class, $extraClasses );
318 $html .= Html::rawElement(
321 'id' => Sanitizer::escapeId( $id ),
322 'class' => array_merge( [
'sidebar-chunk' ], $classes )
324 Html::rawElement(
'h2', [],
325 Html::element(
'span', [],
329 Html::rawElement(
'div', [
'class' =>
'sidebar-inner' ],
$content )
343 protected function getLogo( $id =
'p-logo', $part =
'both' ) {
345 $language = $this->
getSkin()->getLanguage();
348 $html .= Html::openElement(
351 'id' => Sanitizer::escapeId( $id ),
352 'class' =>
'mw-portlet',
356 if ( $part !==
'image' ) {
360 if ( !$wordmarkImage ) {
361 if ( $language->hasVariants() ) {
362 $siteTitle = $language->convert( $this->
getMsg(
'timeless-sitetitle' )->escaped() );
364 $siteTitle = $this->
getMsg(
'timeless-sitetitle' )->escaped();
367 if ( mb_strlen( $siteTitle ) > 13 ) {
368 $titleClass =
'long';
371 $titleClass =
'wordmark';
373 $html .= Html::rawElement(
'a', [
375 'class' => [
'mw-wiki-title', $titleClass ],
376 'href' => $this->data[
'nav_urls'][
'mainpage'][
'href']
378 $wordmarkImage ?: $siteTitle
382 if ( $part !==
'text' ) {
385 $html .= Html::rawElement(
389 'class' => [
'mw-wiki-logo', !$logoImage ?
'fallback' :
'timeless-logo' ],
390 'href' => $this->data[
'nav_urls'][
'mainpage'][
'href']
397 $html .= Html::closeElement(
'div' );
410 $html .= Html::openElement(
'div', [
'class' =>
'mw-portlet',
'id' =>
'p-search' ] );
412 $html .= Html::rawElement(
414 [
'lang' => $this->
get(
'userlang' ),
'dir' => $this->
get(
'dir' ) ],
415 Html::rawElement(
'label', [
'for' =>
'searchInput' ], $this->
getMsg(
'search' )->escaped() )
418 $html .= Html::rawElement(
'form', [
'action' => $this->
get(
'wgScript' ),
'id' =>
'searchform' ],
419 Html::rawElement(
'div', [
'id' =>
'simpleSearch' ],
420 Html::rawElement(
'div', [
'id' =>
'searchInput-container' ],
422 'id' =>
'searchInput'
425 Html::hidden(
'title', $this->
get(
'searchtitle' ) ) .
428 [
'id' =>
'mw-searchButton',
'class' =>
'searchButton mw-fallbackSearchButton' ]
432 [
'id' =>
'searchButton',
'class' =>
'searchButton' ]
437 $html .= Html::closeElement(
'div' );
451 $this->sidebar[
'SEARCH'] =
false;
453 $this->sidebar[
'TOOLBOX'] =
false;
455 $this->sidebar[
'LANGUAGES'] =
false;
457 foreach ( $this->sidebar as $name =>
$content ) {
462 $name = (string)$name;
466 $html = $this->
getSidebarChunk(
'site-navigation',
'navigation', $html );
481 $html .= Html::rawElement(
'div', [
'id' =>
'mw-header-hack',
'class' =>
'color-bar' ],
482 Html::rawElement(
'div', [
'class' =>
'color-middle-container' ],
483 Html::element(
'div', [
'class' =>
'color-middle' ] )
485 Html::element(
'div', [
'class' =>
'color-left' ] ) .
486 Html::element(
'div', [
'class' =>
'color-right' ] )
488 $html .= Html::rawElement(
'div', [
'id' =>
'mw-header-nav-hack' ],
489 Html::rawElement(
'div', [
'class' =>
'color-bar' ],
490 Html::rawElement(
'div', [
'class' =>
'color-middle-container' ],
491 Html::element(
'div', [
'class' =>
'color-middle' ] )
493 Html::element(
'div', [
'class' =>
'color-left' ] ) .
494 Html::element(
'div', [
'class' =>
'color-right' ] )
510 $this->pileOfTools[
'page-secondary'],
511 'timeless-pageactions'
515 $this->pileOfTools[
'user'],
516 'timeless-userpagetools'
520 $this->pileOfTools[
'page-tertiary'],
523 if ( isset( $this->collectionPortlet ) ) {
526 $this->collectionPortlet[
'content']
530 return $this->
getSidebarChunk(
'page-tools',
'timeless-pageactions', $pageTools );
540 $user = $this->
getSkin()->getUser();
543 $userName = $personalTools[
'userpage'][
'links'][0][
'text'] ?? $user->getName();
549 if ( isset( $personalTools[
'notifications-alert'] ) ) {
550 $extraTools[
'notifications-alert'] = $personalTools[
'notifications-alert'];
551 unset( $personalTools[
'notifications-alert'] );
553 if ( isset( $personalTools[
'notifications-notice'] ) ) {
554 $extraTools[
'notifications-notice'] = $personalTools[
'notifications-notice'];
555 unset( $personalTools[
'notifications-notice'] );
557 $class = empty( $extraTools ) ?
'' :
'extension-icons';
560 if ( isset( $personalTools[
'userpage'] ) ) {
561 $personalTools[
'userpage'][
'links'][0][
'text'] = $this->
getMsg(
'timeless-userpage' )->text();
563 if ( isset( $personalTools[
'mytalk'] ) ) {
564 $personalTools[
'mytalk'][
'links'][0][
'text'] = $this->
getMsg(
'timeless-talkpage' )->text();
568 if ( $user->isLoggedIn() ) {
569 $dropdownHeader = $userName;
570 $headerMsg = [
'timeless-loggedinas', $userName ];
572 $dropdownHeader = $this->
getMsg(
'timeless-anonymous' )->text();
573 $headerMsg =
'timeless-notloggedin';
575 $html .= Html::openElement(
'div', [
'id' =>
'user-tools' ] );
577 $html .= Html::rawElement(
'div', [
'id' =>
'personal' ],
578 Html::rawElement(
'h2', [],
579 Html::element(
'span', [], $dropdownHeader )
581 Html::rawElement(
'div', [
'id' =>
'personal-inner',
'class' =>
'dropdown' ],
582 $this->
getPortlet(
'personal', $personalTools, $headerMsg )
587 if ( !empty( $extraTools ) ) {
589 foreach ( $extraTools as $key => $item ) {
593 $html .= Html::rawElement(
595 [
'id' =>
'personal-extra',
'class' =>
'p-body' ],
596 Html::rawElement(
'ul', [], $iconList )
600 $html .= Html::closeElement(
'div' );
616 if ( $this->data[
'sitenotice'] ) {
617 $html .= Html::rawElement(
'div', [
'id' =>
'siteNotice' ], $this->
get(
'sitenotice' ) );
619 if ( $this->data[
'newtalk'] ) {
620 $html .= Html::rawElement(
'div', [
'class' =>
'usermessage' ], $this->
get(
'newtalk' ) );
634 $html .= Html::openElement(
'div', [
'id' =>
'contentSub' ] );
635 if ( $this->data[
'subtitle'] ) {
636 $html .= $this->
get(
'subtitle' );
638 if ( $this->data[
'undelete'] ) {
639 $html .= $this->
get(
'undelete' );
641 $html .= Html::closeElement(
'div' );
655 if ( $this->data[
'catlinks'] || $this->data[
'dataAfterContent'] ) {
656 $html .= Html::openElement(
'div', [
'id' =>
'content-bottom-stuff' ] );
657 if ( $this->data[
'catlinks'] ) {
658 $html .= $this->
get(
'catlinks' );
660 if ( $this->data[
'dataAfterContent'] ) {
661 $html .= $this->
get(
'dataAfterContent' );
663 $html .= Html::closeElement(
'div' );
680 $namespace =
$title->getNamespace();
682 $sortedPileOfTools = [
684 'page-primary' => [],
685 'page-secondary' => [],
687 'page-tertiary' => [],
693 $pileOfEditTools = [];
694 foreach ( $this->data[
'content_navigation'] as $navKey => $navBlock ) {
696 if ( $navKey ==
'namespaces' ) {
697 if ( $namespace < 0 && count( $navBlock ) < 2 ) {
699 $sortedPileOfTools[
'page-tertiary'] = $navBlock;
701 $sortedPileOfTools[
'namespaces'] = $navBlock;
703 } elseif ( $navKey ==
'variants' ) {
705 $sortedPileOfTools[
'variants'] = $navBlock;
707 $pileOfEditTools = array_merge( $pileOfEditTools, $navBlock );
713 if ( $namespace >= 0 ) {
715 'text' => $this->
getMsg(
'timeless-pagelog' )->text(),
716 'href' => SpecialPage::getTitleFor(
'Log' )->getLocalURL(
717 [
'page' =>
$title->getPrefixedText() ]
725 'text' => $this->
getMsg(
'timeless-more' )->text(),
727 'class' =>
'dropdown-toggle'
729 if ( $this->data[
'language_urls'] !==
false || $sortedPileOfTools[
'variants']
730 || isset( $this->otherProjects ) ) {
732 'text' => $this->
getMsg(
'timeless-languages' )->escaped(),
733 'id' =>
'ca-languages',
734 'class' =>
'dropdown-toggle'
740 foreach ( $pileOfEditTools as $navKey => $navBlock ) {
743 if ( in_array( $navKey, [
747 $currentSet =
'namespaces';
748 } elseif ( in_array( $navKey, [
755 $currentSet =
'page-primary';
756 } elseif ( in_array( $navKey, [
763 $currentSet =
'page-secondary';
766 $currentSet =
'page-primary';
768 $sortedPileOfTools[$currentSet][$navKey] = $navBlock;
773 if ( $navKey ===
'contributions' ) {
774 $currentSet =
'page-primary';
775 } elseif ( in_array( $navKey, [
782 $currentSet =
'user';
783 } elseif ( in_array( $navKey, [
788 'recentchangeslinked',
793 $currentSet =
'page-tertiary';
794 } elseif ( in_array( $navKey, [
798 $currentSet =
'more';
800 $currentSet =
'general';
802 $sortedPileOfTools[$currentSet][$navKey] = $navBlock;
807 'proofreadPagePrevLink',
809 'proofreadPageScanLink',
810 'proofreadPageIndexLink',
811 'proofreadPageNextLink',
813 foreach ( $tabs as $tab ) {
814 if ( isset( $sortedPileOfTools[
'namespaces'][$tab] ) ) {
815 $toMove = $sortedPileOfTools[
'namespaces'][$tab];
816 unset( $sortedPileOfTools[
'namespaces'][$tab] );
819 $toMove[
'title'] = $toMove[
'text'];
821 if ( $tab ===
'proofreadPagePrevLink' ) {
823 $sortedPileOfTools[
'namespaces'] = array_merge(
825 $sortedPileOfTools[
'namespaces']
829 $sortedPileOfTools[
'namespaces'][$tab] = $toMove;
834 return $sortedPileOfTools;
850 $allCats = $skin->getOutput()->getCategoryLinks();
851 if ( !empty( $allCats ) ) {
852 if ( !empty( $allCats[
'normal'] ) ) {
853 $catHeader =
'categories';
857 'mw-normal-catlinks',
861 $catHeader =
'hidden-categories';
864 if ( isset( $allCats[
'hidden'] ) ) {
865 $hiddenCatClass = [
'mw-hidden-catlinks' ];
866 if ( $skin->getUser()->getBoolOption(
'showhiddencats' ) ) {
867 $hiddenCatClass[] =
'mw-hidden-cats-user-shown';
868 } elseif ( $skin->getTitle()->getNamespace() ==
NS_CATEGORY ) {
869 $hiddenCatClass[] =
'mw-hidden-cats-ns-shown';
871 $hiddenCatClass[] =
'mw-hidden-cats-hidden';
877 [
'hidden-categories', count( $allCats[
'hidden'] ) ]
882 if ( $catList !==
'' ) {
883 $html = $this->
getSidebarChunk(
'catlinks-sidebar', $catHeader, $catList );
899 protected function getCatList( $list, $id, $class, $message ) {
900 $html = Html::openElement(
'div', [
'id' =>
"sidebar-{$id}",
'class' => $class ] );
902 $makeLinkItem =
function ( $linkHtml ) {
903 return Html::rawElement(
'li', [], $linkHtml );
906 $categoryItems = array_map( $makeLinkItem, $list );
908 $categoriesHtml = Html::rawElement(
'ul',
910 implode(
'', $categoryItems )
913 $html .= $this->
getPortlet( $id, $categoriesHtml, $message );
915 $html .= Html::closeElement(
'div' );
930 if ( $this->pileOfTools[
'variants'] ) {
933 $this->pileOfTools[
'variants'],
935 [
'body-extra-classes' =>
'dropdown' ]
953 $variantsOnly =
false;
955 if ( $this->pileOfTools[
'variants'] ) {
958 $this->pileOfTools[
'variants']
961 $variantsOnly =
true;
963 if ( $this->data[
'language_urls'] !==
false ) {
966 $this->data[
'language_urls'] ?: [],
970 $variantsOnly =
false;
973 if ( isset( $this->otherProjects ) ) {
975 'wikibase-otherprojects',
976 $this->otherProjects[
'content']
979 $variantsOnly =
false;
987 $variantsOnly ? [
'variants-only' ] : []
1003 if ( $logo ===
null ) {
1009 if ( is_string( $logo ) ) {
1019 $width =
$file->getWidth();
1020 $height =
$file->getHeight();
1021 $bound = $width > $height ? $width : $height;
1022 $svg = File::normalizeExtension(
$file->getExtension() ) ===
'svg';
1028 $large = $doLarge ? 4 : 2;
1030 if ( $bound <= 165 ) {
1032 $logoData[
'width'] = $width;
1033 $logoData[
'height'] = $height;
1036 $logoData[
'1x'] =
$file->createThumb( $logoData[
'width'] );
1037 $logoData[
'1.5x'] =
$file->createThumb( $logoData[
'width'] * 1.5 );
1038 $logoData[
'2x'] =
$file->createThumb( $logoData[
'width'] * $large );
1039 } elseif (
$file->mustRender() ) {
1040 $logoData[
'1x'] =
$file->createThumb( $logoData[
'width'] );
1042 $logoData[
'1x'] =
$file->getUrl();
1045 } elseif ( $bound >= 230 && $bound <= 330 ) {
1047 $logoData[
'width'] = $width / 2;
1048 $logoData[
'height'] = $height / 2;
1050 $logoData[
'1x'] =
$file->createThumb( $logoData[
'width'] );
1051 $logoData[
'1.5x'] =
$file->createThumb( $logoData[
'width'] * 1.5 );
1053 if ( $svg ||
$file->mustRender() ) {
1054 $logoData[
'2x'] =
$file->createThumb( $logoData[
'width'] * 2 );
1056 $logoData[
'2x'] =
$file->getUrl();
1062 $logoData[
'width'] = 155;
1063 $logoData[
'height'] = File::scaleHeight( $width, $height, $logoData[
'width'] );
1065 $logoData[
'1x'] =
$file->createThumb( $logoData[
'width'] );
1066 if ( $svg || $logoData[
'width'] * 1.5 <= $width ) {
1067 $logoData[
'1.5x'] =
$file->createThumb( $logoData[
'width'] * 1.5 );
1069 if ( $svg || $logoData[
'width'] * 2 <= $width ) {
1070 $logoData[
'2x'] =
$file->createThumb( $logoData[
'width'] * $large );
1073 } elseif ( is_array( $logo ) ) {
1083 'alt' => $this->
getMsg(
'sitetitle' )->text(),
1085 'decoding' =>
'auto',
1086 'width' => $logoData[
'width'],
1087 'height' => $logoData[
'height'],
1090 if ( !isset( $logoData[
'1x'] ) && isset( $logoData[
'2x'] ) ) {
1092 $attribs[
'src'] = $logoData[
'2x'];
1096 $attribs[
'src'] = $logoData[
'1x'];
1099 unset( $logoData[
'1x'], $logoData[
'width'], $logoData[
'height'] );
1101 foreach ( $logoData as
$res =>
$path ) {
1102 if ( $srcset !=
'' ) {
1108 if ( $srcset !==
'' ) {
1109 $attribs[
'srcset'] = $srcset;
1113 return Html::element(
'img', $attribs );
wfFindFile( $title, $options=[])
Find a file.
New base template for a skin's template extended from QuickTemplate this class features helper method...
makeSearchButton( $mode, $attrs=[])
getToolbox()
Create an array of common toolbox items from the data in the quicktemplate stored by SkinTemplate.
getPersonalTools()
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
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.
getSkin()
Get the Skin object related to this object.
BaseTemplate class for the Timeless skin.
getLogo( $id='p-logo', $part='both')
The logo and (optionally) site title.
getHeaderHack()
The colour bars Split this out so we don't have to look at it/can easily kill it later.
getVariants()
Interlanguage links block, with variants if applicable Layout sort of assumes we're using ULS compact...
getContentBlock()
Generate the page content block Broken out here due to the excessive indenting, or stuff.
getSiteNotices()
Notices that may appear above the firstHeading.
array null $otherProjects
getContentSub()
Links and information that may appear below the firstHeading.
getPageTools()
Generate pile of all the tools.
getLogoImage( $logo, $doLarge=false)
Generate img-based logos for proper HiDPI support.
getMainNavigation()
Left sidebar navigation, usually.
mergeClasses( $class, $extraClasses)
Helper function for getPortlet.
array null $collectionPortlet
getSidebarChunk( $id, $headerMessage, $content, $classes=[])
Sidebar chunk containing one or more portlets.
getCategories()
Categories for the sidebar.
getInterwikiLinks()
Interwiki links block.
getPageToolSidebar()
Page tools in sidebar.
getUserLinks()
Personal/user links portlet for header.
getSearch()
The search box at the top.
getAfterContent()
The data after content, catlinks, and potential other stuff that may appear within the content block ...
execute()
Outputs the entire contents of the page.
getCatList( $list, $id, $class, $message)
List of categories.
getPortlet( $name, $content, $msg=null, $setOptions=[])
Generates a block of navigation links with a header This is some random fork of some random fork of w...
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
switch( $options['output']) $languages