xref: /dokuwiki/inc/Parsing/ParserMode/GfmMedia.php (revision 1e28e406b358f79221c515b2a56520d5dbbfb6c8)
13440a8c0SAndreas Gohr<?php
23440a8c0SAndreas Gohr
33440a8c0SAndreas Gohrnamespace dokuwiki\Parsing\ParserMode;
43440a8c0SAndreas Gohr
53440a8c0SAndreas Gohruse dokuwiki\Parsing\Handler;
6*1e28e406SAndreas Gohruse dokuwiki\Parsing\Helpers\Media as MediaHelper;
73440a8c0SAndreas Gohr
83440a8c0SAndreas Gohr/**
93440a8c0SAndreas Gohr * GFM inline image ![alt](url) with optional title ![alt](url "title").
103440a8c0SAndreas Gohr *
113440a8c0SAndreas Gohr * Emits the same internalmedia/externalmedia handler calls as DokuWiki's
123440a8c0SAndreas Gohr * {{...}} media mode so renderers, indexers, and reverse renderers need no
133440a8c0SAndreas Gohr * changes. Width, height, cache, linking, and alignment directives are
143440a8c0SAndreas Gohr * accepted via the same URL-parameter vocabulary as DW media
153440a8c0SAndreas Gohr * (?100x200&nolink&recache, ?right, ?center, etc.) through shared parsing
16*1e28e406SAndreas Gohr * in Helpers\Media::parseParameters() — the last `?` in the URL delimits
173440a8c0SAndreas Gohr * the DW parameter block, so query-bearing URLs like
183440a8c0SAndreas Gohr * https://example.com/img?v=2?100x100&right still work. GFM has no native
193440a8c0SAndreas Gohr * alignment syntax, so the `?left`/`?right`/`?center` keywords are the
203440a8c0SAndreas Gohr * canonical way to align an inline GFM image.
213440a8c0SAndreas Gohr *
223440a8c0SAndreas Gohr * Deliberately not supported (see skip.php for the affected spec examples):
233440a8c0SAndreas Gohr *
243440a8c0SAndreas Gohr *   - Reference-style images ![text][id] / ![text][] / ![foo] — the
253440a8c0SAndreas Gohr *     single-pass lexer cannot resolve forward references to [foo]: url
263440a8c0SAndreas Gohr *     definitions.
273440a8c0SAndreas Gohr *   - Pointy-bracket destinations ![alt](<foo bar>) — rarely used.
283440a8c0SAndreas Gohr *   - Nested brackets in alt text (![foo ![bar](x)](y), ![foo [bar](x)](y))
293440a8c0SAndreas Gohr *     — leftmost-match cannot reorder; outer falls back to literal.
303440a8c0SAndreas Gohr *   - Title HTML attribute — DokuWiki media instructions have no separate
313440a8c0SAndreas Gohr *     title-attribute slot (alt is used as the caption). The title parses
323440a8c0SAndreas Gohr *     cleanly but is discarded.
333440a8c0SAndreas Gohr *   - Mixed syntax: ![alt](url) inside [[dw|link]] or {{dw|media}} inside
343440a8c0SAndreas Gohr *     [gfm](link) — cross-syntax nesting is out of scope.
353440a8c0SAndreas Gohr */
363440a8c0SAndreas Gohrclass GfmMedia extends AbstractMode
373440a8c0SAndreas Gohr{
383440a8c0SAndreas Gohr    /** @inheritdoc */
393440a8c0SAndreas Gohr    public function getSort()
403440a8c0SAndreas Gohr    {
413440a8c0SAndreas Gohr        return 310;
423440a8c0SAndreas Gohr    }
433440a8c0SAndreas Gohr
443440a8c0SAndreas Gohr    /** @inheritdoc */
453440a8c0SAndreas Gohr    public function connectTo($mode)
463440a8c0SAndreas Gohr    {
473440a8c0SAndreas Gohr        // Outer shape: `![alt](url)`. Alt class forbids brackets and
483440a8c0SAndreas Gohr        // newlines; URL slot is permissive (`[^)\n]+`) — handle() does
493440a8c0SAndreas Gohr        // URL / title splitting post-entry, mirroring how GfmLink and DW
503440a8c0SAndreas Gohr        // Internallink work.
513440a8c0SAndreas Gohr        $this->Lexer->addSpecialPattern('!\[[^\[\]\n]*\]\([^)\n]+\)', $mode, 'gfm_media');
523440a8c0SAndreas Gohr    }
533440a8c0SAndreas Gohr
543440a8c0SAndreas Gohr    /** @inheritdoc */
553440a8c0SAndreas Gohr    public function handle($match, $state, $pos, Handler $handler)
563440a8c0SAndreas Gohr    {
573440a8c0SAndreas Gohr        $sep    = strpos($match, '](');
583440a8c0SAndreas Gohr        $alt    = substr($match, 2, $sep - 2);
593440a8c0SAndreas Gohr        $inside = trim(substr($match, $sep + 2, -1));
603440a8c0SAndreas Gohr        $url    = substr($inside, 0, strcspn($inside, " \t\n"));
613440a8c0SAndreas Gohr
62*1e28e406SAndreas Gohr        $p = MediaHelper::parseParameters($url);
633440a8c0SAndreas Gohr
643440a8c0SAndreas Gohr        $call = (media_isexternal($p['src']) || link_isinterwiki($p['src']))
653440a8c0SAndreas Gohr            ? 'externalmedia'
663440a8c0SAndreas Gohr            : 'internalmedia';
673440a8c0SAndreas Gohr
683440a8c0SAndreas Gohr        $handler->addCall(
693440a8c0SAndreas Gohr            $call,
703440a8c0SAndreas Gohr            [$p['src'], $alt !== '' ? $alt : null, $p['align'], $p['width'], $p['height'], $p['cache'], $p['linking']],
713440a8c0SAndreas Gohr            $pos
723440a8c0SAndreas Gohr        );
733440a8c0SAndreas Gohr        return true;
743440a8c0SAndreas Gohr    }
753440a8c0SAndreas Gohr}
76