You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
841 lines
22 KiB
PHP
841 lines
22 KiB
PHP
<?php
|
|
/**
|
|
* BaseTemplate class for the Timeless skin
|
|
*
|
|
* @ingroup Skins
|
|
*/
|
|
class TimelessTemplate extends BaseTemplate {
|
|
|
|
/** @var array */
|
|
protected $pileOfTools;
|
|
|
|
/**
|
|
* Outputs the entire contents of the page
|
|
*/
|
|
public function execute() {
|
|
$this->pileOfTools = $this->getPageTools();
|
|
$userLinks = $this->getUserLinks();
|
|
|
|
// Open html, body elements, etc
|
|
$html = $this->get( 'headelement' );
|
|
|
|
$html .= Html::openElement( 'div', [ 'id' => 'mw-wrapper', 'class' => $userLinks['class'] ] );
|
|
|
|
$html .= Html::rawElement( 'div', [ 'id' => 'mw-header-container', 'class' => 'ts-container' ],
|
|
Html::rawElement( 'div', [ 'id' => 'mw-header', 'class' => 'ts-inner' ],
|
|
$userLinks['html'] .
|
|
$this->getLogo( 'p-logo-text', 'text' ) .
|
|
$this->getSearch()
|
|
) .
|
|
$this->getClear()
|
|
);
|
|
$html .= $this->getHeaderHack();
|
|
|
|
// For mobile
|
|
$html .= Html::element( 'div', [ 'id' => 'menus-cover' ] );
|
|
|
|
$html .= Html::rawElement( 'div', [ 'id' => 'mw-content-container', 'class' => 'ts-container' ],
|
|
Html::rawElement( 'div', [ 'id' => 'mw-content-block', 'class' => 'ts-inner' ],
|
|
Html::rawElement( 'div', [ 'id' => 'mw-site-navigation' ],
|
|
$this->getLogo( 'p-logo', 'image' ) .
|
|
$this->getMainNavigation() .
|
|
$this->getSidebarChunk(
|
|
'site-tools',
|
|
'timeless-sitetools',
|
|
$this->getPortlet(
|
|
'tb',
|
|
$this->pileOfTools['general'],
|
|
'timeless-sitetools'
|
|
)
|
|
)
|
|
) .
|
|
Html::rawElement( 'div', [ 'id' => 'mw-related-navigation' ],
|
|
$this->getPageToolSidebar() .
|
|
$this->getInterlanguageLinks() .
|
|
$this->getCategories()
|
|
) .
|
|
Html::rawElement( 'div', [ 'id' => 'mw-content' ],
|
|
Html::rawElement( 'div', [ 'id' => 'content', 'class' => 'mw-body', 'role' => 'main' ],
|
|
$this->getSiteNotices() .
|
|
$this->getIndicators() .
|
|
Html::rawElement(
|
|
'h1',
|
|
[
|
|
'id' => 'firstHeading',
|
|
'class' => 'firstHeading',
|
|
'lang' => $this->get( 'pageLanguage' )
|
|
],
|
|
$this->get( 'title' )
|
|
) .
|
|
Html::rawElement( 'div', [ 'id' => 'mw-page-header-links' ],
|
|
$this->getPortlet(
|
|
'namespaces',
|
|
$this->pileOfTools['namespaces'],
|
|
'timeless-namespaces'
|
|
) .
|
|
$this->getPortlet(
|
|
'pagetools',
|
|
$this->pileOfTools['page-primary'],
|
|
'timeless-pagetools'
|
|
)
|
|
) .
|
|
$this->getClear() .
|
|
Html::rawElement( 'div', [ 'class' => 'mw-body-content', 'id' => 'bodyContent' ],
|
|
$this->getContentSub() .
|
|
$this->get( 'bodytext' ) .
|
|
$this->getClear()
|
|
)
|
|
)
|
|
) .
|
|
$this->getAfterContent() .
|
|
$this->getClear()
|
|
)
|
|
);
|
|
|
|
$html .= Html::rawElement( 'div', [ 'id' => 'mw-footer-container', 'class' => 'ts-container' ],
|
|
Html::rawElement( 'div', [ 'id' => 'mw-footer', 'class' => 'ts-inner' ],
|
|
$this->getFooter()
|
|
)
|
|
);
|
|
|
|
$html .= Html::closeElement( 'div' );
|
|
|
|
// BaseTemplate::printTrail() stuff (has no get version)
|
|
// Required for RL to run
|
|
$html .= MWDebug::getDebugHTML( $this->getSkin()->getContext() );
|
|
$html .= $this->get( 'bottomscripts' );
|
|
$html .= $this->get( 'reporttime' );
|
|
|
|
$html .= Html::closeElement( 'body' );
|
|
$html .= Html::closeElement( 'html' );
|
|
|
|
// The unholy echo
|
|
echo $html;
|
|
}
|
|
|
|
/**
|
|
* Generates a block of navigation links with a header
|
|
*
|
|
* @param string $name
|
|
* @param array|string $content array of links for use with makeListItem, or a block of text
|
|
* Expected array format:
|
|
* [
|
|
* $name => [
|
|
* 'links' => [ '0' =>
|
|
* [ 'href' => ..., 'single-id' => ..., 'text' => ... ]
|
|
* ],
|
|
* 'id' => ...,
|
|
* 'active' => ...
|
|
* ],
|
|
* ...
|
|
* ]
|
|
* @param null|string|array|bool $msg
|
|
*
|
|
* @return string html
|
|
* @since 1.29
|
|
*/
|
|
protected function getPortlet( $name, $content, $msg = null ) {
|
|
if ( $msg === null ) {
|
|
$msg = $name;
|
|
} elseif ( is_array( $msg ) ) {
|
|
$msgString = array_shift( $msg );
|
|
$msgParams = $msg;
|
|
$msg = $msgString;
|
|
}
|
|
$msgObj = wfMessage( $msg );
|
|
if ( $msgObj->exists() ) {
|
|
if ( isset( $msgParams ) && !empty( $msgParams ) ) {
|
|
$msgString = $this->getMsg( $msg, $msgParams )->parse();
|
|
} else {
|
|
$msgString = $msgObj->parse();
|
|
}
|
|
} else {
|
|
$msgString = htmlspecialchars( $msg );
|
|
}
|
|
|
|
// HACK: Compatibility with extensions still using SkinTemplateToolboxEnd
|
|
$hookContents = '';
|
|
if ( $name == 'tb' ) {
|
|
if ( isset( $boxes['TOOLBOX'] ) ) {
|
|
ob_start();
|
|
// We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
|
|
// can abort and avoid outputting double toolbox links
|
|
// Avoid PHP 7.1 warning from passing $this by reference
|
|
$template = $this;
|
|
Hooks::run( 'SkinTemplateToolboxEnd', [ &$template, true ] );
|
|
$hookContents = ob_get_contents();
|
|
ob_end_clean();
|
|
if ( !trim( $hookContents ) ) {
|
|
$hookContents = '';
|
|
}
|
|
}
|
|
}
|
|
// END hack
|
|
|
|
$labelId = Sanitizer::escapeId( "p-$name-label" );
|
|
|
|
if ( is_array( $content ) ) {
|
|
$contentText = Html::openElement( 'ul' );
|
|
foreach ( $content as $key => $item ) {
|
|
$contentText .= $this->makeListItem(
|
|
$key,
|
|
$item,
|
|
[ 'text-wrapper' => [ 'tag' => 'span' ] ]
|
|
);
|
|
}
|
|
// Add in SkinTemplateToolboxEnd, if any
|
|
$contentText .= $hookContents;
|
|
$contentText .= Html::closeElement( 'ul' );
|
|
} else {
|
|
$contentText = $content;
|
|
}
|
|
|
|
$html = Html::rawElement( 'div', [
|
|
'role' => 'navigation',
|
|
'class' => 'mw-portlet',
|
|
'id' => Sanitizer::escapeId( 'p-' . $name ),
|
|
'title' => Linker::titleAttrib( 'p-' . $name ),
|
|
'aria-labelledby' => $labelId
|
|
],
|
|
Html::rawElement( 'h3', [
|
|
'id' => $labelId,
|
|
'lang' => $this->get( 'userlang' ),
|
|
'dir' => $this->get( 'dir' )
|
|
],
|
|
$msgString
|
|
) .
|
|
Html::rawElement( 'div', [ 'class' => 'mw-portlet-body' ],
|
|
$contentText .
|
|
$this->getAfterPortlet( $name )
|
|
)
|
|
);
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Sidebar chunk containing one or more portlets
|
|
*
|
|
* @param string $id
|
|
* @param string $headerMessage
|
|
* @param string $content
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getSidebarChunk( $id, $headerMessage, $content ) {
|
|
$html = '';
|
|
|
|
$html .= Html::rawElement(
|
|
'div',
|
|
[ 'id' => Sanitizer::escapeId( $id ), 'class' => 'sidebar-chunk' ],
|
|
Html::rawElement( 'h2', [],
|
|
Html::rawElement( 'span', [],
|
|
$this->getMsg( $headerMessage )->escaped()
|
|
) .
|
|
Html::element( 'div', [ 'class' => 'pokey' ] )
|
|
) .
|
|
Html::rawElement( 'div', [ 'class' => 'sidebar-inner' ], $content )
|
|
);
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* The logo and (optionally) site title
|
|
*
|
|
* @param string $id
|
|
* @param string $part whether it's only image, only text, or both
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getLogo( $id = 'p-logo', $part = 'both' ) {
|
|
$html = '';
|
|
|
|
$html .= Html::openElement(
|
|
'div',
|
|
[
|
|
'id' => Sanitizer::escapeId( $id ),
|
|
'class' => 'mw-portlet',
|
|
'role' => 'banner'
|
|
]
|
|
);
|
|
if ( $part !== 'image' ) {
|
|
$titleClass = '';
|
|
$siteTitle = $this->getMsg( 'timeless-sitetitle' )->escaped();
|
|
// width is 11em; 13 characters will probably fit?
|
|
if ( mb_strlen( $siteTitle ) > 13 ) {
|
|
$titleClass = 'long';
|
|
}
|
|
$html .= Html::element( 'a', [
|
|
'id' => 'p-banner',
|
|
'class' => [ 'mw-wiki-title', $titleClass ],
|
|
'href' => htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] )
|
|
],
|
|
$siteTitle
|
|
);
|
|
}
|
|
if ( $part !== 'text' ) {
|
|
$html .= Html::element( 'a', array_merge(
|
|
[
|
|
'class' => 'mw-wiki-logo',
|
|
'href' => htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] )
|
|
],
|
|
Linker::tooltipAndAccesskeyAttribs( 'p-logo' )
|
|
) );
|
|
}
|
|
$html .= Html::closeElement( 'div' );
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* The search box at the top
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getSearch() {
|
|
$html = '';
|
|
|
|
$html .= Html::openElement( 'div', [ 'class' => 'mw-portlet', 'id' => 'p-search' ] );
|
|
|
|
$html .= Html::rawElement(
|
|
'h3',
|
|
[ 'lang' => $this->get( 'userlang' ), 'dir' => $this->get( 'dir' ) ],
|
|
Html::rawElement( 'label', [ 'for' => 'searchInput' ], $this->getMsg( 'search' )->text() )
|
|
);
|
|
|
|
$html .= Html::rawElement( 'form', [ 'action' => $this->get( 'wgScript' ), 'id' => 'searchform' ],
|
|
Html::rawElement( 'div', [ 'id' => 'simpleSearch' ],
|
|
Html::rawElement( 'div', [ 'id' => 'searchInput-container' ],
|
|
$this->makeSearchInput( [
|
|
'id' => 'searchInput',
|
|
'placeholder' => $this->getMsg( 'timeless-search-placeholder' )->text(),
|
|
] )
|
|
) .
|
|
Html::hidden( 'title', $this->get( 'searchtitle' ) ) .
|
|
$this->makeSearchButton(
|
|
'fulltext',
|
|
[ 'id' => 'mw-searchButton', 'class' => 'searchButton mw-fallbackSearchButton' ]
|
|
) .
|
|
$this->makeSearchButton(
|
|
'go',
|
|
[ 'id' => 'searchButton', 'class' => 'searchButton' ]
|
|
)
|
|
)
|
|
);
|
|
|
|
$html .= Html::closeElement( 'div' );
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Left sidebar navigation, usually
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getMainNavigation() {
|
|
$sidebar = $this->getSidebar();
|
|
$html = '';
|
|
|
|
$sidebar['SEARCH'] = false; // Already hardcoded into header
|
|
$sidebar['TOOLBOX'] = false; // Parsed as part of pageTools
|
|
$sidebar['LANGUAGES'] = false; // Forcibly removed to separate chunk
|
|
|
|
foreach ( $sidebar as $name => $content ) {
|
|
if ( $content === false ) {
|
|
continue;
|
|
}
|
|
// Numeric strings gets an integer when set as key, cast back - T73639
|
|
$name = (string)$name;
|
|
$html .= $this->getPortlet( $name, $content['content'] );
|
|
}
|
|
|
|
$html = $this->getSidebarChunk( 'site-navigation', 'navigation', $html );
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* The colour bars
|
|
* Split this out so we don't have to look at it/can easily kill it later
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getHeaderHack() {
|
|
$html = '';
|
|
|
|
// These are almost exactly the same and this is stupid.
|
|
$html .= Html::rawElement( 'div', [ 'id' => 'mw-header-hack', 'class' => 'color-bar' ],
|
|
Html::rawElement( 'div', [ 'class' => 'color-middle-container' ],
|
|
Html::element( 'div', [ 'class' => 'color-middle' ] )
|
|
) .
|
|
Html::element( 'div', [ 'class' => 'color-left' ] ) .
|
|
Html::element( 'div', [ 'class' => 'color-right' ] )
|
|
);
|
|
$html .= Html::rawElement( 'div', [ 'id' => 'mw-header-nav-hack' ],
|
|
Html::rawElement( 'div', [ 'class' => 'color-bar' ],
|
|
Html::rawElement( 'div', [ 'class' => 'color-middle-container' ],
|
|
Html::element( 'div', [ 'class' => 'color-middle' ] )
|
|
) .
|
|
Html::element( 'div', [ 'class' => 'color-left' ] ) .
|
|
Html::element( 'div', [ 'class' => 'color-right' ] )
|
|
)
|
|
);
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Page tools in sidebar
|
|
*
|
|
* @return string html
|
|
**/
|
|
protected function getPageToolSidebar() {
|
|
$pageTools = '';
|
|
if ( count( $this->pileOfTools['page-secondary'] ) > 0 ) {
|
|
$pageTools .= $this->getPortlet(
|
|
'pageactions',
|
|
$this->pileOfTools['page-secondary'],
|
|
'timeless-pageactions'
|
|
);
|
|
}
|
|
if ( count( $this->pileOfTools['user'] ) > 0 ) {
|
|
$pageTools .= $this->getPortlet(
|
|
'userpagetools',
|
|
$this->pileOfTools['user'],
|
|
'timeless-userpagetools'
|
|
);
|
|
}
|
|
$pageTools .= $this->getPortlet(
|
|
'pagemisc',
|
|
$this->pileOfTools['page-tertiary'],
|
|
'timeless-pagemisc'
|
|
);
|
|
|
|
return $this->getSidebarChunk( 'page-tools', 'timeless-pageactions', $pageTools );
|
|
}
|
|
|
|
/**
|
|
* Personal/user links portlet for header
|
|
*
|
|
* @return array [ html, class ], where class is an extra class to apply to surrounding objects
|
|
* (for width adjustments)
|
|
*/
|
|
protected function getUserLinks() {
|
|
$user = $this->getSkin()->getUser();
|
|
$personalTools = $this->getPersonalTools();
|
|
|
|
$html = '';
|
|
$extraTools = [];
|
|
|
|
// Remove Echo badges
|
|
if ( isset( $personalTools['notifications-alert'] ) ) {
|
|
$extraTools['notifications-alert'] = $personalTools['notifications-alert'];
|
|
unset( $personalTools['notifications-alert'] );
|
|
}
|
|
if ( isset( $personalTools['notifications-notice'] ) ) {
|
|
$extraTools['notifications-notice'] = $personalTools['notifications-notice'];
|
|
unset( $personalTools['notifications-notice'] );
|
|
}
|
|
$class = empty( $extraTools ) ? '' : 'extension-icons';
|
|
|
|
// Re-label some messages
|
|
if ( isset( $personalTools['userpage'] ) ) {
|
|
$personalTools['userpage']['links'][0]['text'] = $this->getMsg( 'timeless-userpage' )->text();
|
|
}
|
|
if ( isset( $personalTools['mytalk'] ) ) {
|
|
$personalTools['mytalk']['links'][0]['text'] = $this->getMsg( 'timeless-talkpage' )->text();
|
|
}
|
|
|
|
// Labels
|
|
if ( $user->isLoggedIn() ) {
|
|
$userName = $user->getName();
|
|
// Make sure it fits first (numbers slightly made up, may need adjusting)
|
|
$fit = empty( $extraTools ) ? 13 : 9;
|
|
if ( mb_strlen( $userName ) < $fit ) {
|
|
$dropdownHeader = htmlspecialchars( $userName, ENT_QUOTES );
|
|
} else {
|
|
$dropdownHeader = wfMessage( 'timeless-loggedin' )->escaped();
|
|
}
|
|
$headerMsg = [ 'timeless-loggedinas', $user->getName() ];
|
|
} else {
|
|
$dropdownHeader = wfMessage( 'timeless-anonymous' )->escaped();
|
|
$headerMsg = 'timeless-notloggedin';
|
|
}
|
|
$html .= Html::openElement( 'div', [ 'id' => 'user-tools' ] );
|
|
|
|
$html .= Html::rawElement( 'div', [ 'id' => 'personal' ],
|
|
Html::rawElement( 'h2', [],
|
|
Html::rawElement( 'span', [], $dropdownHeader ) .
|
|
Html::element( 'div', [ 'class' => 'pokey' ] )
|
|
) .
|
|
Html::rawElement( 'div', [ 'id' => 'personal-inner', 'class' => 'dropdown' ],
|
|
$this->getPortlet( 'personal', $personalTools, $headerMsg )
|
|
)
|
|
);
|
|
|
|
// Extra icon stuff (echo etc)
|
|
if ( !empty( $extraTools ) ) {
|
|
$iconList = '';
|
|
foreach ( $extraTools as $key => $item ) {
|
|
$iconList .= $this->makeListItem( $key, $item );
|
|
}
|
|
|
|
$html .= Html::rawElement(
|
|
'div',
|
|
[ 'id' => 'personal-extra', 'class' => 'p-body' ],
|
|
Html::rawElement( 'ul', [], $iconList )
|
|
);
|
|
}
|
|
|
|
$html .= Html::closeElement( 'div' );
|
|
|
|
return [
|
|
'html' => $html,
|
|
'class' => $class
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Notices that may appear above the firstHeading
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getSiteNotices() {
|
|
$html = '';
|
|
|
|
if ( $this->data['sitenotice'] ) {
|
|
$html .= Html::rawElement( 'div', [ 'id' => 'siteNotice' ], $this->get( 'sitenotice' ) );
|
|
}
|
|
if ( $this->data['newtalk'] ) {
|
|
$html .= Html::rawElement( 'div', [ 'class' => 'usermessage' ], $this->get( 'newtalk' ) );
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Links and information that may appear below the firstHeading
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getContentSub() {
|
|
$html = '';
|
|
|
|
$html .= Html::openElement( 'div', [ 'id' => 'contentSub' ] );
|
|
if ( $this->data['subtitle'] ) {
|
|
$html .= $this->get( 'subtitle' );
|
|
}
|
|
if ( $this->data['undelete'] ) {
|
|
$html .= $this->get( 'undelete' );
|
|
}
|
|
$html .= Html::closeElement( 'div' );
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* The data after content, catlinks, and potential other stuff that may appear within
|
|
* the content block but after the main content
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getAfterContent() {
|
|
$html = '';
|
|
|
|
if ( $this->data['catlinks'] || $this->data['dataAfterContent'] ) {
|
|
$html .= Html::openElement( 'div', [ 'id' => 'content-bottom-stuff' ] );
|
|
if ( $this->data['catlinks'] ) {
|
|
$html .= $this->get( 'catlinks' );
|
|
}
|
|
if ( $this->data['dataAfterContent'] ) {
|
|
$html .= $this->get( 'dataAfterContent' );
|
|
}
|
|
$html .= Html::closeElement( 'div' );
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Generate pile of all the tools
|
|
*
|
|
* We can make a few assumptions based on where a tool started out:
|
|
* If it's in the cactions region, it's a page tool, probably primary or secondary
|
|
* ...that's all I can think of
|
|
*
|
|
* @return array of array of tools information (portlet formatting)
|
|
*/
|
|
protected function getPageTools() {
|
|
$title = $this->getSkin()->getTitle();
|
|
$namespace = $title->getNamespace();
|
|
|
|
$sortedPileOfTools = [
|
|
'namespaces' => [],
|
|
'page-primary' => [],
|
|
'page-secondary' => [],
|
|
'user' => [],
|
|
'page-tertiary' => [],
|
|
'general' => []
|
|
];
|
|
|
|
// Tools specific to the page
|
|
$pileOfEditTools = [];
|
|
foreach ( $this->data['content_navigation'] as $navKey => $navBlock ) {
|
|
// Just use namespaces items as they are
|
|
if ( $navKey == 'namespaces' ) {
|
|
if ( $namespace < 0 ) {
|
|
// Put special page ns_pages in the more pile so they're not so lonely
|
|
$sortedPileOfTools['page-tertiary'] = $navBlock;
|
|
} else {
|
|
$sortedPileOfTools['namespaces'] = $navBlock;
|
|
}
|
|
} else {
|
|
$pileOfEditTools = array_merge( $pileOfEditTools, $navBlock );
|
|
}
|
|
}
|
|
|
|
// Tools that may be general or page-related (typically the toolbox)
|
|
$pileOfTools = $this->getToolbox();
|
|
if ( $namespace >= 0 ) {
|
|
$pileOfTools['pagelog'] = [
|
|
'text' => $this->getMsg( 'timeless-pagelog' )->text(),
|
|
'href' => SpecialPage::getTitleFor( 'Log', $title->getPrefixedText() )->getLocalURL(),
|
|
'id' => 't-pagelog'
|
|
];
|
|
}
|
|
$pileOfTools['more'] = [
|
|
'text' => $this->getMsg( 'timeless-more' )->text(),
|
|
'id' => 'ca-more',
|
|
'class' => 'dropdown-toggle'
|
|
];
|
|
|
|
// Goes in the page-primary in mobile, doesn't appear otherwise
|
|
if ( $this->data['language_urls'] !== false ) {
|
|
$pileOfTools['languages'] = [
|
|
'text' => $this->getMsg( 'timeless-languages' )->escaped(),
|
|
'id' => 'ca-languages',
|
|
'class' => 'dropdown-toggle'
|
|
];
|
|
}
|
|
|
|
// This is really dumb, and you're an idiot for doing it this way.
|
|
// Obviously if you're not the idiot who did this, I don't mean you.
|
|
foreach ( $pileOfEditTools as $navKey => $navBlock ) {
|
|
$currentSet = null;
|
|
|
|
if ( in_array( $navKey, [
|
|
'watch',
|
|
'unwatch'
|
|
] ) ) {
|
|
$currentSet = 'namespaces';
|
|
} elseif ( in_array( $navKey, [
|
|
'edit',
|
|
'view',
|
|
'history',
|
|
'addsection'
|
|
] ) ) {
|
|
$currentSet = 'page-primary';
|
|
} elseif ( in_array( $navKey, [
|
|
'delete',
|
|
'rename',
|
|
'protect',
|
|
'unprotect',
|
|
'viewsource',
|
|
'move'
|
|
] ) ) {
|
|
$currentSet = 'page-secondary';
|
|
} else {
|
|
$currentSet = 'page-primary'; // Catch random extension ones?
|
|
}
|
|
$sortedPileOfTools[$currentSet][$navKey] = $navBlock;
|
|
}
|
|
foreach ( $pileOfTools as $navKey => $navBlock ) {
|
|
$currentSet = null;
|
|
|
|
if ( in_array( $navKey, [
|
|
'contributions',
|
|
'more',
|
|
'languages'
|
|
] ) ) {
|
|
$currentSet = 'page-primary';
|
|
} elseif ( in_array( $navKey, [
|
|
'blockip',
|
|
'userrights',
|
|
'log'
|
|
] ) ) {
|
|
$currentSet = 'user';
|
|
} elseif ( in_array( $navKey, [
|
|
'whatlinkshere',
|
|
'print',
|
|
'info',
|
|
'pagelog',
|
|
'recentchangeslinked',
|
|
'permalink'
|
|
] ) ) {
|
|
$currentSet = 'page-tertiary';
|
|
} else {
|
|
$currentSet = 'general';
|
|
}
|
|
$sortedPileOfTools[$currentSet][$navKey] = $navBlock;
|
|
}
|
|
|
|
return $sortedPileOfTools;
|
|
}
|
|
|
|
/**
|
|
* Categories for the sidebar
|
|
*
|
|
* Assemble an array of categories, regardless of view mode. Just using Skin or
|
|
* OutputPage functions doesn't respect view modes (preview, history, whatever)
|
|
* But why? I have no idea what the purpose of this is.
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getCategories() {
|
|
global $wgContLang;
|
|
|
|
$skin = $this->getSkin();
|
|
$title = $skin->getTitle();
|
|
$catList = false;
|
|
$html = '';
|
|
|
|
// Get list from outputpage if in preview; otherwise get list from title
|
|
if ( in_array( $skin->getRequest()->getVal( 'action' ), [ 'submit', 'edit' ] ) ) {
|
|
$allCats = [];
|
|
// Can't just use getCategoryLinks because there's no equivalent for Title
|
|
$allCats2 = $skin->getOutput()->getCategories();
|
|
foreach ( $allCats2 as $displayName ) {
|
|
$catTitle = Title::makeTitleSafe( NS_CATEGORY, $displayName );
|
|
$allCats[] = $catTitle->getDBkey();
|
|
}
|
|
} else {
|
|
// This is probably to trim out some excessive stuff. Unless I was just high on cough syrup.
|
|
$allCats = array_keys( $title->getParentCategories() );
|
|
|
|
$len = strlen( $wgContLang->getNsText( NS_CATEGORY ) . ':' );
|
|
foreach ( $allCats as $i => $catName ) {
|
|
$allCats[$i] = substr( $catName, $len );
|
|
}
|
|
}
|
|
if ( count( $allCats ) > 0 ) {
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
$res = $dbr->select(
|
|
[ 'page', 'page_props' ],
|
|
[ 'page_id', 'page_title' ],
|
|
[
|
|
'page_title' => $allCats,
|
|
'page_namespace' => NS_CATEGORY,
|
|
'pp_propname' => 'hiddencat'
|
|
],
|
|
__METHOD__,
|
|
[],
|
|
[ 'page_props' => [ 'JOIN', 'pp_page = page_id' ] ]
|
|
);
|
|
$hiddenCats = [];
|
|
foreach ( $res as $row ) {
|
|
$hiddenCats[] = $row->page_title;
|
|
}
|
|
$normalCats = array_diff( $allCats, $hiddenCats );
|
|
|
|
$normalCount = count( $normalCats );
|
|
$hiddenCount = count( $hiddenCats );
|
|
$count = $normalCount;
|
|
|
|
// Mostly consistent with how Skin does it.
|
|
// Doesn't have the classes. Either way can't be good for caching.
|
|
if (
|
|
$skin->getUser()->getBoolOption( 'showhiddencats' ) ||
|
|
$title->getNamespace() == NS_CATEGORY
|
|
) {
|
|
$count += $hiddenCount;
|
|
} else {
|
|
/* We don't care if there are hidden ones. */
|
|
$hiddenCount = 0;
|
|
}
|
|
|
|
// Assemble the html...
|
|
if ( $count ) {
|
|
if ( $normalCount ) {
|
|
$catHeader = 'categories';
|
|
} else {
|
|
$catHeader = 'hidden-categories';
|
|
}
|
|
$catList = '';
|
|
if ( $normalCount ) {
|
|
$catList .= $this->getCatList( $normalCats, 'catlist-normal', 'categories' );
|
|
}
|
|
if ( $hiddenCount ) {
|
|
$catList .= $this->getCatList( $hiddenCats, 'catlist-hidden', 'hidden-categories' );
|
|
}
|
|
}
|
|
}
|
|
if ( $catList ) {
|
|
$html = $this->getSidebarChunk( 'catlinks-sidebar', $catHeader, $catList );
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* List of categories
|
|
*
|
|
* @param array $list
|
|
* @param string $id
|
|
* @param string $message
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getCatList( $list, $id, $message ) {
|
|
$html = '';
|
|
|
|
$categories = [];
|
|
// Generate portlet content
|
|
foreach ( $list as $category ) {
|
|
$title = Title::makeTitleSafe( NS_CATEGORY, $category );
|
|
if ( !$title ) {
|
|
continue;
|
|
}
|
|
$categories[ htmlspecialchars( $category ) ] = [ 'links' => [ 0 => [
|
|
'href' => $title->getLinkURL(),
|
|
'text' => $title->getText()
|
|
] ] ];
|
|
}
|
|
|
|
$html .= $this->getPortlet( $id, $categories, $message );
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Interlanguage links block, also with variants
|
|
*
|
|
* @return string html
|
|
*/
|
|
protected function getInterlanguageLinks() {
|
|
$html = '';
|
|
|
|
if ( isset( $this->data['variant_urls'] ) && $this->data['variant_urls'] !== false ) {
|
|
$variants = $this->getPortlet( 'variants', $this->data['variant_urls'], true );
|
|
} else {
|
|
$variants = '';
|
|
}
|
|
if ( $this->data['language_urls'] !== false ) {
|
|
|
|
$html .= $this->getSidebarChunk(
|
|
'other-languages',
|
|
'timeless-languages',
|
|
$variants .
|
|
$this->getPortlet(
|
|
'lang',
|
|
$this->data['language_urls'] ?: [],
|
|
'otherlanguages'
|
|
)
|
|
);
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
}
|