2021-12-23 09:10:28 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace MediaWiki\Extension\TemplateData;
|
|
|
|
|
2024-01-04 20:53:10 +00:00
|
|
|
use MediaWiki\Html\Html;
|
2022-08-31 13:31:48 +00:00
|
|
|
use MediaWiki\Logger\LoggerFactory;
|
|
|
|
use MediaWiki\MediaWikiServices;
|
2023-08-19 04:19:39 +00:00
|
|
|
use MediaWiki\Title\Title;
|
2022-01-03 17:37:15 +00:00
|
|
|
use MessageLocalizer;
|
2022-02-03 10:30:21 +00:00
|
|
|
use stdClass;
|
2021-12-23 09:10:28 +00:00
|
|
|
|
2023-08-23 07:29:25 +00:00
|
|
|
/**
|
|
|
|
* @license GPL-2.0-or-later
|
|
|
|
*/
|
2021-12-23 09:10:28 +00:00
|
|
|
class TemplateDataHtmlFormatter {
|
|
|
|
|
2023-08-23 07:29:25 +00:00
|
|
|
private MessageLocalizer $localizer;
|
|
|
|
private string $languageCode;
|
2022-01-03 17:37:15 +00:00
|
|
|
|
2022-02-03 08:31:50 +00:00
|
|
|
public function __construct( MessageLocalizer $localizer, string $languageCode = 'en' ) {
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer = $localizer;
|
2022-02-03 08:31:50 +00:00
|
|
|
$this->languageCode = $languageCode;
|
2022-01-03 17:37:15 +00:00
|
|
|
}
|
|
|
|
|
2021-12-23 09:10:28 +00:00
|
|
|
/**
|
2022-02-03 08:31:50 +00:00
|
|
|
* @param TemplateDataBlob $templateData
|
2022-08-31 13:31:48 +00:00
|
|
|
* @param Title $frameTitle
|
|
|
|
* @param bool $showEditLink
|
2021-12-23 09:10:28 +00:00
|
|
|
*
|
2022-02-03 08:31:50 +00:00
|
|
|
* @return string HTML
|
2021-12-23 09:10:28 +00:00
|
|
|
*/
|
2022-08-31 13:31:48 +00:00
|
|
|
public function getHtml( TemplateDataBlob $templateData, Title $frameTitle, bool $showEditLink = true ): string {
|
2022-02-03 08:31:50 +00:00
|
|
|
$data = $templateData->getDataInLanguage( $this->languageCode );
|
|
|
|
|
2022-04-06 16:40:50 +00:00
|
|
|
$icon = null;
|
|
|
|
$formatMsg = null;
|
|
|
|
if ( isset( $data->format ) && is_string( $data->format ) ) {
|
|
|
|
$format = $data->format;
|
|
|
|
'@phan-var string $format';
|
|
|
|
if ( isset( TemplateDataValidator::PREDEFINED_FORMATS[$format] ) ) {
|
|
|
|
// The following icon names are used here:
|
|
|
|
// * template-format-block
|
|
|
|
// * template-format-inline
|
|
|
|
$icon = 'template-format-' . $format;
|
|
|
|
// Messages that can be used here:
|
|
|
|
// * templatedata-doc-format-block
|
|
|
|
// * templatedata-doc-format-inline
|
|
|
|
$formatMsg = $this->localizer->msg( 'templatedata-doc-format-' . $format );
|
|
|
|
}
|
|
|
|
if ( !$formatMsg || $formatMsg->isDisabled() ) {
|
|
|
|
$icon = 'settings';
|
|
|
|
$formatMsg = $this->localizer->msg( 'templatedata-doc-format-custom' );
|
|
|
|
}
|
2021-12-23 09:10:28 +00:00
|
|
|
}
|
2022-04-06 16:40:50 +00:00
|
|
|
|
2023-08-23 07:29:25 +00:00
|
|
|
$sorting = count( (array)$data->params ) > 1 ? ' sortable' : '';
|
2021-12-23 09:10:28 +00:00
|
|
|
$html = '<header>'
|
|
|
|
. Html::element( 'p',
|
|
|
|
[
|
|
|
|
'class' => [
|
|
|
|
'mw-templatedata-doc-desc',
|
|
|
|
'mw-templatedata-doc-muted' => $data->description === null,
|
|
|
|
]
|
|
|
|
],
|
|
|
|
$data->description ??
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-desc-empty' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. '</header>'
|
|
|
|
. '<table class="wikitable mw-templatedata-doc-params' . $sorting . '">'
|
|
|
|
. Html::rawElement( 'caption', [],
|
2023-06-21 16:43:39 +00:00
|
|
|
Html::rawElement( 'p',
|
2022-08-31 13:31:48 +00:00
|
|
|
[ 'class' => 'mw-templatedata-caption' ],
|
2023-06-21 16:43:39 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-params' )->escaped() .
|
|
|
|
// Edit interface is only loaded in the template namespace (see Hooks::onEditPage)
|
|
|
|
( $showEditLink && $frameTitle->inNamespace( NS_TEMPLATE ) ?
|
|
|
|
Html::element( 'mw:edittemplatedata', [
|
|
|
|
'page' => $frameTitle->getPrefixedText()
|
|
|
|
] ) :
|
|
|
|
''
|
|
|
|
)
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
2022-04-06 16:40:50 +00:00
|
|
|
. ( $formatMsg ?
|
2021-12-23 09:10:28 +00:00
|
|
|
Html::rawElement( 'p', [],
|
|
|
|
new \OOUI\IconWidget( [ 'icon' => $icon ] )
|
|
|
|
. Html::element(
|
|
|
|
'span',
|
|
|
|
[ 'class' => 'mw-templatedata-format' ],
|
2022-04-06 16:40:50 +00:00
|
|
|
$formatMsg->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
) :
|
|
|
|
''
|
|
|
|
)
|
|
|
|
)
|
|
|
|
. '<thead><tr>'
|
|
|
|
. Html::element( 'th', [ 'colspan' => 2 ],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-name' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. Html::element( 'th', [],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-desc' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. Html::element( 'th', [],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-type' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. Html::element( 'th', [],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-status' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. '</tr></thead>'
|
|
|
|
. '<tbody>';
|
|
|
|
|
2022-02-03 10:30:21 +00:00
|
|
|
$paramNames = $data->paramOrder ?? array_keys( (array)$data->params );
|
|
|
|
if ( !$paramNames ) {
|
2021-12-23 09:10:28 +00:00
|
|
|
// Display no parameters message
|
|
|
|
$html .= '<tr>'
|
|
|
|
. Html::element( 'td',
|
|
|
|
[
|
|
|
|
'class' => 'mw-templatedata-doc-muted',
|
|
|
|
'colspan' => 7
|
|
|
|
],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-no-params-set' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. '</tr>';
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ( $paramNames as $paramName ) {
|
2022-02-03 10:30:21 +00:00
|
|
|
$html .= $this->formatParameterTableRow( $paramName, $data->params->$paramName );
|
|
|
|
}
|
|
|
|
$html .= '</tbody></table>';
|
2021-12-23 09:10:28 +00:00
|
|
|
|
2022-02-03 10:30:21 +00:00
|
|
|
return Html::rawElement( 'section', [ 'class' => 'mw-templatedata-doc-wrap' ], $html );
|
|
|
|
}
|
|
|
|
|
2022-08-31 13:31:48 +00:00
|
|
|
/**
|
|
|
|
* Replace <mw:edittemplatedata> markers with links
|
|
|
|
*
|
|
|
|
* @param string &$text
|
|
|
|
*/
|
2023-08-23 07:29:25 +00:00
|
|
|
public function replaceEditLink( string &$text ): void {
|
2022-08-31 13:31:48 +00:00
|
|
|
$localizer = $this->localizer;
|
|
|
|
$text = preg_replace_callback(
|
|
|
|
// Based on EDITSECTION_REGEX in ParserOutput
|
|
|
|
'#<mw:edittemplatedata page="(.*?)"></mw:edittemplatedata>#s',
|
2023-08-23 07:29:25 +00:00
|
|
|
static function ( array $m ) use ( $localizer ): string {
|
2022-08-31 13:31:48 +00:00
|
|
|
$editsectionPage = Title::newFromText( htmlspecialchars_decode( $m[1] ) );
|
|
|
|
|
|
|
|
if ( !is_object( $editsectionPage ) ) {
|
|
|
|
LoggerFactory::getInstance( 'Parser' )
|
|
|
|
->error(
|
|
|
|
'TemplateDataHtmlFormatter::replaceEditLink(): bad title in edittemplatedata placeholder',
|
|
|
|
[
|
|
|
|
'placeholder' => $m[0],
|
|
|
|
'editsectionPage' => $m[1],
|
|
|
|
]
|
|
|
|
);
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
$result = Html::openElement( 'span', [ 'class' => 'mw-editsection-like' ] );
|
|
|
|
$result .= Html::rawElement( 'span', [ 'class' => 'mw-editsection-bracket' ], '[' );
|
|
|
|
|
|
|
|
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
|
|
|
|
$result .= $linkRenderer->makeKnownLink(
|
|
|
|
$editsectionPage,
|
|
|
|
$localizer->msg( 'templatedata-editbutton' )->text(),
|
|
|
|
[],
|
|
|
|
[
|
|
|
|
'action' => 'edit',
|
|
|
|
'templatedata' => 'edit',
|
|
|
|
]
|
|
|
|
);
|
|
|
|
|
|
|
|
$result .= Html::rawElement( 'span', [ 'class' => 'mw-editsection-bracket' ], ']' );
|
|
|
|
$result .= Html::closeElement( 'span' );
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
},
|
|
|
|
$text
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-02-03 10:30:21 +00:00
|
|
|
/**
|
|
|
|
* @param int|string $paramName
|
|
|
|
* @param stdClass $param
|
|
|
|
*
|
|
|
|
* @return string HTML
|
|
|
|
*/
|
|
|
|
private function formatParameterTableRow( $paramName, stdClass $param ): string {
|
|
|
|
'@phan-var object $param';
|
|
|
|
|
|
|
|
$allParamNames = [ Html::element( 'code', [], $paramName ) ];
|
|
|
|
foreach ( $param->aliases as $alias ) {
|
|
|
|
$allParamNames[] = Html::element( 'code', [ 'class' => 'mw-templatedata-doc-param-alias' ],
|
|
|
|
$alias
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$suggestedValues = [];
|
|
|
|
foreach ( $param->suggestedvalues as $suggestedValue ) {
|
2022-08-08 09:01:35 +00:00
|
|
|
$suggestedValues[] = Html::element( 'code', [], $suggestedValue );
|
2022-02-03 10:30:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( $param->deprecated ) {
|
|
|
|
$status = 'deprecated';
|
|
|
|
} elseif ( $param->required ) {
|
|
|
|
$status = 'required';
|
|
|
|
} elseif ( $param->suggested ) {
|
|
|
|
$status = 'suggested';
|
|
|
|
} else {
|
|
|
|
$status = 'optional';
|
|
|
|
}
|
|
|
|
|
|
|
|
return '<tr>'
|
2021-12-23 09:10:28 +00:00
|
|
|
// Label
|
2022-02-01 14:21:34 +00:00
|
|
|
. Html::element( 'th', [], $param->label ?? $paramName )
|
2021-12-23 09:10:28 +00:00
|
|
|
// Parameters and aliases
|
|
|
|
. Html::rawElement( 'td', [ 'class' => 'mw-templatedata-doc-param-name' ],
|
2023-06-25 14:53:54 +00:00
|
|
|
implode( ' ', $allParamNames )
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
// Description
|
2022-08-08 09:01:35 +00:00
|
|
|
. Html::rawElement( 'td', [],
|
|
|
|
Html::element( 'p',
|
|
|
|
[
|
|
|
|
'class' => $param->description ? null : 'mw-templatedata-doc-muted',
|
|
|
|
],
|
2022-02-01 14:21:34 +00:00
|
|
|
$param->description ??
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-desc-empty' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. Html::rawElement( 'dl', [],
|
|
|
|
// Suggested Values
|
2022-02-03 10:30:21 +00:00
|
|
|
( $suggestedValues ? ( Html::element( 'dt', [],
|
|
|
|
$this->localizer->msg( 'templatedata-doc-param-suggestedvalues' )->text()
|
|
|
|
)
|
|
|
|
. Html::rawElement( 'dd', [],
|
2023-06-25 14:53:54 +00:00
|
|
|
implode( ' ', $suggestedValues )
|
2022-02-03 10:30:21 +00:00
|
|
|
) ) : '' ) .
|
2021-12-23 09:10:28 +00:00
|
|
|
// Default
|
2022-02-01 14:21:34 +00:00
|
|
|
( $param->default !== null ? ( Html::element( 'dt', [],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-default' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. Html::element( 'dd', [],
|
2022-02-01 14:21:34 +00:00
|
|
|
$param->default
|
2021-12-23 09:10:28 +00:00
|
|
|
) ) : '' )
|
|
|
|
// Example
|
2022-02-01 14:21:34 +00:00
|
|
|
. ( $param->example !== null ? ( Html::element( 'dt', [],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-example' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. Html::element( 'dd', [],
|
2022-02-01 14:21:34 +00:00
|
|
|
$param->example
|
2021-12-23 09:10:28 +00:00
|
|
|
) ) : '' )
|
|
|
|
// Auto value
|
2022-02-01 14:21:34 +00:00
|
|
|
. ( $param->autovalue !== null ? ( Html::element( 'dt', [],
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-autovalue' )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. Html::rawElement( 'dd', [],
|
2022-02-01 14:21:34 +00:00
|
|
|
Html::element( 'code', [], $param->autovalue )
|
2021-12-23 09:10:28 +00:00
|
|
|
) ) : '' )
|
|
|
|
)
|
|
|
|
)
|
|
|
|
// Type
|
|
|
|
. Html::element( 'td',
|
|
|
|
[
|
|
|
|
'class' => [
|
|
|
|
'mw-templatedata-doc-param-type',
|
2022-02-01 14:21:34 +00:00
|
|
|
'mw-templatedata-doc-muted' => $param->type === 'unknown'
|
2021-12-23 09:10:28 +00:00
|
|
|
]
|
|
|
|
],
|
|
|
|
// Known messages, for grepping:
|
|
|
|
// templatedata-doc-param-type-boolean, templatedata-doc-param-type-content,
|
|
|
|
// templatedata-doc-param-type-date, templatedata-doc-param-type-line,
|
|
|
|
// templatedata-doc-param-type-number, templatedata-doc-param-type-string,
|
|
|
|
// templatedata-doc-param-type-unbalanced-wikitext, templatedata-doc-param-type-unknown,
|
|
|
|
// templatedata-doc-param-type-url, templatedata-doc-param-type-wiki-file-name,
|
|
|
|
// templatedata-doc-param-type-wiki-page-name, templatedata-doc-param-type-wiki-template-name,
|
|
|
|
// templatedata-doc-param-type-wiki-user-name
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( 'templatedata-doc-param-type-' . $param->type )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
// Status
|
|
|
|
. Html::element( 'td',
|
|
|
|
[
|
|
|
|
// CSS class names that can be used here:
|
|
|
|
// mw-templatedata-doc-param-status-deprecated
|
|
|
|
// mw-templatedata-doc-param-status-optional
|
|
|
|
// mw-templatedata-doc-param-status-required
|
|
|
|
// mw-templatedata-doc-param-status-suggested
|
|
|
|
'class' => "mw-templatedata-doc-param-status-$status",
|
|
|
|
'data-sort-value' => [
|
|
|
|
'deprecated' => -1,
|
|
|
|
'suggested' => 1,
|
|
|
|
'required' => 2,
|
|
|
|
][$status] ?? 0,
|
|
|
|
],
|
|
|
|
// Messages that can be used here:
|
|
|
|
// templatedata-doc-param-status-deprecated
|
|
|
|
// templatedata-doc-param-status-optional
|
|
|
|
// templatedata-doc-param-status-required
|
|
|
|
// templatedata-doc-param-status-suggested
|
2022-01-03 17:37:15 +00:00
|
|
|
$this->localizer->msg( "templatedata-doc-param-status-$status" )->text()
|
2021-12-23 09:10:28 +00:00
|
|
|
)
|
|
|
|
. '</tr>';
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|