You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
7.1 KiB
PHP
217 lines
7.1 KiB
PHP
<?php
|
|
namespace Isekai\Widgets;
|
|
|
|
use Html;
|
|
use MediaWiki\MediaWikiServices;
|
|
use Title;
|
|
|
|
class TileWidget {
|
|
private $size = 'medium';
|
|
private $icon = false;
|
|
private $title = '';
|
|
private $href = '';
|
|
private $badge = false;
|
|
private $color = false;
|
|
private $cover = false;
|
|
private $images = [];
|
|
private $grid = false;
|
|
|
|
private $attributes = [];
|
|
|
|
public function __construct($args, $content){
|
|
$this->content = $content;
|
|
$this->parseArgs($args);
|
|
}
|
|
|
|
public static function create(string $text, array $args, \Parser $parser, \PPFrame $frame){
|
|
$parser->getOutput()->addModules(['ext.isekai.tile']);
|
|
|
|
$content = '';
|
|
if ($text) {
|
|
$content = $frame->expand($text);
|
|
|
|
$title = preg_replace('/\[\[.*?\]\]/', '', $content);
|
|
$title = preg_replace('/<img .*?src="(?<src>.*?)".*?srcset="(?<srcset>.*?)"[^\>]+>/', '', $title);
|
|
$title = strip_tags(trim($title));
|
|
$args['title'] = $title;
|
|
}
|
|
|
|
$tile = new TileWidget($args, $content);
|
|
return [$tile->toHtml(), 'markerType' => 'nowiki'];
|
|
}
|
|
|
|
private function parseArgs($args){
|
|
$allowedArgs = ['size', 'icon', 'title', 'cover', 'badge', 'color', 'href', 'grid'];
|
|
|
|
foreach($args as $name => $arg){
|
|
if(in_array($name, $allowedArgs)){
|
|
$this->$name = $arg;
|
|
} elseif(substr($name, 0, 2) !== 'on'){
|
|
$this->attributes[$name] = $arg;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getSizeArgs(array &$element, array &$content){
|
|
$element['data-size'] = $this->size;
|
|
$element['class'][] = 'tile-' . $this->size;
|
|
}
|
|
|
|
private function getColorArgs(array &$element, array &$content){
|
|
if($this->color){
|
|
if(substr($this->color, 0, 1) == '#' || substr($this->color, 0, 3) == 'rgb'){
|
|
$element['style'][] = 'background-color: ' . $this->color;
|
|
} else {
|
|
$color = str_replace($this->color, 'bg-', '');
|
|
$element['class'][] = 'bg-' . $color;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getTitleArgs(array &$element, array &$content){
|
|
if(!empty($this->title)){
|
|
$content[] = Html::element('span', [
|
|
'class' => ['branding-bar'],
|
|
], $this->title);
|
|
$element['data-title'] = $this->title;
|
|
}
|
|
}
|
|
|
|
private function getCoverArgs(array &$element, array &$content){
|
|
$element['data-cover'] = $this->cover;
|
|
}
|
|
|
|
private function getHrefArgs(array &$element, array &$content){
|
|
if(substr($this->href, 0, 2) == '[[' && substr($this->href, -2, 2) == ']]'){ //内部链接
|
|
$titleText = substr($this->href, 2, strlen($this->href) - 4);
|
|
$title = Title::newFromText($titleText);
|
|
$href = $title->getLocalURL();
|
|
} else {
|
|
$href = $this->href;
|
|
}
|
|
$element['href'] = $href;
|
|
}
|
|
|
|
private function getIconArgs(array &$element, array &$content){
|
|
if($this->icon){
|
|
if(is_string($this->icon)){
|
|
if(preg_match('/\.[a-zA-Z0-9]{3,4}$/', $this->icon)){
|
|
//图片图标
|
|
$iconSrc = $this->icon;
|
|
$type = 'image';
|
|
} else {
|
|
$iconSrc = explode(' ', $this->icon);
|
|
$type = 'class';
|
|
}
|
|
} else {
|
|
$type = 'class';
|
|
$iconSrc = $this->icon;
|
|
}
|
|
|
|
if($type == 'class'){
|
|
$content[] = Html::element('span', [
|
|
'class' => array_merge($iconSrc, ['icon']),
|
|
]);
|
|
} elseif($type == 'image'){
|
|
$content[] = Html::element('img', [
|
|
'src' => $iconSrc,
|
|
'class' => ['icon'],
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getBadgeArgs(array &$element, array &$content){
|
|
if($this->badge){
|
|
$content[] = Html::element('span', [
|
|
'class' => ['badge-bottom'],
|
|
], strval($this->badge));
|
|
}
|
|
}
|
|
|
|
private function getImagesArgs(array &$element, array &$content){
|
|
$service = MediaWikiServices::getInstance();
|
|
$this->images = [];
|
|
// 提取wikitext图片
|
|
preg_match_all('/\[\[(?<title>.+?:.+?)(\|.*?)?\]\]/', $this->content, $matches);
|
|
if (isset($matches['title']) && !empty($matches['title'])) {
|
|
foreach ($matches['title'] as $titleText) {
|
|
$title = Title::newFromText($titleText);
|
|
if ($title->inNamespace(NS_FILE)) {
|
|
$file = $service->getRepoGroup()->findFile($title);
|
|
$thumb = $file->getUrl();
|
|
$this->images[] = $thumb;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 提取html图片
|
|
preg_match_all('/<img .*?src="(?<src>.*?)".*?srcset="(?<srcset>.*?)"[^\>]+>/', $this->content, $matches);
|
|
if (isset($matches['src']) && !empty($matches['src'])) {
|
|
$this->images = array_merge($this->images, $matches['src']);
|
|
}
|
|
|
|
if(!empty($this->images)){
|
|
$element['data-effect'] = 'image-set';
|
|
foreach($this->images as $image){
|
|
$content[] = Html::element('img', [
|
|
'src' => $image,
|
|
'style' => 'display: none'
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getGridArgs(array &$element, array &$content){
|
|
if($this->grid){
|
|
$grid = explode(' ', $this->grid);
|
|
$element['class'][] = 'col-' . $grid[0];
|
|
if(count($grid) > 1){
|
|
$element['class'][] = 'row-' . $grid[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
public function toHtml(){
|
|
$element = array_merge($this->attributes, [
|
|
'data-role' => 'tile',
|
|
]);
|
|
$content = [];
|
|
|
|
if(isset($element['class'])){
|
|
$element['class'] = explode(' ', $element['class']);
|
|
} else {
|
|
$element['class'] = [];
|
|
}
|
|
if(isset($element['style'])){
|
|
$element['style'] = explode(' ', $element['style']);
|
|
} else {
|
|
$element['style'] = [];
|
|
}
|
|
|
|
$this->getSizeArgs($element, $content);
|
|
$this->getColorArgs($element, $content);
|
|
$this->getIconArgs($element, $content);
|
|
$this->getTitleArgs($element, $content);
|
|
$this->getCoverArgs($element, $content);
|
|
$this->getHrefArgs($element, $content);
|
|
$this->getBadgeArgs($element, $content);
|
|
$this->getImagesArgs($element, $content);
|
|
$this->getGridArgs($element, $content);
|
|
|
|
$content = implode('', $content);
|
|
|
|
if(!empty($element['class'])){
|
|
$element['class'] = implode(' ', $element['class']);
|
|
} else {
|
|
unset($element['class']);
|
|
}
|
|
if(!empty($element['style'])){
|
|
$element['style'] = implode('; ', $element['style']) . ';';
|
|
} else {
|
|
unset($element['style']);
|
|
}
|
|
|
|
return Html::rawElement('a', $element, $content);
|
|
}
|
|
} |