|
|
<?php
|
|
|
namespace Isekai\Widgets;
|
|
|
|
|
|
use Html;
|
|
|
use MediaWiki\MediaWikiServices;
|
|
|
|
|
|
class InformationWidget {
|
|
|
public static function parseContent($content, $dataMap, $title) {
|
|
|
$lines = explode("\n", str_replace("\r\n", "\n", $content));
|
|
|
$prevDataKey = null;
|
|
|
|
|
|
$finalData = [];
|
|
|
foreach ($lines as $lineNum => $line) {
|
|
|
// 静态文本数据
|
|
|
$sep = Utils::strContains($line, [':', ':']);
|
|
|
if ($sep) {
|
|
|
list($key, $value) = Utils::getKeyValue($sep, $line);
|
|
|
$data = [
|
|
|
'type' => 'pair',
|
|
|
'label' => $key,
|
|
|
'text' => $value,
|
|
|
];
|
|
|
$finalData[] = $data;
|
|
|
$prevDataKey = count($finalData) - 1;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 动态文本数据
|
|
|
$sep = Utils::strContains($line, ['=']);
|
|
|
if ($sep) {
|
|
|
list($key, $value) = Utils::getKeyValue($sep, $line);
|
|
|
if ($key === '') { // While text is '= key'
|
|
|
$key = $value;
|
|
|
}
|
|
|
if (isset($dataMap[$value])) {
|
|
|
$data = [
|
|
|
'type' => 'pair',
|
|
|
'label' => $key,
|
|
|
'text' => $dataMap[$value],
|
|
|
];
|
|
|
} else {
|
|
|
$data = [
|
|
|
'type' => 'pair',
|
|
|
'label' => $key,
|
|
|
'text' => '#' . $value,
|
|
|
];
|
|
|
}
|
|
|
$finalData[] = $data;
|
|
|
$prevDataKey = count($finalData) - 1;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 多行数据,附加到上一行
|
|
|
/* 暂时仅支持<br>
|
|
|
if (preg_match('/^[ \t]+/', $line) && $prevDataKey !== null) {
|
|
|
$finalData[$prevDataKey]['text'] .= "\n\n" . trim($line);
|
|
|
continue;
|
|
|
}
|
|
|
*/
|
|
|
|
|
|
if ($lineNum === 0) {
|
|
|
$title = trim($line);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 归类为分栏数据
|
|
|
$data = [
|
|
|
'type' => 'banner',
|
|
|
'text' => trim($line)
|
|
|
];
|
|
|
$finalData[] = $data;
|
|
|
$prevDataKey = count($finalData) - 1;
|
|
|
}
|
|
|
return [$finalData, $title];
|
|
|
}
|
|
|
|
|
|
public static function parseMap($dataMap) {
|
|
|
$finalData = [];
|
|
|
foreach ($dataMap as $key => $value) {
|
|
|
$finalData[] = [
|
|
|
'type' => 'pair',
|
|
|
'label' => $key,
|
|
|
'text' => $value
|
|
|
];
|
|
|
}
|
|
|
return $finalData;
|
|
|
}
|
|
|
|
|
|
public static function buildText(\Parser $parser, \PPFrame $frame, array $dataMap, $title, $picture, $float) {
|
|
|
global $wgIsekaiWidgetInformationTextSeparator;
|
|
|
$sep = $wgIsekaiWidgetInformationTextSeparator;
|
|
|
|
|
|
$lines = [];
|
|
|
foreach ($dataMap as $information) {
|
|
|
if ($information['type'] === 'pair') {
|
|
|
$lines[] = $information['label'] . $sep . $information['text'];
|
|
|
}
|
|
|
}
|
|
|
$html = implode("\n\n", $lines);
|
|
|
$html = str_replace("\n", "\r\n", $html);
|
|
|
$html = $parser->recursiveTagParseFully($html, $frame);
|
|
|
return [$html, 'markerType' => 'nowiki'];
|
|
|
}
|
|
|
|
|
|
public static function buildInfoBox(\Parser $parser, \PPFrame $frame, array $dataMap, $title, $picture, $float) {
|
|
|
$parser->getOutput()->addModules(['ext.isekai.information.infobox']);
|
|
|
|
|
|
$tableClasses = ['wikitable-container', 'infobox'];
|
|
|
if ($float === 'right') {
|
|
|
$tableClasses[] = 'infobox-float-right';
|
|
|
} else if ($float === 'left') {
|
|
|
$tableClasses[] = 'infobox-float-left';
|
|
|
}
|
|
|
$htmlBuilder = [
|
|
|
Html::openElement('div', [
|
|
|
'class' => implode(' ', $tableClasses)
|
|
|
]) . Html::openElement('table', [
|
|
|
'class' => 'wikitable'
|
|
|
])
|
|
|
];
|
|
|
if (is_string($title) && $title !== '') {
|
|
|
$htmlBuilder[] = Html::rawElement('thead', [],
|
|
|
Html::rawElement('th', ['colspan' => 2, 'class' => 'infobox-title'],
|
|
|
$parser->recursiveTagParse($title, $frame)
|
|
|
)
|
|
|
);
|
|
|
}
|
|
|
$htmlBuilder[] = Html::openElement('tbody');
|
|
|
if (is_string($picture) && $picture !== '') {
|
|
|
$htmlBuilder[] = Html::rawElement('tr', [],
|
|
|
Html::rawElement('td', ['colspan' => 2, 'class' => 'infobox-picture'], $parser->recursiveTagParse("[[$picture|frameless]]", $frame))
|
|
|
);
|
|
|
}
|
|
|
foreach ($dataMap as $information) {
|
|
|
switch ($information['type']) {
|
|
|
case 'pair':
|
|
|
$htmlBuilder[] = Html::rawElement('tr', [],
|
|
|
Html::rawElement('td', [], $parser->recursiveTagParse($information['label'], $frame)) .
|
|
|
Html::rawElement('td', ['style' => 'text-align:center'], $parser->recursiveTagParse($information['text'], $frame))
|
|
|
);
|
|
|
break;
|
|
|
case 'banner':
|
|
|
$htmlBuilder[] = Html::rawElement('tr', [],
|
|
|
Html::rawElement('td', ['colspan' => 2, 'class' => 'infobox-banner'], $parser->recursiveTagParse($information['text'], $frame))
|
|
|
);
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
}
|
|
|
$htmlBuilder[] = Html::closeElement('tbody') . Html::closeElement('table') . Html::closeElement('div');
|
|
|
$html = implode('', $htmlBuilder);
|
|
|
return [$html, 'markerType' => 'nowiki'];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param string $content
|
|
|
* @param array $args
|
|
|
* @param \Parser $parser
|
|
|
* @param \PPFrame $frame
|
|
|
* @return array|string
|
|
|
*/
|
|
|
public static function create(string $content, array $args, \Parser $parser, \PPFrame $frame) {
|
|
|
$configKeys = ['type', 'float', 'title_key', 'picture'];
|
|
|
$configArgs = [];
|
|
|
$infoArgs = [];
|
|
|
|
|
|
foreach ($args as $key => $value) {
|
|
|
if (in_array($key, $configKeys)) {
|
|
|
$configArgs[$key] = $value;
|
|
|
} else {
|
|
|
$infoArgs[$key] = $value;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
$type = strtolower($configArgs['type']) ?? 'text';
|
|
|
$picture = $configArgs['picture'] ?? null;
|
|
|
$float = $configArgs['float'] ?? '';
|
|
|
|
|
|
$titleKey = $configArgs['title_key'] ?? null;
|
|
|
$title = null;
|
|
|
|
|
|
if ($type === 'text') {
|
|
|
// 文本模式中,没有title
|
|
|
$titleKey = null;
|
|
|
} else if ($type === 'infobox') {
|
|
|
// 信息框默认居右
|
|
|
if ($float === '') {
|
|
|
$float = 'right';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
$dataMap = [];
|
|
|
foreach ($infoArgs as $key => $value) {
|
|
|
if ((is_int($key) && !$titleKey) || ($titleKey && $key === $titleKey)) {
|
|
|
$title = $value;
|
|
|
unset($dataMap[$key]);
|
|
|
} else {
|
|
|
$dataMap[$key] = $value;
|
|
|
}
|
|
|
}
|
|
|
if (trim($content) !== '') {
|
|
|
list($dataMap, $title) = static::parseContent($content, $dataMap, $title);
|
|
|
} else {
|
|
|
$dataMap = static::parseMap($dataMap);
|
|
|
if ($type === 'infobox') {
|
|
|
array_unshift($dataMap, [
|
|
|
'type' => 'banner',
|
|
|
'text' => wfMessage('isekai-information-title-base-information')->parse()
|
|
|
]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
switch ($type) {
|
|
|
case 'text':
|
|
|
return static::buildText($parser, $frame, $dataMap, $title, $picture, $float);
|
|
|
case 'infobox':
|
|
|
return static::buildInfoBox($parser, $frame, $dataMap, $title, $picture, $float);
|
|
|
default:
|
|
|
return '<span class="error">' . wfMessage('isekai-information-error-invalid-type')->parse() . '</span>';
|
|
|
}
|
|
|
}
|
|
|
} |