xref: /dokuwiki/inc/Parsing/ParserMode/GfmMedia.php (revision 3440a8c07d59952439e180d2c33a32262fd3a84c)
1*3440a8c0SAndreas Gohr<?php
2*3440a8c0SAndreas Gohr
3*3440a8c0SAndreas Gohrnamespace dokuwiki\Parsing\ParserMode;
4*3440a8c0SAndreas Gohr
5*3440a8c0SAndreas Gohruse dokuwiki\Parsing\Handler;
6*3440a8c0SAndreas Gohruse dokuwiki\Parsing\Helpers;
7*3440a8c0SAndreas Gohr
8*3440a8c0SAndreas Gohr/**
9*3440a8c0SAndreas Gohr * GFM inline image ![alt](url) with optional title ![alt](url "title").
10*3440a8c0SAndreas Gohr *
11*3440a8c0SAndreas Gohr * Emits the same internalmedia/externalmedia handler calls as DokuWiki's
12*3440a8c0SAndreas Gohr * {{...}} media mode so renderers, indexers, and reverse renderers need no
13*3440a8c0SAndreas Gohr * changes. Width, height, cache, linking, and alignment directives are
14*3440a8c0SAndreas Gohr * accepted via the same URL-parameter vocabulary as DW media
15*3440a8c0SAndreas Gohr * (?100x200&nolink&recache, ?right, ?center, etc.) through shared parsing
16*3440a8c0SAndreas Gohr * in Helpers::parseMediaParameters() — the last `?` in the URL delimits
17*3440a8c0SAndreas Gohr * the DW parameter block, so query-bearing URLs like
18*3440a8c0SAndreas Gohr * https://example.com/img?v=2?100x100&right still work. GFM has no native
19*3440a8c0SAndreas Gohr * alignment syntax, so the `?left`/`?right`/`?center` keywords are the
20*3440a8c0SAndreas Gohr * canonical way to align an inline GFM image.
21*3440a8c0SAndreas Gohr *
22*3440a8c0SAndreas Gohr * Deliberately not supported (see skip.php for the affected spec examples):
23*3440a8c0SAndreas Gohr *
24*3440a8c0SAndreas Gohr *   - Reference-style images ![text][id] / ![text][] / ![foo] — the
25*3440a8c0SAndreas Gohr *     single-pass lexer cannot resolve forward references to [foo]: url
26*3440a8c0SAndreas Gohr *     definitions.
27*3440a8c0SAndreas Gohr *   - Pointy-bracket destinations ![alt](<foo bar>) — rarely used.
28*3440a8c0SAndreas Gohr *   - Nested brackets in alt text (![foo ![bar](x)](y), ![foo [bar](x)](y))
29*3440a8c0SAndreas Gohr *     — leftmost-match cannot reorder; outer falls back to literal.
30*3440a8c0SAndreas Gohr *   - Title HTML attribute — DokuWiki media instructions have no separate
31*3440a8c0SAndreas Gohr *     title-attribute slot (alt is used as the caption). The title parses
32*3440a8c0SAndreas Gohr *     cleanly but is discarded.
33*3440a8c0SAndreas Gohr *   - Mixed syntax: ![alt](url) inside [[dw|link]] or {{dw|media}} inside
34*3440a8c0SAndreas Gohr *     [gfm](link) — cross-syntax nesting is out of scope.
35*3440a8c0SAndreas Gohr */
36*3440a8c0SAndreas Gohrclass GfmMedia extends AbstractMode
37*3440a8c0SAndreas Gohr{
38*3440a8c0SAndreas Gohr    /** @inheritdoc */
39*3440a8c0SAndreas Gohr    public function getSort()
40*3440a8c0SAndreas Gohr    {
41*3440a8c0SAndreas Gohr        return 310;
42*3440a8c0SAndreas Gohr    }
43*3440a8c0SAndreas Gohr
44*3440a8c0SAndreas Gohr    /** @inheritdoc */
45*3440a8c0SAndreas Gohr    public function connectTo($mode)
46*3440a8c0SAndreas Gohr    {
47*3440a8c0SAndreas Gohr        // Outer shape: `![alt](url)`. Alt class forbids brackets and
48*3440a8c0SAndreas Gohr        // newlines; URL slot is permissive (`[^)\n]+`) — handle() does
49*3440a8c0SAndreas Gohr        // URL / title splitting post-entry, mirroring how GfmLink and DW
50*3440a8c0SAndreas Gohr        // Internallink work.
51*3440a8c0SAndreas Gohr        $this->Lexer->addSpecialPattern('!\[[^\[\]\n]*\]\([^)\n]+\)', $mode, 'gfm_media');
52*3440a8c0SAndreas Gohr    }
53*3440a8c0SAndreas Gohr
54*3440a8c0SAndreas Gohr    /** @inheritdoc */
55*3440a8c0SAndreas Gohr    public function handle($match, $state, $pos, Handler $handler)
56*3440a8c0SAndreas Gohr    {
57*3440a8c0SAndreas Gohr        $sep    = strpos($match, '](');
58*3440a8c0SAndreas Gohr        $alt    = substr($match, 2, $sep - 2);
59*3440a8c0SAndreas Gohr        $inside = trim(substr($match, $sep + 2, -1));
60*3440a8c0SAndreas Gohr        $url    = substr($inside, 0, strcspn($inside, " \t\n"));
61*3440a8c0SAndreas Gohr
62*3440a8c0SAndreas Gohr        $p = Helpers::parseMediaParameters($url);
63*3440a8c0SAndreas Gohr
64*3440a8c0SAndreas Gohr        $call = (media_isexternal($p['src']) || link_isinterwiki($p['src']))
65*3440a8c0SAndreas Gohr            ? 'externalmedia'
66*3440a8c0SAndreas Gohr            : 'internalmedia';
67*3440a8c0SAndreas Gohr
68*3440a8c0SAndreas Gohr        $handler->addCall(
69*3440a8c0SAndreas Gohr            $call,
70*3440a8c0SAndreas Gohr            [$p['src'], $alt !== '' ? $alt : null, $p['align'], $p['width'], $p['height'], $p['cache'], $p['linking']],
71*3440a8c0SAndreas Gohr            $pos
72*3440a8c0SAndreas Gohr        );
73*3440a8c0SAndreas Gohr        return true;
74*3440a8c0SAndreas Gohr    }
75*3440a8c0SAndreas Gohr}
76