mediawiki-skins-Insurgency/includes/MonoBookTemplate.php
Isarra cbc6e46f68 Refactor MonoBookTemplate helper functions to return output
instead of just spitting it out directly

Also rename all of said functions accordingly, add documentation,
and start trying to make an actually cross-compatible version of
getPortlet() for BaseTemplate...

Output should be structurally the same. All existing attributes for
output elements are maintained; some may have new attribs added due
to more consistent render method (getPortlet). (Essentially, if one
item had it, now they all have it.)

New attribs include:
* id
* lang
* dir
* aria-labelledby

Change-Id: I0a7ca1b95c2ad03273ed9c713be0da694c94a176
2018-04-03 04:58:46 +00:00

521 lines
14 KiB
PHP

<?php
/**
* MonoBook nouveau.
*
* Translated from gwicke's previous TAL template version to remove
* dependency on PHPTAL.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup Skins
*/
/**
* @ingroup Skins
*/
class MonoBookTemplate extends BaseTemplate {
/**
* Template filter callback for MonoBook skin.
* Takes an associative array of data set from a SkinTemplate-based
* class, and a wrapper for MediaWiki's localization database, and
* outputs a formatted page.
*/
public function execute() {
$this->html( 'headelement' );
?><div id="globalWrapper">
<div id="column-content">
<div id="content" class="mw-body" role="main">
<a id="top"></a>
<?php
if ( $this->data['sitenotice'] ) {
?>
<div id="siteNotice" class="mw-body-content"><?php
$this->html( 'sitenotice' )
?></div><?php
}
?>
<?php
echo $this->getIndicators();
// Loose comparison with '!=' is intentional, to catch null and false too, but not '0'
if ( $this->data['title'] != '' ) {
?>
<h1 id="firstHeading" class="firstHeading" lang="<?php
$this->data['pageLanguage'] =
$this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode();
$this->text( 'pageLanguage' );
?>"><?php $this->html( 'title' ) ?></h1>
<?php
}
?>
<div id="bodyContent" class="mw-body-content">
<div id="siteSub"><?php $this->msg( 'tagline' ) ?></div>
<div id="contentSub"<?php
$this->html( 'userlangattributes' ) ?>><?php $this->html( 'subtitle' )
?></div>
<?php if ( $this->data['undelete'] ) { ?>
<div id="contentSub2"><?php $this->html( 'undelete' ) ?></div>
<?php
}
?><?php
if ( $this->data['newtalk'] ) {
?>
<div class="usermessage"><?php $this->html( 'newtalk' ) ?></div>
<?php
}
?>
<div id="jump-to-nav" class="mw-jump"><?php
$this->msg( 'jumpto' )
?> <a href="#column-one"><?php
$this->msg( 'jumptonavigation' )
?></a><?php
$this->msg( 'comma-separator' )
?><a href="#searchInput"><?php
$this->msg( 'jumptosearch' )
?></a></div>
<!-- start content -->
<?php $this->html( 'bodytext' ) ?>
<?php
if ( $this->data['catlinks'] ) {
$this->html( 'catlinks' );
}
?>
<!-- end content -->
<?php
if ( $this->data['dataAfterContent'] ) {
$this->html( 'dataAfterContent' );
}
?>
<div class="visualClear"></div>
</div>
</div>
<?php Hooks::run( 'MonoBookAfterContent' ); ?>
</div>
<div id="column-one"<?php $this->html( 'userlangattributes' ) ?>>
<h2><?php $this->msg( 'navigation-heading' ) ?></h2>
<?php
// Print the content actions (cactions) bar
echo $this->getBox( 'cactions', $this->data['content_actions'], 'views' );
?>
<div class="portlet" id="p-personal" role="navigation">
<h3><?php $this->msg( 'personaltools' ) ?></h3>
<div class="pBody">
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php
$personalTools = $this->getPersonalTools();
if ( array_key_exists( 'uls', $personalTools ) ) {
echo $this->makeListItem( 'uls', $personalTools['uls'] );
unset( $personalTools['uls'] );
}
if ( !$this->getSkin()->getUser()->isLoggedIn() &&
User::groupHasPermission( '*', 'edit' )
) {
echo Html::rawElement( 'li', [
'id' => 'pt-anonuserpage'
], $this->getMsg( 'notloggedin' )->escaped() );
}
foreach ( $personalTools as $key => $item ) { ?>
<?php echo $this->makeListItem( $key, $item ); ?>
<?php
}
?>
</ul>
</div>
</div>
<div class="portlet" id="p-logo" role="banner">
<?php
echo Html::element( 'a', [
'href' => $this->data['nav_urls']['mainpage']['href'],
'class' => 'mw-wiki-logo',
]
+ Linker::tooltipAndAccesskeyAttribs( 'p-logo' )
); ?>
</div>
<?php
echo $this->getRenderedSidebar();
?>
</div><!-- end of the left (by default at least) column -->
<div class="visualClear"></div>
<?php
$validFooterIcons = $this->getFooterIcons( 'icononly' );
// Additional footer links
$validFooterLinks = $this->getFooterLinks( 'flat' );
if ( count( $validFooterIcons ) + count( $validFooterLinks ) > 0 ) {
?>
<div id="footer" role="contentinfo"<?php $this->html( 'userlangattributes' ) ?>>
<?php
$footerEnd = '</div>';
} else {
$footerEnd = '';
}
foreach ( $validFooterIcons as $blockName => $footerIcons ) {
?>
<div id="f-<?php echo htmlspecialchars( $blockName ); ?>ico">
<?php foreach ( $footerIcons as $icon ) { ?>
<?php echo $this->getSkin()->makeFooterIcon( $icon ); ?>
<?php
}
?>
</div>
<?php
}
if ( count( $validFooterLinks ) > 0 ) {
?>
<ul id="f-list">
<?php
foreach ( $validFooterLinks as $aLink ) {
?>
<li id="<?php echo $aLink ?>"><?php $this->html( $aLink ) ?></li>
<?php
}
?>
</ul>
<?php
}
echo $footerEnd;
?>
</div>
<?php
$this->printTrail();
echo Html::closeElement( 'body' );
echo Html::closeElement( 'html' );
echo "\n";
}
/**
* Generate the full sidebar
*
* @return string html
*/
protected function getRenderedSidebar() {
$sidebar = $this->data['sidebar'];
$html = '';
if ( !isset( $sidebar['SEARCH'] ) ) {
$sidebar['SEARCH'] = true;
}
if ( !isset( $sidebar['TOOLBOX'] ) ) {
$sidebar['TOOLBOX'] = true;
}
if ( !isset( $sidebar['LANGUAGES'] ) ) {
$sidebar['LANGUAGES'] = true;
}
foreach ( $sidebar as $boxName => $content ) {
if ( $content === false ) {
continue;
}
// Numeric strings gets an integer when set as key, cast back - T73639
$boxName = (string)$boxName;
if ( $boxName == 'SEARCH' ) {
$html .= $this->getSearchBox();
} elseif ( $boxName == 'TOOLBOX' ) {
$html .= $this->getToolboxBox();
} elseif ( $boxName == 'LANGUAGES' ) {
$html .= $this->getLanguageBox();
} else {
$html .= $this->getBox(
$boxName,
$content,
null,
[ 'extra-classes' => 'generated-sidebar' ]
);
}
}
return $html;
}
/**
* Generate the search, using config options for buttons (?)
*
* @return string html
*/
protected function getSearchBox() {
$html = '';
if ( $this->config->get( 'UseTwoButtonsSearchForm' ) ) {
$optionButtons = '&#160; ' . $this->makeSearchButton(
'fulltext',
[ 'id' => 'mw-searchButton', 'class' => 'searchButton' ]
);
} else {
$optionButtons = Html::rawElement( 'div', [],
Html::rawElement( 'a', [ 'href' => $this->get( 'searchaction' ), 'rel' => 'search' ],
$this->getMsg( 'powersearch-legend' )->escaped()
)
);
}
$searchInputId = 'searchInput';
$searchForm = Html::rawElement( 'form', [
'action' => $this->get( 'wgScript' ),
'id' => 'searchform'
],
Html::hidden( 'title', $this->get( 'searchtitle' ) ) .
$this->makeSearchInput( [ 'id' => $searchInputId ] ) .
$this->makeSearchButton( 'go', [ 'id' => 'searchGoButton', 'class' => 'searchButton' ] ) .
$optionButtons
);
$html .= $this->getBox( 'search', $searchForm, null, [
'search-input-id' => $searchInputId,
'role' => 'search',
'body-id' => 'searchBody'
] );
return $html;
}
/**
* Generate the toolbox, complete with all three old hooks
*
* @return string html
*/
protected function getToolboxBox() {
$html = '';
$skin = $this;
$html .= $this->getBox( 'tb', $this->getToolbox(), 'toolbox', [ 'hooks' => [
// Deprecated hooks
'MonoBookTemplateToolboxEnd' => [ &$skin ],
'SkinTemplateToolboxEnd' => [ &$skin, true ]
] ] );
// HACK: ANOTHER stupid hook
$hookContents = '';
ob_start();
Hooks::run( 'MonoBookAfterToolbox' );
$hookContents = ob_get_contents();
ob_end_clean();
if ( !trim( $hookContents ) ) {
$hookContents = '';
}
// END hack
$html .= $hookContents;
return $html;
}
/**
* Generate the languages box
*
* @return string html
*/
protected function getLanguageBox() {
$html = '';
if ( $this->data['language_urls'] !== false ) {
$html .= $this->getBox( 'lang', $this->data['language_urls'], 'otherlanguages' );
}
return $html;
}
/**
* Generate a sidebar box using getPortlet(); prefill some common stuff
*
* @param string $name
* @param array|string $contents
* @param null|string|array|bool $msg
* @param array $setOptions
*
* @return string html
*/
protected function getBox( $name, $contents, $msg = null, $setOptions = [] ) {
$options = [
'class' => 'portlet',
'body-class' => 'pBody',
'text-wrapper' => ''
];
foreach ( $setOptions as $key => $value ) {
$options[$key] = $value;
}
return $this->getPortlet( $name, $contents, $msg, $options );
}
/**
* 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
* @param null|string|array $msg
* @param array $setOptions random crap to rename/do/whatever
*
* @return string html
*/
protected function getPortlet( $name, $content, $msg = null, $setOptions = [] ) {
// random stuff to override with any provided options
$options = [
// handle role=search a little differently
'role' => 'navigation',
'search-input-id' => 'searchInput',
// extra classes/ids
'id' => 'p-' . $name,
'class' => 'mw-portlet',
'extra-classes' => '',
'body-id' => null,
'body-class' => 'mw-portlet-body',
'body-extra-classes' => '',
// wrapper for individual list items
'text-wrapper' => [ 'tag' => 'span' ],
// old toolbox hook support (use: [ 'SkinTemplateToolboxEnd' => [ &$skin, true ] ])
'hooks' => ''
];
// set options based on input
foreach ( $setOptions as $key => $value ) {
$options[$key] = $value;
}
// Handle the different $msg possibilities
if ( $msg === null ) {
$msg = $name;
$msgParams = [];
} elseif ( is_array( $msg ) ) {
$msgString = array_shift( $msg );
$msgParams = $msg;
$msg = $msgString;
} else {
$msgParams = [];
}
$msgObj = $this->getMsg( $msg, $msgParams );
if ( $msgObj->exists() ) {
$msgString = $msgObj->parse();
} else {
$msgString = htmlspecialchars( $msg );
}
// HACK: Compatibility with extensions still using SkinTemplateToolboxEnd or other stupid hooks
$hooksContents = '';
if ( is_array( $options['hooks'] ) ) {
foreach ( $options['hooks'] as $hook => $hookOptions ) {
ob_start();
Hooks::run( $hook, $hookOptions );
$hookContents = ob_get_contents();
ob_end_clean();
if ( !trim( $hookContents ) ) {
$hookContents = '';
}
$hooksContents .= $hookContents;
}
}
// END hack
$labelId = Sanitizer::escapeId( "p-$name-label" );
if ( is_array( $content ) ) {
$contentText = Html::openElement( 'ul',
[ 'lang' => $this->get( 'userlang' ), 'dir' => $this->get( 'dir' ) ]
);
foreach ( $content as $key => $item ) {
if ( is_array( $options['text-wrapper'] ) ) {
$contentText .= $this->makeListItem(
$key,
$item,
[ 'text-wrapper' => $options['text-wrapper'] ]
);
} else {
$contentText .= $this->makeListItem(
$key,
$item
);
}
}
// Add in hook crap, if any
$contentText .= $hooksContents;
$contentText .= Html::closeElement( 'ul' );
} else {
$contentText = $content;
}
// Special handling for role=search
$divOptions = [
'role' => $options['role'],
'class' => $this->mergeClasses( $options['class'], $options['extra-classes'] ),
'id' => Sanitizer::escapeId( $options['id'] ),
'title' => Linker::titleAttrib( $options['id'] )
];
if ( $options['role'] !== 'search' ) {
$divOptions['aria-labelledby'] = $labelId;
}
$labelOptions = [
'id' => $labelId,
'lang' => $this->get( 'userlang' ),
'dir' => $this->get( 'dir' )
];
if ( $options['role'] == 'search' ) {
$msgString = Html::rawElement( 'label', [ 'for' => $options['search-input-id'] ], $msgString );
}
$bodyDivOptions = [
'class' => $this->mergeClasses( $options['body-class'], $options['body-extra-classes'] )
];
if ( is_string( $options['body-id'] ) ) {
$bodyDivOptions['id'] = $options['body-id'];
}
$html = Html::rawElement( 'div', $divOptions,
Html::rawElement( 'h3', $labelOptions, $msgString ) .
Html::rawElement( 'div', $bodyDivOptions,
$contentText .
$this->getAfterPortlet( $name )
)
);
return $html;
}
/**
* Helper function for getPortlet
*
* Merge all provided css classes into a single array
* Account for possible different input methods matching what Html::element stuff takes
*
* @param string|array $class base portlet/body class
* @param string|array $extraClasses any extra classes to also include
*
* @return array all classes to apply
*/
protected function mergeClasses( $class, $extraClasses ) {
if ( !is_array( $class ) ) {
$class = [ $class ];
}
if ( !is_array( $extraClasses ) ) {
$extraClasses = [ $extraClasses ];
}
return array_merge( $class, $extraClasses );
}
}