Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
namespace Termwind;
6
 
7
use DOMDocument;
8
use DOMNode;
9
use Termwind\Html\CodeRenderer;
10
use Termwind\Html\PreRenderer;
11
use Termwind\Html\TableRenderer;
12
use Termwind\ValueObjects\Node;
13
 
14
/**
15
 * @internal
16
 */
17
final class HtmlRenderer
18
{
19
    /**
20
     * Renders the given html.
21
     */
22
    public function render(string $html, int $options): void
23
    {
24
        $this->parse($html)->render($options);
25
    }
26
 
27
    /**
28
     * Parses the given html.
29
     */
30
    public function parse(string $html): Components\Element
31
    {
32
        $dom = new DOMDocument();
33
 
34
        if (strip_tags($html) === $html) {
35
            return Termwind::span($html);
36
        }
37
 
38
        $html = '<?xml encoding="UTF-8">'.trim($html);
39
        $dom->loadHTML($html, LIBXML_NOERROR | LIBXML_COMPACT | LIBXML_HTML_NODEFDTD | LIBXML_NOBLANKS | LIBXML_NOXMLDECL);
40
 
41
        /** @var DOMNode $body */
42
        $body = $dom->getElementsByTagName('body')->item(0);
43
        $el = $this->convert(new Node($body));
44
 
45
        // @codeCoverageIgnoreStart
46
        return is_string($el)
47
            ? Termwind::span($el)
48
            : $el;
49
        // @codeCoverageIgnoreEnd
50
    }
51
 
52
    /**
53
     * Convert a tree of DOM nodes to a tree of termwind elements.
54
     */
55
    private function convert(Node $node): Components\Element|string
56
    {
57
        $children = [];
58
 
59
        if ($node->isName('table')) {
60
            return (new TableRenderer)->toElement($node);
61
        } elseif ($node->isName('code')) {
62
            return (new CodeRenderer)->toElement($node);
63
        } elseif ($node->isName('pre')) {
64
            return (new PreRenderer)->toElement($node);
65
        }
66
 
67
        foreach ($node->getChildNodes() as $child) {
68
            $children[] = $this->convert($child);
69
        }
70
 
71
        $children = array_filter($children, fn ($child) => $child !== '');
72
 
73
        return $this->toElement($node, $children);
74
    }
75
 
76
    /**
77
     * Convert a given DOM node to it's termwind element equivalent.
78
     *
79
     * @param  array<int, Components\Element|string>  $children
80
     */
81
    private function toElement(Node $node, array $children): Components\Element|string
82
    {
83
        if ($node->isText() || $node->isComment()) {
84
            return (string) $node;
85
        }
86
 
87
        /** @var array<string, mixed> $properties */
88
        $properties = [
89
            'isFirstChild' => $node->isFirstChild(),
90
        ];
91
 
92
        $styles = $node->getClassAttribute();
93
 
94
        return match ($node->getName()) {
95
            'body' => $children[0], // Pick only the first element from the body node
96
            'div' => Termwind::div($children, $styles, $properties),
97
            'p' => Termwind::paragraph($children, $styles, $properties),
98
            'ul' => Termwind::ul($children, $styles, $properties),
99
            'ol' => Termwind::ol($children, $styles, $properties),
100
            'li' => Termwind::li($children, $styles, $properties),
101
            'dl' => Termwind::dl($children, $styles, $properties),
102
            'dt' => Termwind::dt($children, $styles, $properties),
103
            'dd' => Termwind::dd($children, $styles, $properties),
104
            'span' => Termwind::span($children, $styles, $properties),
105
            'br' => Termwind::breakLine($styles, $properties),
106
            'strong' => Termwind::span($children, $styles, $properties)->strong(),
107
            'b' => Termwind::span($children, $styles, $properties)->fontBold(),
108
            'em', 'i' => Termwind::span($children, $styles, $properties)->italic(),
109
            'u' => Termwind::span($children, $styles, $properties)->underline(),
110
            's' => Termwind::span($children, $styles, $properties)->lineThrough(),
111
            'a' => Termwind::anchor($children, $styles, $properties)->href($node->getAttribute('href')),
112
            'hr' => Termwind::hr($styles, $properties),
113
            default => Termwind::div($children, $styles, $properties),
114
        };
115
    }
116
}