gplx/mediawiki/includes/skins/components/SkinComponentMenu.php

178 lines
4.5 KiB
PHP

<?php
namespace MediaWiki\Skin;
use MediaWiki\Html\Html;
use MediaWiki\Linker\Linker;
use MediaWiki\Message\Message;
use MediaWiki\Parser\Sanitizer;
use MessageLocalizer;
/**
* @internal for use inside Skin and SkinTemplate classes only
* @unstable
*/
class SkinComponentMenu implements SkinComponent {
/** @var string */
private $name;
/** @var array */
private $items;
/** @var MessageLocalizer */
private $localizer;
/** @var string */
private $content;
/** @var array */
private $linkOptions;
/** @var string */
private $htmlAfterContent;
/** @var string */
private $htmlBeforeContent;
/**
* @param string $name
* @param array $items
* @param MessageLocalizer $localizer
* @param string $content
* @param array $linkOptions
* @param string $htmlAfterContent
* @param string $htmlBeforeContent
*/
public function __construct(
string $name,
array $items,
MessageLocalizer $localizer,
string $content = '',
array $linkOptions = [],
string $htmlAfterContent = '',
string $htmlBeforeContent = ''
) {
$this->name = $name;
$this->items = $items;
$this->localizer = $localizer;
$this->content = $content;
$this->linkOptions = $linkOptions;
$this->htmlAfterContent = $htmlAfterContent;
$this->htmlBeforeContent = $htmlBeforeContent;
}
/**
* @param string $key
*
* @return Message
*/
private function msg( string $key ): Message {
return $this->localizer->msg( $key );
}
/**
* @param string $name of the menu e.g. p-personal the name is personal.
*
* @return string that is human-readable corresponding to the menu.
*/
private function getMenuLabel( $name ) {
// For historic reasons for some menu items, there is no language key corresponding
// with its menu key.
$mappings = [
'tb' => 'toolbox',
'personal' => 'personaltools',
'lang' => 'otherlanguages',
];
$msgObj = $this->msg( $mappings[ $name ] ?? $name );
// If no message exists fallback to plain text (T252727)
return $msgObj->exists() ? $msgObj->text() : $name;
}
/**
* @inheritDoc
*/
public function getTemplateData(): array {
$name = $this->name;
// Monobook and Vector historically render this portal as an element with ID p-cactions.
// To ensure compatibility with gadgets, it is renamed accordingly.
// @todo Port p-#cactions to #p-actions and drop these conditionals.
if ( $name === 'actions' ) {
$name = 'cactions';
}
// The new personal tools without the notifications is user-menu.
// A lot of user code and gadgets relies on it being named personal.
// This allows it to function as a drop-in replacement.
if ( $name === 'user-menu' ) {
$name = 'personal';
}
if ( strpos( $name, 'footer' ) === 0 ) {
// Retain footer IDs.
$id = $name;
} else {
$id = Sanitizer::escapeIdForAttribute( "p-$name" );
}
$isEmptyContent = !$this->content;
$isEmptyAfterContent = !$this->htmlAfterContent;
$isEmptyBeforeContent = !$this->htmlBeforeContent;
$isEmptyItems = count( $this->items ) === 0;
$isEmptyPortlet = ( $isEmptyContent && $isEmptyAfterContent && $isEmptyBeforeContent && $isEmptyItems );
$data = [
'id' => $id,
// Any changes to these classes should be synced with resources/src/mediawiki.util/util.js
'class' => 'mw-portlet ' . Sanitizer::escapeClass( "mw-portlet-$name" ),
'html-tooltip' => Linker::tooltip( $id ),
'html-items' => '',
// Will be populated by SkinAfterPortlet hook.
'html-after-portal' => '',
'html-before-portal' => '',
'is-empty' => $isEmptyPortlet,
];
// for output. In production this currently supports the Wikibase 'edit' link.
if ( !$isEmptyAfterContent ) {
$data['html-after-portal'] = Html::rawElement(
'div',
[
'class' => [
'after-portlet',
Sanitizer::escapeClass( "after-portlet-$name" ),
],
],
$this->htmlAfterContent
);
}
if ( !$isEmptyBeforeContent ) {
$data['html-before-portal'] = Html::rawElement(
'div',
[
'class' => [
'before-portlet',
Sanitizer::escapeClass( "before-portlet-$name" ),
],
],
$this->htmlBeforeContent
);
}
$html = '';
$arrayItems = [];
foreach ( $this->items as $key => $item ) {
$item = new SkinComponentListItem( $key, $item, $this->localizer, [], $this->linkOptions );
$itemData = $item->getTemplateData();
$html .= $itemData['html-item'];
$arrayItems[] = $itemData;
}
$data['html-items'] = $html;
$data['array-items'] = $arrayItems;
$data['label'] = $this->getMenuLabel( $name );
$data['class'] .= $isEmptyPortlet ? ' emptyPortlet' : '';
return $data;
}
}