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