1
0
mirror of https://github.com/erusev/parsedown.git synced 2023-08-10 21:13:06 +03:00
Files
parsedown/src/Html/Renderables/Element.php
2021-10-12 21:58:24 +01:00

218 lines
5.0 KiB
PHP

<?php
namespace Erusev\Parsedown\Html\Renderables;
use Erusev\Parsedown\Html\Renderable;
use Erusev\Parsedown\Html\Sanitisation\CharacterFilter;
use Erusev\Parsedown\Html\Sanitisation\Escaper;
use Erusev\Parsedown\Html\TransformableRenderable;
final class Element implements TransformableRenderable
{
use CanonicalStateRenderable;
const TEXT_LEVEL_ELEMENTS = [
'a' => true,
'b' => true,
'i' => true,
'q' => true,
's' => true,
'u' => true,
'br' => true,
'em' => true,
'rp' => true,
'rt' => true,
'tt' => true,
'xm' => true,
'bdo' => true,
'big' => true,
'del' => true,
'img' => true,
'ins' => true,
'kbd' => true,
'sub' => true,
'sup' => true,
'var' => true,
'wbr' => true,
'abbr' => true,
'cite' => true,
'code' => true,
'font' => true,
'mark' => true,
'nobr' => true,
'ruby' => true,
'span' => true,
'time' => true,
'blink' => true,
'small' => true,
'nextid' => true,
'spacer' => true,
'strike' => true,
'strong' => true,
'acronym' => true,
'listing' => true,
'marquee' => true,
'basefont' => true,
];
/** @var string */
private $name;
/** @var array<string, string>*/
private $attributes;
/** @var Renderable[]|null */
private $Contents;
/**
* @param string $name
* @param array<string, string> $attributes
* @param Renderable[]|null $Contents
*/
public function __construct($name, $attributes, $Contents)
{
$this->name = $name;
$this->attributes = $attributes;
$this->Contents = $Contents;
}
/**
* @param string $name
* @param array<string, string> $attributes
* @return self
*/
public static function selfClosing($name, array $attributes)
{
return new self($name, $attributes, null);
}
/** @return string */
public function name()
{
return $this->name;
}
/**
* @return array<string, string>
*/
public function attributes()
{
return $this->attributes;
}
/**
* @return Renderable[]|null
*/
public function contents()
{
return $this->Contents;
}
/**
* @param string $name
* @return self
*/
public function settingName($name)
{
return new self($name, $this->attributes, $this->Contents);
}
/**
* @param array<string, string> $attributes
* @return self
*/
public function settingAttributes(array $attributes)
{
return new self($this->name, $attributes, $this->Contents);
}
/**
* @param Renderable[]|null $Contents
* @return self
*/
public function settingContents($Contents)
{
return new self($this->name, $this->attributes, $Contents);
}
/** @return string */
public function getHtml()
{
$elementName = CharacterFilter::htmlElementName($this->name);
$html = '<' . $elementName;
if (! empty($this->attributes)) {
foreach ($this->attributes as $name => $value) {
$html .= ' '
. CharacterFilter::htmlAttributeName($name)
. '="'
. Escaper::htmlAttributeValue($value)
. '"'
;
}
}
if ($this->Contents !== null) {
$html .= '>';
if (! empty($this->Contents)) {
foreach ($this->Contents as $C) {
if (
$C instanceof Element
&& ! \array_key_exists(\strtolower($C->name()), self::TEXT_LEVEL_ELEMENTS)
) {
$html .= "\n";
}
$html .= $C->getHtml();
}
$Last = \end($this->Contents);
if (
$Last instanceof Element
&& ! \array_key_exists(\strtolower($Last->name()), self::TEXT_LEVEL_ELEMENTS)
) {
$html .= "\n";
}
}
$html .= "</" . $elementName . ">";
} else {
$html .= ' />';
}
return $html;
}
/**
* @param \Closure(string):Renderable $Transform
* @return Renderable
*/
public function transformingContent(\Closure $Transform): Renderable
{
if (! isset($this->Contents)) {
return $this;
}
return new self($this->name, $this->attributes, \array_map(
function (Renderable $R) use ($Transform): Renderable {
if (! $R instanceof TransformableRenderable) {
return $R;
}
return $R->transformingContent($Transform);
},
$this->Contents
));
}
}