xref: /dokuwiki/_test/tests/Parsing/Markdown/SpecCompatRenderer.php (revision 3440a8c07d59952439e180d2c33a32262fd3a84c)
1<?php
2
3namespace dokuwiki\test\Parsing\Markdown;
4
5use Doku_Renderer_xhtml;
6
7/**
8 * XHTML renderer tuned to emit the minimal HTML shape GFM's spec.txt uses.
9 *
10 * DokuWiki's production XHTML renderer wraps internal media in details
11 * links pointing at `/lib/exe/fetch.php?media=...` / `/lib/exe/detail.php?media=...`,
12 * rewrites internal link hrefs to `/doku.php?id=...`, and adds wiki-specific
13 * classes and attributes. All of this is correct for live wiki pages but
14 * diverges byte-for-byte from GFM's bare `<img src="...">` and
15 * `<a href="...">...</a>`.
16 *
17 * This renderer is used only by {@see GfmSpecTest} so the spec roundtrip
18 * can compare against byte-level spec HTML. Production rendering is
19 * unchanged. Methods not overridden here fall through to the XHTML
20 * renderer (paragraphs, emphasis, code spans, lists, etc.) — those render
21 * the same shape the spec expects.
22 *
23 * Note: title attributes on links/images are discarded at handle time
24 * (no DW instruction slot), so spec examples that expect `title="..."`
25 * still don't pass and stay in `skip.php`.
26 */
27class SpecCompatRenderer extends Doku_Renderer_xhtml
28{
29    public function internalmedia(
30        $src,
31        $title = null,
32        $align = null,
33        $width = null,
34        $height = null,
35        $cache = null,
36        $linking = null,
37        $return = false
38    ) {
39        $this->doc .= $this->specImg($src, $title, $width, $height);
40    }
41
42    public function externalmedia(
43        $src,
44        $title = null,
45        $align = null,
46        $width = null,
47        $height = null,
48        $cache = null,
49        $linking = null,
50        $return = false
51    ) {
52        $this->doc .= $this->specImg($src, $title, $width, $height);
53    }
54
55    public function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content')
56    {
57        $this->doc .= $this->specLink($id, $name);
58    }
59
60    public function externallink($url, $name = null, $returnonly = false)
61    {
62        $this->doc .= $this->specLink($url, $name);
63    }
64
65    public function interwikilink($match, $name, $wikiName, $wikiUri, $returnonly = false)
66    {
67        // Spec has no interwiki expectations; emit the raw `wp>Page` form as
68        // href so the mode is still visible but obviously non-standard.
69        $this->doc .= $this->specLink($match, $name);
70    }
71
72    public function emaillink($address, $name = null, $returnonly = false)
73    {
74        $this->doc .= $this->specLink('mailto:' . $address, $name ?? $address);
75    }
76
77    public function locallink($hash, $name = null, $returnonly = false)
78    {
79        $this->doc .= $this->specLink('#' . $hash, $name ?? $hash);
80    }
81
82    public function windowssharelink($url, $name = null, $returnonly = false)
83    {
84        $this->doc .= $this->specLink($url, $name);
85    }
86
87    private function specImg($src, $alt, $width, $height): string
88    {
89        $out = '<img src="' . hsc((string) $src) . '"';
90        $out .= ' alt="' . hsc((string) $alt) . '"';
91        if ($width !== null)  $out .= ' width="' . (int) $width . '"';
92        if ($height !== null) $out .= ' height="' . (int) $height . '"';
93        $out .= ' />';
94        return $out;
95    }
96
97    /**
98     * Emit a bare <a href="...">label</a>. If the label is a media
99     * descriptor array (the shape Media::parseMedia() returns, passed by
100     * Internallink / GfmLink when the label is `{{img}}` / `![alt](img)`),
101     * render the <img> inside the <a>.
102     */
103    private function specLink($href, $label): string
104    {
105        if (is_array($label) && isset($label['type'])) {
106            $img = $this->specImg(
107                $label['src'],
108                $label['title'],
109                $label['width'] ?? null,
110                $label['height'] ?? null
111            );
112            return '<a href="' . hsc((string) $href) . '">' . $img . '</a>';
113        }
114        $text = ($label === null || $label === '') ? $href : $label;
115        return '<a href="' . hsc((string) $href) . '">' . hsc((string) $text) . '</a>';
116    }
117}
118