xref: /dokuwiki/inc/parser/metadata.php (revision 74981a4e680e4586b25ac0a679add084112cd604)
139a89382SEsther Brunner<?php
2faf3f01bSAndreas Gohr
3faf3f01bSAndreas Gohruse dokuwiki\File\MediaResolver;
4faf3f01bSAndreas Gohruse dokuwiki\File\PageResolver;
5faf3f01bSAndreas Gohruse dokuwiki\Utf8\PhpString;
6faf3f01bSAndreas Gohr
739a89382SEsther Brunner/**
893075b01SAndreas Gohr * The MetaData Renderer
993075b01SAndreas Gohr *
1093075b01SAndreas Gohr * Metadata is additional information about a DokuWiki page that gets extracted mainly from the page's content
1193075b01SAndreas Gohr * but also it's own filesystem data (like the creation time). All metadata is stored in the fields $meta and
1293075b01SAndreas Gohr * $persistent.
1393075b01SAndreas Gohr *
1493075b01SAndreas Gohr * Some simplified rendering to $doc is done to gather the page's (text-only) abstract.
15b4f2363aSAndreas Gohr *
16b4f2363aSAndreas Gohr * @author Esther Brunner <wikidesign@gmail.com>
1739a89382SEsther Brunner */
183aa984aeSLarsGit223class Doku_Renderer_metadata extends Doku_Renderer
193aa984aeSLarsGit223{
2017076c2aSAndreas Gohr    /** the approximate byte lenght to capture for the abstract */
21*74981a4eSAndreas Gohr    public const ABSTRACT_LEN = 250;
2217076c2aSAndreas Gohr
2317076c2aSAndreas Gohr    /** the maximum UTF8 character length for the abstract */
24*74981a4eSAndreas Gohr    public const ABSTRACT_MAX = 500;
2539a89382SEsther Brunner
2693075b01SAndreas Gohr    /** @var array transient meta data, will be reset on each rendering */
27faf3f01bSAndreas Gohr    public $meta = [];
2839a89382SEsther Brunner
2993075b01SAndreas Gohr    /** @var array persistent meta data, will be kept until explicitly deleted */
30faf3f01bSAndreas Gohr    public $persistent = [];
3139a89382SEsther Brunner
3293075b01SAndreas Gohr    /** @var array the list of headers used to create unique link ids */
33faf3f01bSAndreas Gohr    protected $headers = [];
3493075b01SAndreas Gohr
3593075b01SAndreas Gohr    /** @var string temporary $doc store */
3693075b01SAndreas Gohr    protected $store = '';
3793075b01SAndreas Gohr
3893075b01SAndreas Gohr    /** @var string keeps the first image reference */
3993075b01SAndreas Gohr    protected $firstimage = '';
4093075b01SAndreas Gohr
41b8f47726SChristopher Smith    /** @var bool whether or not data is being captured for the abstract, public to be accessible by plugins */
42b8f47726SChristopher Smith    public $capturing = true;
43b8f47726SChristopher Smith
4417076c2aSAndreas Gohr    /** @var bool determines if enough data for the abstract was collected, yet */
458f2758f6SAndreas Gohr    public $capture = true;
4617076c2aSAndreas Gohr
4717076c2aSAndreas Gohr    /** @var int number of bytes captured for abstract */
4817076c2aSAndreas Gohr    protected $captured = 0;
4917076c2aSAndreas Gohr
5093075b01SAndreas Gohr    /**
5193075b01SAndreas Gohr     * Returns the format produced by this renderer.
5293075b01SAndreas Gohr     *
5393075b01SAndreas Gohr     * @return string always 'metadata'
5493075b01SAndreas Gohr     */
553aa984aeSLarsGit223    public function getFormat()
563aa984aeSLarsGit223    {
575f70445dSAndreas Gohr        return 'metadata';
585f70445dSAndreas Gohr    }
595f70445dSAndreas Gohr
6093075b01SAndreas Gohr    /**
6193075b01SAndreas Gohr     * Initialize the document
6293075b01SAndreas Gohr     *
6393075b01SAndreas Gohr     * Sets up some of the persistent info about the page if it doesn't exist, yet.
6493075b01SAndreas Gohr     */
653aa984aeSLarsGit223    public function document_start()
663aa984aeSLarsGit223    {
67ef47e298SAndreas Gohr        global $ID;
68620f4930SAndreas Gohr
69faf3f01bSAndreas Gohr        $this->headers = [];
70620f4930SAndreas Gohr
71ef47e298SAndreas Gohr        // external pages are missing create date
720a444b5aSPhy        if (!isset($this->persistent['date']['created']) || !$this->persistent['date']['created']) {
73ef47e298SAndreas Gohr            $this->persistent['date']['created'] = filectime(wikiFN($ID));
74ef47e298SAndreas Gohr        }
75a8e72133SAndreas Gohr        if (!isset($this->persistent['user'])) {
76a8e72133SAndreas Gohr            $this->persistent['user'] = '';
77a8e72133SAndreas Gohr        }
78ef47e298SAndreas Gohr        if (!isset($this->persistent['creator'])) {
79ef47e298SAndreas Gohr            $this->persistent['creator'] = '';
80ef47e298SAndreas Gohr        }
810a7e3bceSchris        // reset metadata to persistent values
820a7e3bceSchris        $this->meta = $this->persistent;
8339a89382SEsther Brunner    }
8439a89382SEsther Brunner
8593075b01SAndreas Gohr    /**
8693075b01SAndreas Gohr     * Finalize the document
8793075b01SAndreas Gohr     *
8893075b01SAndreas Gohr     * Stores collected data in the metadata
8993075b01SAndreas Gohr     */
903aa984aeSLarsGit223    public function document_end()
913aa984aeSLarsGit223    {
92482cff99SAndreas Gohr        global $ID;
93482cff99SAndreas Gohr
94b8595a66SAndreas Gohr        // store internal info in metadata (notoc,nocache)
95b8595a66SAndreas Gohr        $this->meta['internal'] = $this->info;
96b8595a66SAndreas Gohr
97c66972f2SAdrian Lang        if (!isset($this->meta['description']['abstract'])) {
9839a89382SEsther Brunner            // cut off too long abstracts
9939a89382SEsther Brunner            $this->doc = trim($this->doc);
10017076c2aSAndreas Gohr            if (strlen($this->doc) > self::ABSTRACT_MAX) {
101faf3f01bSAndreas Gohr                $this->doc = PhpString::substr($this->doc, 0, self::ABSTRACT_MAX) . '…';
10217076c2aSAndreas Gohr            }
10339a89382SEsther Brunner            $this->meta['description']['abstract'] = $this->doc;
10439a89382SEsther Brunner        }
105aa5a2937SAndreas Gohr
106aa5a2937SAndreas Gohr        $this->meta['relation']['firstimage'] = $this->firstimage;
107482cff99SAndreas Gohr
108c0322273SAdrian Lang        if (!isset($this->meta['date']['modified'])) {
109482cff99SAndreas Gohr            $this->meta['date']['modified'] = filemtime(wikiFN($ID));
110482cff99SAndreas Gohr        }
11139a89382SEsther Brunner    }
11239a89382SEsther Brunner
11393075b01SAndreas Gohr    /**
11417076c2aSAndreas Gohr     * Render plain text data
11517076c2aSAndreas Gohr     *
11617076c2aSAndreas Gohr     * This function takes care of the amount captured data and will stop capturing when
11717076c2aSAndreas Gohr     * enough abstract data is available
11817076c2aSAndreas Gohr     *
11917076c2aSAndreas Gohr     * @param $text
12017076c2aSAndreas Gohr     */
1213aa984aeSLarsGit223    public function cdata($text)
1223aa984aeSLarsGit223    {
1233aa984aeSLarsGit223        if (!$this->capture || !$this->capturing) {
1243aa984aeSLarsGit223            return;
1253aa984aeSLarsGit223        }
12617076c2aSAndreas Gohr
12717076c2aSAndreas Gohr        $this->doc .= $text;
12817076c2aSAndreas Gohr
12917076c2aSAndreas Gohr        $this->captured += strlen($text);
1303aa984aeSLarsGit223        if ($this->captured > self::ABSTRACT_LEN) {
1313aa984aeSLarsGit223            $this->capture = false;
1323aa984aeSLarsGit223        }
13317076c2aSAndreas Gohr    }
13417076c2aSAndreas Gohr
13517076c2aSAndreas Gohr    /**
13693075b01SAndreas Gohr     * Add an item to the TOC
13793075b01SAndreas Gohr     *
13893075b01SAndreas Gohr     * @param string $id the hash link
13993075b01SAndreas Gohr     * @param string $text the text to display
14093075b01SAndreas Gohr     * @param int $level the nesting level
14193075b01SAndreas Gohr     */
1423aa984aeSLarsGit223    public function toc_additem($id, $text, $level)
1433aa984aeSLarsGit223    {
14439a89382SEsther Brunner        global $conf;
14539a89382SEsther Brunner
146e7856beaSchris        //only add items within configured levels
14739a89382SEsther Brunner        if ($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) {
14839a89382SEsther Brunner            // the TOC is one of our standard ul list arrays ;-)
149faf3f01bSAndreas Gohr            $this->meta['description']['tableofcontents'][] = [
150e7856beaSchris                'hid' => $id,
15139a89382SEsther Brunner                'title' => $text,
15239a89382SEsther Brunner                'type' => 'ul',
15339a89382SEsther Brunner                'level' => $level - $conf['toptoclevel'] + 1
154faf3f01bSAndreas Gohr            ];
15539a89382SEsther Brunner        }
156e7856beaSchris    }
157e7856beaSchris
15893075b01SAndreas Gohr    /**
15993075b01SAndreas Gohr     * Render a heading
16093075b01SAndreas Gohr     *
16193075b01SAndreas Gohr     * @param string $text the text to display
16293075b01SAndreas Gohr     * @param int $level header level
16393075b01SAndreas Gohr     * @param int $pos byte position in the original source
16493075b01SAndreas Gohr     */
1653aa984aeSLarsGit223    public function header($text, $level, $pos)
1663aa984aeSLarsGit223    {
1673aa984aeSLarsGit223        if (!isset($this->meta['title'])) {
1683aa984aeSLarsGit223            $this->meta['title'] = $text;
1693aa984aeSLarsGit223        }
170e7856beaSchris
171e7856beaSchris        // add the header to the TOC
172e0c26282SGerrit Uitslag        $hid = $this->_headerToLink($text, true);
173e7856beaSchris        $this->toc_additem($hid, $text, $level);
174e7856beaSchris
17539a89382SEsther Brunner        // add to summary
17617076c2aSAndreas Gohr        $this->cdata(DOKU_LF . $text . DOKU_LF);
17739a89382SEsther Brunner    }
17839a89382SEsther Brunner
17993075b01SAndreas Gohr    /**
18093075b01SAndreas Gohr     * Open a paragraph
18193075b01SAndreas Gohr     */
1823aa984aeSLarsGit223    public function p_open()
1833aa984aeSLarsGit223    {
18417076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
18539a89382SEsther Brunner    }
18639a89382SEsther Brunner
18793075b01SAndreas Gohr    /**
18893075b01SAndreas Gohr     * Close a paragraph
18993075b01SAndreas Gohr     */
1903aa984aeSLarsGit223    public function p_close()
1913aa984aeSLarsGit223    {
19217076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
19339a89382SEsther Brunner    }
19439a89382SEsther Brunner
19593075b01SAndreas Gohr    /**
19693075b01SAndreas Gohr     * Create a line break
19793075b01SAndreas Gohr     */
1983aa984aeSLarsGit223    public function linebreak()
1993aa984aeSLarsGit223    {
20017076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
20139a89382SEsther Brunner    }
20239a89382SEsther Brunner
20393075b01SAndreas Gohr    /**
20493075b01SAndreas Gohr     * Create a horizontal line
20593075b01SAndreas Gohr     */
2063aa984aeSLarsGit223    public function hr()
2073aa984aeSLarsGit223    {
20817076c2aSAndreas Gohr        $this->cdata(DOKU_LF . '----------' . DOKU_LF);
20939a89382SEsther Brunner    }
21039a89382SEsther Brunner
21139a89382SEsther Brunner    /**
21239a89382SEsther Brunner     * Callback for footnote start syntax
21339a89382SEsther Brunner     *
21439a89382SEsther Brunner     * All following content will go to the footnote instead of
21539a89382SEsther Brunner     * the document. To achieve this the previous rendered content
21639a89382SEsther Brunner     * is moved to $store and $doc is cleared
21739a89382SEsther Brunner     *
21839a89382SEsther Brunner     * @author Andreas Gohr <andi@splitbrain.org>
21939a89382SEsther Brunner     */
2203aa984aeSLarsGit223    public function footnote_open()
2213aa984aeSLarsGit223    {
22239a89382SEsther Brunner        if ($this->capture) {
223b8f47726SChristopher Smith            // move current content to store
224b8f47726SChristopher Smith            // this is required to ensure safe behaviour of plugins accessed within footnotes
22539a89382SEsther Brunner            $this->store = $this->doc;
22639a89382SEsther Brunner            $this->doc = '';
227b8f47726SChristopher Smith
228b8f47726SChristopher Smith            // disable capturing
229b8f47726SChristopher Smith            $this->capturing = false;
23039a89382SEsther Brunner        }
23139a89382SEsther Brunner    }
23239a89382SEsther Brunner
23339a89382SEsther Brunner    /**
23439a89382SEsther Brunner     * Callback for footnote end syntax
23539a89382SEsther Brunner     *
236b8f47726SChristopher Smith     * All content rendered whilst within footnote syntax mode is discarded,
237b8f47726SChristopher Smith     * the previously rendered content is restored and capturing is re-enabled.
23839a89382SEsther Brunner     *
23939a89382SEsther Brunner     * @author Andreas Gohr
24039a89382SEsther Brunner     */
2413aa984aeSLarsGit223    public function footnote_close()
2423aa984aeSLarsGit223    {
24339a89382SEsther Brunner        if ($this->capture) {
244b8f47726SChristopher Smith            // re-enable capturing
245b8f47726SChristopher Smith            $this->capturing = true;
246b8f47726SChristopher Smith            // restore previously rendered content
24739a89382SEsther Brunner            $this->doc = $this->store;
24839a89382SEsther Brunner            $this->store = '';
24939a89382SEsther Brunner        }
25039a89382SEsther Brunner    }
25139a89382SEsther Brunner
25293075b01SAndreas Gohr    /**
25393075b01SAndreas Gohr     * Open an unordered list
25493075b01SAndreas Gohr     */
2553aa984aeSLarsGit223    public function listu_open()
2563aa984aeSLarsGit223    {
25717076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
25839a89382SEsther Brunner    }
25939a89382SEsther Brunner
26093075b01SAndreas Gohr    /**
26193075b01SAndreas Gohr     * Open an ordered list
26293075b01SAndreas Gohr     */
2633aa984aeSLarsGit223    public function listo_open()
2643aa984aeSLarsGit223    {
26517076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
26639a89382SEsther Brunner    }
26739a89382SEsther Brunner
26893075b01SAndreas Gohr    /**
26993075b01SAndreas Gohr     * Open a list item
27093075b01SAndreas Gohr     *
27193075b01SAndreas Gohr     * @param int $level the nesting level
272e3a24861SChristopher Smith     * @param bool $node true when a node; false when a leaf
27393075b01SAndreas Gohr     */
2743aa984aeSLarsGit223    public function listitem_open($level, $node = false)
2753aa984aeSLarsGit223    {
27617076c2aSAndreas Gohr        $this->cdata(str_repeat(DOKU_TAB, $level) . '* ');
27739a89382SEsther Brunner    }
27839a89382SEsther Brunner
27993075b01SAndreas Gohr    /**
28093075b01SAndreas Gohr     * Close a list item
28193075b01SAndreas Gohr     */
2823aa984aeSLarsGit223    public function listitem_close()
2833aa984aeSLarsGit223    {
28417076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
28539a89382SEsther Brunner    }
28639a89382SEsther Brunner
28793075b01SAndreas Gohr    /**
28893075b01SAndreas Gohr     * Output preformatted text
28993075b01SAndreas Gohr     *
29093075b01SAndreas Gohr     * @param string $text
29193075b01SAndreas Gohr     */
2923aa984aeSLarsGit223    public function preformatted($text)
2933aa984aeSLarsGit223    {
29417076c2aSAndreas Gohr        $this->cdata($text);
29539a89382SEsther Brunner    }
29639a89382SEsther Brunner
29793075b01SAndreas Gohr    /**
29893075b01SAndreas Gohr     * Start a block quote
29993075b01SAndreas Gohr     */
3003aa984aeSLarsGit223    public function quote_open()
3013aa984aeSLarsGit223    {
30217076c2aSAndreas Gohr        $this->cdata(DOKU_LF . DOKU_TAB . '"');
30339a89382SEsther Brunner    }
30439a89382SEsther Brunner
30593075b01SAndreas Gohr    /**
30693075b01SAndreas Gohr     * Stop a block quote
30793075b01SAndreas Gohr     */
3083aa984aeSLarsGit223    public function quote_close()
3093aa984aeSLarsGit223    {
31017076c2aSAndreas Gohr        $this->cdata('"' . DOKU_LF);
31139a89382SEsther Brunner    }
31239a89382SEsther Brunner
31393075b01SAndreas Gohr    /**
31493075b01SAndreas Gohr     * Display text as file content, optionally syntax highlighted
31593075b01SAndreas Gohr     *
31693075b01SAndreas Gohr     * @param string $text text to show
31793075b01SAndreas Gohr     * @param string $lang programming language to use for syntax highlighting
31893075b01SAndreas Gohr     * @param string $file file path label
31993075b01SAndreas Gohr     */
3203aa984aeSLarsGit223    public function file($text, $lang = null, $file = null)
3213aa984aeSLarsGit223    {
32217076c2aSAndreas Gohr        $this->cdata(DOKU_LF . $text . DOKU_LF);
32393075b01SAndreas Gohr    }
32493075b01SAndreas Gohr
32593075b01SAndreas Gohr    /**
32693075b01SAndreas Gohr     * Display text as code content, optionally syntax highlighted
32793075b01SAndreas Gohr     *
32893075b01SAndreas Gohr     * @param string $text text to show
32993075b01SAndreas Gohr     * @param string $language programming language to use for syntax highlighting
33093075b01SAndreas Gohr     * @param string $file file path label
33193075b01SAndreas Gohr     */
3323aa984aeSLarsGit223    public function code($text, $language = null, $file = null)
3333aa984aeSLarsGit223    {
33417076c2aSAndreas Gohr        $this->cdata(DOKU_LF . $text . DOKU_LF);
33539a89382SEsther Brunner    }
33639a89382SEsther Brunner
33793075b01SAndreas Gohr    /**
33893075b01SAndreas Gohr     * Format an acronym
33993075b01SAndreas Gohr     *
34093075b01SAndreas Gohr     * Uses $this->acronyms
34193075b01SAndreas Gohr     *
34293075b01SAndreas Gohr     * @param string $acronym
34393075b01SAndreas Gohr     */
3443aa984aeSLarsGit223    public function acronym($acronym)
3453aa984aeSLarsGit223    {
34617076c2aSAndreas Gohr        $this->cdata($acronym);
34739a89382SEsther Brunner    }
34839a89382SEsther Brunner
34993075b01SAndreas Gohr    /**
35093075b01SAndreas Gohr     * Format a smiley
35193075b01SAndreas Gohr     *
35293075b01SAndreas Gohr     * Uses $this->smiley
35393075b01SAndreas Gohr     *
35493075b01SAndreas Gohr     * @param string $smiley
35593075b01SAndreas Gohr     */
3563aa984aeSLarsGit223    public function smiley($smiley)
3573aa984aeSLarsGit223    {
35817076c2aSAndreas Gohr        $this->cdata($smiley);
35939a89382SEsther Brunner    }
36039a89382SEsther Brunner
36193075b01SAndreas Gohr    /**
36293075b01SAndreas Gohr     * Format an entity
36393075b01SAndreas Gohr     *
36493075b01SAndreas Gohr     * Entities are basically small text replacements
36593075b01SAndreas Gohr     *
36693075b01SAndreas Gohr     * Uses $this->entities
36793075b01SAndreas Gohr     *
36893075b01SAndreas Gohr     * @param string $entity
36993075b01SAndreas Gohr     */
3703aa984aeSLarsGit223    public function entity($entity)
3713aa984aeSLarsGit223    {
37217076c2aSAndreas Gohr        $this->cdata($entity);
37339a89382SEsther Brunner    }
37439a89382SEsther Brunner
37593075b01SAndreas Gohr    /**
37693075b01SAndreas Gohr     * Typographically format a multiply sign
37793075b01SAndreas Gohr     *
37893075b01SAndreas Gohr     * Example: ($x=640, $y=480) should result in "640×480"
37993075b01SAndreas Gohr     *
38093075b01SAndreas Gohr     * @param string|int $x first value
38193075b01SAndreas Gohr     * @param string|int $y second value
38293075b01SAndreas Gohr     */
3833aa984aeSLarsGit223    public function multiplyentity($x, $y)
3843aa984aeSLarsGit223    {
38517076c2aSAndreas Gohr        $this->cdata($x . '×' . $y);
38639a89382SEsther Brunner    }
38739a89382SEsther Brunner
38893075b01SAndreas Gohr    /**
38993075b01SAndreas Gohr     * Render an opening single quote char (language specific)
39093075b01SAndreas Gohr     */
3913aa984aeSLarsGit223    public function singlequoteopening()
3923aa984aeSLarsGit223    {
39371b40da2SAnika Henke        global $lang;
39417076c2aSAndreas Gohr        $this->cdata($lang['singlequoteopening']);
39539a89382SEsther Brunner    }
39639a89382SEsther Brunner
39793075b01SAndreas Gohr    /**
39893075b01SAndreas Gohr     * Render a closing single quote char (language specific)
39993075b01SAndreas Gohr     */
4003aa984aeSLarsGit223    public function singlequoteclosing()
4013aa984aeSLarsGit223    {
40271b40da2SAnika Henke        global $lang;
40317076c2aSAndreas Gohr        $this->cdata($lang['singlequoteclosing']);
40439a89382SEsther Brunner    }
40539a89382SEsther Brunner
40693075b01SAndreas Gohr    /**
40793075b01SAndreas Gohr     * Render an apostrophe char (language specific)
40893075b01SAndreas Gohr     */
4093aa984aeSLarsGit223    public function apostrophe()
4103aa984aeSLarsGit223    {
41157d757d1SAndreas Gohr        global $lang;
41217076c2aSAndreas Gohr        $this->cdata($lang['apostrophe']);
41357d757d1SAndreas Gohr    }
41457d757d1SAndreas Gohr
41593075b01SAndreas Gohr    /**
41693075b01SAndreas Gohr     * Render an opening double quote char (language specific)
41793075b01SAndreas Gohr     */
4183aa984aeSLarsGit223    public function doublequoteopening()
4193aa984aeSLarsGit223    {
42071b40da2SAnika Henke        global $lang;
42117076c2aSAndreas Gohr        $this->cdata($lang['doublequoteopening']);
42239a89382SEsther Brunner    }
42339a89382SEsther Brunner
42493075b01SAndreas Gohr    /**
42593075b01SAndreas Gohr     * Render an closinging double quote char (language specific)
42693075b01SAndreas Gohr     */
4273aa984aeSLarsGit223    public function doublequoteclosing()
4283aa984aeSLarsGit223    {
42971b40da2SAnika Henke        global $lang;
43017076c2aSAndreas Gohr        $this->cdata($lang['doublequoteclosing']);
43139a89382SEsther Brunner    }
43239a89382SEsther Brunner
43393075b01SAndreas Gohr    /**
43493075b01SAndreas Gohr     * Render a CamelCase link
43593075b01SAndreas Gohr     *
43693075b01SAndreas Gohr     * @param string $link The link name
43793075b01SAndreas Gohr     * @see http://en.wikipedia.org/wiki/CamelCase
43893075b01SAndreas Gohr     */
4393aa984aeSLarsGit223    public function camelcaselink($link)
4403aa984aeSLarsGit223    {
44139a89382SEsther Brunner        $this->internallink($link, $link);
44239a89382SEsther Brunner    }
44339a89382SEsther Brunner
44493075b01SAndreas Gohr    /**
44593075b01SAndreas Gohr     * Render a page local link
44693075b01SAndreas Gohr     *
44793075b01SAndreas Gohr     * @param string $hash hash link identifier
44893075b01SAndreas Gohr     * @param string $name name for the link
44993075b01SAndreas Gohr     */
4503aa984aeSLarsGit223    public function locallink($hash, $name = null)
4513aa984aeSLarsGit223    {
4529269d0b1SMichael Hamann        if (is_array($name)) {
4539269d0b1SMichael Hamann            $this->_firstimage($name['src']);
4543aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
4553aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
4563aa984aeSLarsGit223            }
4579269d0b1SMichael Hamann        }
4589269d0b1SMichael Hamann    }
45939a89382SEsther Brunner
46039a89382SEsther Brunner    /**
46139a89382SEsther Brunner     * keep track of internal links in $this->meta['relation']['references']
46293075b01SAndreas Gohr     *
46393075b01SAndreas Gohr     * @param string $id page ID to link to. eg. 'wiki:syntax'
46459bc3b48SGerrit Uitslag     * @param string|array|null $name name for the link, array for media file
46539a89382SEsther Brunner     */
4663aa984aeSLarsGit223    public function internallink($id, $name = null)
4673aa984aeSLarsGit223    {
46839a89382SEsther Brunner        global $ID;
46939a89382SEsther Brunner
470ffec1009SMichael Hamann        if (is_array($name)) {
471aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
4723aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
4733aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
4743aa984aeSLarsGit223            }
475ffec1009SMichael Hamann        }
476aa5a2937SAndreas Gohr
47766d935e7SMichael Hamann        $parts = explode('?', $id, 2);
47866d935e7SMichael Hamann        if (count($parts) === 2) {
47966d935e7SMichael Hamann            $id = $parts[0];
48066d935e7SMichael Hamann        }
48166d935e7SMichael Hamann
48239a89382SEsther Brunner        $default = $this->_simpleTitle($id);
48339a89382SEsther Brunner
48439a89382SEsther Brunner        // first resolve and clean up the $id
485faf3f01bSAndreas Gohr        $resolver = new PageResolver($ID);
4868c6be208SAndreas Gohr        $id = $resolver->resolveId($id);
487faf3f01bSAndreas Gohr        [$page] = sexplode('#', $id, 2);
48839a89382SEsther Brunner
48939a89382SEsther Brunner        // set metadata
4908c6be208SAndreas Gohr        $this->meta['relation']['references'][$page] = page_exists($page);
49139a89382SEsther Brunner        // $data = array('relation' => array('isreferencedby' => array($ID => true)));
49239a89382SEsther Brunner        // p_set_metadata($id, $data);
49339a89382SEsther Brunner
49439a89382SEsther Brunner        // add link title to summary
49539a89382SEsther Brunner        if ($this->capture) {
49639a89382SEsther Brunner            $name = $this->_getLinkTitle($name, $default, $id);
49739a89382SEsther Brunner            $this->doc .= $name;
49839a89382SEsther Brunner        }
49939a89382SEsther Brunner    }
50039a89382SEsther Brunner
50193075b01SAndreas Gohr    /**
50293075b01SAndreas Gohr     * Render an external link
50393075b01SAndreas Gohr     *
50493075b01SAndreas Gohr     * @param string $url full URL with scheme
50559bc3b48SGerrit Uitslag     * @param string|array|null $name name for the link, array for media file
50693075b01SAndreas Gohr     */
5073aa984aeSLarsGit223    public function externallink($url, $name = null)
5083aa984aeSLarsGit223    {
509ffec1009SMichael Hamann        if (is_array($name)) {
510aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5113aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5123aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5133aa984aeSLarsGit223            }
514ffec1009SMichael Hamann        }
515aa5a2937SAndreas Gohr
51639a89382SEsther Brunner        if ($this->capture) {
517a2ea2dc1SAdrian Lang            $this->doc .= $this->_getLinkTitle($name, '<' . $url . '>');
51839a89382SEsther Brunner        }
51939a89382SEsther Brunner    }
52039a89382SEsther Brunner
52193075b01SAndreas Gohr    /**
52293075b01SAndreas Gohr     * Render an interwiki link
52393075b01SAndreas Gohr     *
52493075b01SAndreas Gohr     * You may want to use $this->_resolveInterWiki() here
52593075b01SAndreas Gohr     *
52693075b01SAndreas Gohr     * @param string $match original link - probably not much use
52793075b01SAndreas Gohr     * @param string|array $name name for the link, array for media file
52893075b01SAndreas Gohr     * @param string $wikiName indentifier (shortcut) for the remote wiki
52993075b01SAndreas Gohr     * @param string $wikiUri the fragment parsed from the original link
53093075b01SAndreas Gohr     */
5313aa984aeSLarsGit223    public function interwikilink($match, $name, $wikiName, $wikiUri)
5323aa984aeSLarsGit223    {
533ffec1009SMichael Hamann        if (is_array($name)) {
534aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5353aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5363aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5373aa984aeSLarsGit223            }
538ffec1009SMichael Hamann        }
539aa5a2937SAndreas Gohr
54039a89382SEsther Brunner        if ($this->capture) {
541faf3f01bSAndreas Gohr            [$wikiUri] = explode('#', $wikiUri, 2);
542a2ea2dc1SAdrian Lang            $name = $this->_getLinkTitle($name, $wikiUri);
54339a89382SEsther Brunner            $this->doc .= $name;
54439a89382SEsther Brunner        }
54539a89382SEsther Brunner    }
54639a89382SEsther Brunner
54793075b01SAndreas Gohr    /**
54893075b01SAndreas Gohr     * Link to windows share
54993075b01SAndreas Gohr     *
55093075b01SAndreas Gohr     * @param string $url the link
55193075b01SAndreas Gohr     * @param string|array $name name for the link, array for media file
55293075b01SAndreas Gohr     */
5533aa984aeSLarsGit223    public function windowssharelink($url, $name = null)
5543aa984aeSLarsGit223    {
555ffec1009SMichael Hamann        if (is_array($name)) {
556aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5573aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5583aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5593aa984aeSLarsGit223            }
560ffec1009SMichael Hamann        }
561aa5a2937SAndreas Gohr
56239a89382SEsther Brunner        if ($this->capture) {
5633aa984aeSLarsGit223            if ($name) {
5643aa984aeSLarsGit223                $this->doc .= $name;
5653aa984aeSLarsGit223            } else {
5663aa984aeSLarsGit223                $this->doc .= '<' . $url . '>';
5673aa984aeSLarsGit223            }
56839a89382SEsther Brunner        }
56939a89382SEsther Brunner    }
57039a89382SEsther Brunner
57193075b01SAndreas Gohr    /**
57293075b01SAndreas Gohr     * Render a linked E-Mail Address
57393075b01SAndreas Gohr     *
57493075b01SAndreas Gohr     * Should honor $conf['mailguard'] setting
57593075b01SAndreas Gohr     *
57693075b01SAndreas Gohr     * @param string $address Email-Address
57793075b01SAndreas Gohr     * @param string|array $name name for the link, array for media file
57893075b01SAndreas Gohr     */
5793aa984aeSLarsGit223    public function emaillink($address, $name = null)
5803aa984aeSLarsGit223    {
581ffec1009SMichael Hamann        if (is_array($name)) {
582aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5833aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5843aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5853aa984aeSLarsGit223            }
586ffec1009SMichael Hamann        }
587aa5a2937SAndreas Gohr
58839a89382SEsther Brunner        if ($this->capture) {
5893aa984aeSLarsGit223            if ($name) {
5903aa984aeSLarsGit223                $this->doc .= $name;
5913aa984aeSLarsGit223            } else {
5923aa984aeSLarsGit223                $this->doc .= '<' . $address . '>';
5933aa984aeSLarsGit223            }
59439a89382SEsther Brunner        }
59539a89382SEsther Brunner    }
59639a89382SEsther Brunner
59793075b01SAndreas Gohr    /**
59893075b01SAndreas Gohr     * Render an internal media file
59993075b01SAndreas Gohr     *
60093075b01SAndreas Gohr     * @param string $src media ID
60193075b01SAndreas Gohr     * @param string $title descriptive text
60293075b01SAndreas Gohr     * @param string $align left|center|right
60393075b01SAndreas Gohr     * @param int $width width of media in pixel
60493075b01SAndreas Gohr     * @param int $height height of media in pixel
60593075b01SAndreas Gohr     * @param string $cache cache|recache|nocache
60693075b01SAndreas Gohr     * @param string $linking linkonly|detail|nolink
60793075b01SAndreas Gohr     */
608de369923SAndreas Gohr    public function internalmedia($src, $title = null, $align = null, $width = null,
6093aa984aeSLarsGit223                                  $height = null, $cache = null, $linking = null)
6103aa984aeSLarsGit223    {
6113aa984aeSLarsGit223        if ($this->capture && $title) {
6123aa984aeSLarsGit223            $this->doc .= '[' . $title . ']';
6133aa984aeSLarsGit223        }
614aa5a2937SAndreas Gohr        $this->_firstimage($src);
615ffec1009SMichael Hamann        $this->_recordMediaUsage($src);
61639a89382SEsther Brunner    }
61739a89382SEsther Brunner
61893075b01SAndreas Gohr    /**
61993075b01SAndreas Gohr     * Render an external media file
62093075b01SAndreas Gohr     *
62193075b01SAndreas Gohr     * @param string $src full media URL
62293075b01SAndreas Gohr     * @param string $title descriptive text
62393075b01SAndreas Gohr     * @param string $align left|center|right
62493075b01SAndreas Gohr     * @param int $width width of media in pixel
62593075b01SAndreas Gohr     * @param int $height height of media in pixel
62693075b01SAndreas Gohr     * @param string $cache cache|recache|nocache
62793075b01SAndreas Gohr     * @param string $linking linkonly|detail|nolink
62893075b01SAndreas Gohr     */
629de369923SAndreas Gohr    public function externalmedia($src, $title = null, $align = null, $width = null,
6303aa984aeSLarsGit223                                  $height = null, $cache = null, $linking = null)
6313aa984aeSLarsGit223    {
6323aa984aeSLarsGit223        if ($this->capture && $title) {
6333aa984aeSLarsGit223            $this->doc .= '[' . $title . ']';
6343aa984aeSLarsGit223        }
635aa5a2937SAndreas Gohr        $this->_firstimage($src);
63639a89382SEsther Brunner    }
63739a89382SEsther Brunner
63893075b01SAndreas Gohr    /**
63993075b01SAndreas Gohr     * Render the output of an RSS feed
64093075b01SAndreas Gohr     *
64193075b01SAndreas Gohr     * @param string $url URL of the feed
64293075b01SAndreas Gohr     * @param array $params Finetuning of the output
64393075b01SAndreas Gohr     */
6443aa984aeSLarsGit223    public function rss($url, $params)
6453aa984aeSLarsGit223    {
646ce6b63d9Schris        $this->meta['relation']['haspart'][$url] = true;
64764e9144aSchris
64864e9144aSchris        $this->meta['date']['valid']['age'] =
64964e9144aSchris            isset($this->meta['date']['valid']['age']) ?
65064e9144aSchris                min($this->meta['date']['valid']['age'], $params['refresh']) :
65164e9144aSchris                $params['refresh'];
652ce6b63d9Schris    }
65339a89382SEsther Brunner
65493075b01SAndreas Gohr    #region Utils
65539a89382SEsther Brunner
65639a89382SEsther Brunner    /**
65739a89382SEsther Brunner     * Removes any Namespace from the given name but keeps
65839a89382SEsther Brunner     * casing and special chars
65939a89382SEsther Brunner     *
660f50a239bSTakamura     * @param string $name
661f50a239bSTakamura     *
662f50a239bSTakamura     * @return mixed|string
663faf3f01bSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
664faf3f01bSAndreas Gohr     *
66539a89382SEsther Brunner     */
6663aa984aeSLarsGit223    public function _simpleTitle($name)
6673aa984aeSLarsGit223    {
66839a89382SEsther Brunner        global $conf;
66939a89382SEsther Brunner
6703aa984aeSLarsGit223        if (is_array($name)) {
6713aa984aeSLarsGit223            return '';
6723aa984aeSLarsGit223        }
6739bee852eSAndreas Gohr
67439a89382SEsther Brunner        if ($conf['useslash']) {
67539a89382SEsther Brunner            $nssep = '[:;/]';
67639a89382SEsther Brunner        } else {
67739a89382SEsther Brunner            $nssep = '[:;]';
67839a89382SEsther Brunner        }
67939a89382SEsther Brunner        $name = preg_replace('!.*' . $nssep . '!', '', $name);
6803be6e394Schris        //if there is a hash we use the anchor name only
68139a89382SEsther Brunner        $name = preg_replace('!.*#!', '', $name);
68239a89382SEsther Brunner        return $name;
68339a89382SEsther Brunner    }
68439a89382SEsther Brunner
68539a89382SEsther Brunner    /**
68639a89382SEsther Brunner     * Construct a title and handle images in titles
68739a89382SEsther Brunner     *
68859bc3b48SGerrit Uitslag     * @param string|array|null $title either string title or media array
68993075b01SAndreas Gohr     * @param string $default default title if nothing else is found
69093075b01SAndreas Gohr     * @param null|string $id linked page id (used to extract title from first heading)
69193075b01SAndreas Gohr     * @return string title text
692faf3f01bSAndreas Gohr     * @author Harry Fuecks <hfuecks@gmail.com>
69339a89382SEsther Brunner     */
6943aa984aeSLarsGit223    public function _getLinkTitle($title, $default, $id = null)
6953aa984aeSLarsGit223    {
69685038eabSDanny        if (is_array($title)) {
69793075b01SAndreas Gohr            if ($title['title']) {
69893075b01SAndreas Gohr                return '[' . $title['title'] . ']';
69993075b01SAndreas Gohr            } else {
70093075b01SAndreas Gohr                return $default;
70193075b01SAndreas Gohr            }
70285038eabSDanny        } elseif (is_null($title) || trim($title) == '') {
703fe9ec250SChris Smith            if (useHeading('content') && $id) {
70420f04039SDanny                $heading = p_get_first_heading($id, METADATA_DONT_RENDER);
7053aa984aeSLarsGit223                if ($heading) {
7063aa984aeSLarsGit223                    return $heading;
7073aa984aeSLarsGit223                }
70839a89382SEsther Brunner            }
70939a89382SEsther Brunner            return $default;
71085038eabSDanny        } else {
71139a89382SEsther Brunner            return $title;
71239a89382SEsther Brunner        }
71339a89382SEsther Brunner    }
71439a89382SEsther Brunner
71593075b01SAndreas Gohr    /**
71693075b01SAndreas Gohr     * Remember first image
71793075b01SAndreas Gohr     *
71893075b01SAndreas Gohr     * @param string $src image URL or ID
71993075b01SAndreas Gohr     */
7203aa984aeSLarsGit223    protected function _firstimage($src)
7213aa984aeSLarsGit223    {
722aa5a2937SAndreas Gohr        global $ID;
723aa5a2937SAndreas Gohr
7243aa984aeSLarsGit223        if ($this->firstimage) {
7253aa984aeSLarsGit223            return;
7263aa984aeSLarsGit223        }
7273aa984aeSLarsGit223
728faf3f01bSAndreas Gohr        [$src] = explode('#', $src, 2);
7293e7e6067SKlap-in        if (!media_isexternal($src)) {
730faf3f01bSAndreas Gohr            $src = (new MediaResolver($ID))->resolveId($src);
731aa5a2937SAndreas Gohr        }
73229d63aa5SAndreas Gohr        if (preg_match('/.(jpe?g|gif|png|webp|svg)$/i', $src)) {
733aa5a2937SAndreas Gohr            $this->firstimage = $src;
734aa5a2937SAndreas Gohr        }
735aa5a2937SAndreas Gohr    }
736ffec1009SMichael Hamann
73793075b01SAndreas Gohr    /**
73893075b01SAndreas Gohr     * Store list of used media files in metadata
73993075b01SAndreas Gohr     *
74093075b01SAndreas Gohr     * @param string $src media ID
74193075b01SAndreas Gohr     */
7423aa984aeSLarsGit223    protected function _recordMediaUsage($src)
7433aa984aeSLarsGit223    {
744ffec1009SMichael Hamann        global $ID;
745ffec1009SMichael Hamann
746faf3f01bSAndreas Gohr        [$src] = explode('#', $src, 2);
7473aa984aeSLarsGit223        if (media_isexternal($src)) {
7483aa984aeSLarsGit223            return;
7493aa984aeSLarsGit223        }
750faf3f01bSAndreas Gohr        $src = (new MediaResolver($ID))->resolveId($src);
7518c6be208SAndreas Gohr        $file = mediaFN($src);
7528c6be208SAndreas Gohr        $this->meta['relation']['media'][$src] = file_exists($file);
753ffec1009SMichael Hamann    }
75493075b01SAndreas Gohr
75593075b01SAndreas Gohr    #endregion
75639a89382SEsther Brunner}
75739a89382SEsther Brunner
758e3776c06SMichael Hamann//Setup VIM: ex: et ts=4 :
759