diff --git a/extension.json b/extension.json
index db32684..5d6923c 100644
--- a/extension.json
+++ b/extension.json
@@ -99,6 +99,15 @@
"mobile"
]
},
+ "ext.isekai.information.infobox": {
+ "styles": [
+ "information/ext.isekai.information.infobox.less"
+ ],
+ "targets": [
+ "desktop",
+ "mobile"
+ ]
+ },
"ext.isekai.previewCard": {
"scripts": [
"previewCard/ext.isekai.previewCard.js"
diff --git a/i18n/en.json b/i18n/en.json
index f5c879c..8a8d230 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -24,6 +24,6 @@
"isekai-font-error-invalid-params": "Please specify name attributes.",
"isekai-font-error-font-name-invalid": "Font name cannot contain special characters.",
"isekai-font-error-font-not-imported": "Font \"$1\" not imported.",
-
+ "isekai-information-title-base-information": "Base Data",
"isekai-information-error-invalid-type": "Information \"type\" unsupported."
}
\ No newline at end of file
diff --git a/i18n/zh-hans.json b/i18n/zh-hans.json
index ec19021..45e5047 100644
--- a/i18n/zh-hans.json
+++ b/i18n/zh-hans.json
@@ -27,5 +27,6 @@
"isekai-font-error-font-name-invalid": "字体名中不能包含特殊字符。",
"isekai-font-error-font-not-imported": "未导入字体: \"$1\"。",
+ "isekai-information-title-base-information": "基本资料",
"isekai-information-error-invalid-type": "提供的信息框类型错误"
}
\ No newline at end of file
diff --git a/i18n/zh-hant.json b/i18n/zh-hant.json
index 9cb438f..1ca06eb 100644
--- a/i18n/zh-hant.json
+++ b/i18n/zh-hant.json
@@ -25,5 +25,6 @@
"isekai-font-error-font-name-invalid": "字體名中不能包含特殊字元。",
"isekai-font-error-font-not-imported": "未導入字體: \"$1\"。",
+ "isekai-information-title-base-information": "基本資料",
"isekai-information-error-invalid-type": "提供的信息框類型錯誤"
}
\ No newline at end of file
diff --git a/includes/InformationWidget.php b/includes/InformationWidget.php
index bdfb34f..eb6b4e9 100644
--- a/includes/InformationWidget.php
+++ b/includes/InformationWidget.php
@@ -1,12 +1,13 @@
$line) {
@@ -19,8 +20,8 @@ class InformationWidget {
'label' => $key,
'text' => $value,
];
- $prevData = &$data;
- $finalData[] = &$data;
+ $finalData[] = $data;
+ $prevDataKey = count($finalData) - 1;
continue;
}
@@ -28,6 +29,9 @@ class InformationWidget {
$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',
@@ -41,16 +45,18 @@ class InformationWidget {
'text' => '#' . $value,
];
}
- $prevData = &$data;
- $finalData[] = &$data;
+ $finalData[] = $data;
+ $prevDataKey = count($finalData) - 1;
continue;
}
// 多行数据,附加到上一行
- if (preg_match('/^[ \t]+/', $line) && $prevData && isset($prevData['text'])) {
- $prevData['text'] .= "\n\n" . trim($line);
+ /* 暂时仅支持
+ if (preg_match('/^[ \t]+/', $line) && $prevDataKey !== null) {
+ $finalData[$prevDataKey]['text'] .= "\n\n" . trim($line);
continue;
}
+ */
if ($lineNum === 0) {
$title = trim($line);
@@ -62,38 +68,99 @@ class InformationWidget {
'type' => 'banner',
'text' => trim($line)
];
- $prevData = &$data;
- $finalData[] = &$data;
+ $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) {
- $config = MediaWikiServices::getInstance()->getConfigFactory()->makeConfig('IsekaiWidget');
- $sep = $config->get('IsekaiWidgetInformationTextSeparator');
+ global $wgIsekaiWidgetInformationTextSeparator;
+ $sep = $wgIsekaiWidgetInformationTextSeparator;
- $stringBuilder = [];
+ $lines = [];
foreach ($dataMap as $information) {
if ($information['type'] === 'pair') {
- $stringBuilder[] = $information['label'] . $sep .
- Utils::makeParagraph($information['text'], false, true);
+ $lines[] = $information['label'] . $sep . $information['text'];
}
}
- return [implode('', $stringBuilder), 'markerType' => 'nowiki'];
+ $html = implode("\n\n", $lines);
+ $html = str_replace("\n", "\r\n", $html);
+ $html = $parser->recursiveTagParseFully($html, $frame);
+ return [$html, 'markerType' => 'nowiki'];
}
- public static function buildTable(\Parser $parser, \PPFrame $frame, array $dataMap, $title, $picture, $float) {
+ 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
- * @param $args
* @return array|string
*/
- public static function create(\Parser $parser, \PPFrame $frame, $args) {
- $configKeys = ['type', 'float', 'content', 'title_key', 'picture'];
+ public static function create(string $content, array $args, \Parser $parser, \PPFrame $frame) {
+ $configKeys = ['type', 'float', 'title_key', 'picture'];
$configArgs = [];
$infoArgs = [];
@@ -105,16 +172,21 @@ class InformationWidget {
}
}
- $type = $configArgs['type'] ?? 'text';
+ $type = strtolower($configArgs['type']) ?? 'text';
$picture = $configArgs['picture'] ?? null;
$float = $configArgs['float'] ?? '';
$titleKey = $configArgs['title_key'] ?? null;
$title = null;
- // 文本模式中,没有title
if ($type === 'text') {
+ // 文本模式中,没有title
$titleKey = null;
+ } else if ($type === 'infobox') {
+ // 信息框默认居右
+ if ($float === '') {
+ $float = 'right';
+ }
}
$dataMap = [];
@@ -126,13 +198,23 @@ class InformationWidget {
$dataMap[$key] = $value;
}
}
- if (isset($configArgs['content'])) {
- list($dataMap, $title) = static::parseContent($configArgs['content'], $dataMap, $title);
+ 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 '' . wfMessage('isekai-information-error-invalid-type')->parse() . '';
}
diff --git a/includes/Widgets.php b/includes/Widgets.php
index 5cd102a..8e10a8c 100644
--- a/includes/Widgets.php
+++ b/includes/Widgets.php
@@ -27,7 +27,7 @@ class Widgets {
$parser->setHook('details', [Html5Widget::class, 'createDetails']);
$parser->setHook('summary', [Html5Widget::class, 'createSummary']);
- $parser->setFunctionHook('information', [InformationWidget::class, 'create'], SFH_OBJECT_ARGS);
+ $parser->setHook('information', [InformationWidget::class, 'create']);
return true;
}
@@ -35,6 +35,7 @@ class Widgets {
public static function onLoad(\OutputPage $outputPage) {
$outputPage->addModuleStyles([
"ext.isekai.widgets.global",
+ "ext.isekai.information.infobox",
"ext.isekai.collapse"
]);
}
diff --git a/modules/information/ext.isekai.information.infobox.less b/modules/information/ext.isekai.information.infobox.less
new file mode 100644
index 0000000..513fe6f
--- /dev/null
+++ b/modules/information/ext.isekai.information.infobox.less
@@ -0,0 +1,52 @@
+.infobox {
+ @media (max-width: 767px) {
+ width: 100%;
+ }
+
+ @media (min-width: 768px) {
+ &.infobox-float-left {
+ float: left;
+ }
+ &.infobox-float-right {
+ float: right;
+ }
+ }
+
+ .infobox-title {
+ color: #fff;
+ background-color: #404244;
+
+ ruby {
+ display: inline-flex;
+ flex-direction: column-reverse;
+ }
+
+ rb, rt {
+ display: inline;
+ line-height: 1;
+ }
+ }
+
+ .infobox-picture {
+ text-align: center;
+
+ img {
+ max-width: 100%;
+ max-height: 350px;
+ }
+ }
+
+ .infobox-banner {
+ text-align: center;
+ color: #000;
+ font-weight: bold;
+ background-color: #eaecf0;
+ }
+
+ @media (prefers-color-scheme: dark) {
+ .infobox-banner {
+ color: #fff;
+ background-color: #202122;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/tile/style.less b/modules/tile/style.less
index 8f4bd23..0c0920f 100644
--- a/modules/tile/style.less
+++ b/modules/tile/style.less
@@ -5,6 +5,10 @@ a {
&.tile-large,
&.tile-app {
color: #fff;
+
+ &:visited:hover {
+ color: #fff;
+ }
}
}