xref: /dokuwiki/inc/parser/metadata.php (revision b1a9a7addb625755af19900df6d0fba816dce1c3)
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 */
2174981a4eSAndreas Gohr    public const ABSTRACT_LEN = 250;
2217076c2aSAndreas Gohr
2317076c2aSAndreas Gohr    /** the maximum UTF8 character length for the abstract */
2474981a4eSAndreas 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        }
111*b1a9a7adSKazutaka Miyasaka
112*b1a9a7adSKazutaka Miyasaka        $this->doc = '';
11339a89382SEsther Brunner    }
11439a89382SEsther Brunner
11593075b01SAndreas Gohr    /**
11617076c2aSAndreas Gohr     * Render plain text data
11717076c2aSAndreas Gohr     *
11817076c2aSAndreas Gohr     * This function takes care of the amount captured data and will stop capturing when
11917076c2aSAndreas Gohr     * enough abstract data is available
12017076c2aSAndreas Gohr     *
12117076c2aSAndreas Gohr     * @param $text
12217076c2aSAndreas Gohr     */
1233aa984aeSLarsGit223    public function cdata($text)
1243aa984aeSLarsGit223    {
1253aa984aeSLarsGit223        if (!$this->capture || !$this->capturing) {
1263aa984aeSLarsGit223            return;
1273aa984aeSLarsGit223        }
12817076c2aSAndreas Gohr
12917076c2aSAndreas Gohr        $this->doc .= $text;
13017076c2aSAndreas Gohr
13117076c2aSAndreas Gohr        $this->captured += strlen($text);
1323aa984aeSLarsGit223        if ($this->captured > self::ABSTRACT_LEN) {
1333aa984aeSLarsGit223            $this->capture = false;
1343aa984aeSLarsGit223        }
13517076c2aSAndreas Gohr    }
13617076c2aSAndreas Gohr
13717076c2aSAndreas Gohr    /**
13893075b01SAndreas Gohr     * Add an item to the TOC
13993075b01SAndreas Gohr     *
14093075b01SAndreas Gohr     * @param string $id the hash link
14193075b01SAndreas Gohr     * @param string $text the text to display
14293075b01SAndreas Gohr     * @param int $level the nesting level
14393075b01SAndreas Gohr     */
1443aa984aeSLarsGit223    public function toc_additem($id, $text, $level)
1453aa984aeSLarsGit223    {
14639a89382SEsther Brunner        global $conf;
14739a89382SEsther Brunner
148e7856beaSchris        //only add items within configured levels
14939a89382SEsther Brunner        if ($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) {
15039a89382SEsther Brunner            // the TOC is one of our standard ul list arrays ;-)
151faf3f01bSAndreas Gohr            $this->meta['description']['tableofcontents'][] = [
152e7856beaSchris                'hid' => $id,
15339a89382SEsther Brunner                'title' => $text,
15439a89382SEsther Brunner                'type' => 'ul',
15539a89382SEsther Brunner                'level' => $level - $conf['toptoclevel'] + 1
156faf3f01bSAndreas Gohr            ];
15739a89382SEsther Brunner        }
158e7856beaSchris    }
159e7856beaSchris
16093075b01SAndreas Gohr    /**
16193075b01SAndreas Gohr     * Render a heading
16293075b01SAndreas Gohr     *
16393075b01SAndreas Gohr     * @param string $text the text to display
16493075b01SAndreas Gohr     * @param int $level header level
16593075b01SAndreas Gohr     * @param int $pos byte position in the original source
16693075b01SAndreas Gohr     */
1673aa984aeSLarsGit223    public function header($text, $level, $pos)
1683aa984aeSLarsGit223    {
1693aa984aeSLarsGit223        if (!isset($this->meta['title'])) {
1703aa984aeSLarsGit223            $this->meta['title'] = $text;
1713aa984aeSLarsGit223        }
172e7856beaSchris
173e7856beaSchris        // add the header to the TOC
174e0c26282SGerrit Uitslag        $hid = $this->_headerToLink($text, true);
175e7856beaSchris        $this->toc_additem($hid, $text, $level);
176e7856beaSchris
17739a89382SEsther Brunner        // add to summary
17817076c2aSAndreas Gohr        $this->cdata(DOKU_LF . $text . DOKU_LF);
17939a89382SEsther Brunner    }
18039a89382SEsther Brunner
18193075b01SAndreas Gohr    /**
18293075b01SAndreas Gohr     * Open a paragraph
18393075b01SAndreas Gohr     */
1843aa984aeSLarsGit223    public function p_open()
1853aa984aeSLarsGit223    {
18617076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
18739a89382SEsther Brunner    }
18839a89382SEsther Brunner
18993075b01SAndreas Gohr    /**
19093075b01SAndreas Gohr     * Close a paragraph
19193075b01SAndreas Gohr     */
1923aa984aeSLarsGit223    public function p_close()
1933aa984aeSLarsGit223    {
19417076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
19539a89382SEsther Brunner    }
19639a89382SEsther Brunner
19793075b01SAndreas Gohr    /**
19893075b01SAndreas Gohr     * Create a line break
19993075b01SAndreas Gohr     */
2003aa984aeSLarsGit223    public function linebreak()
2013aa984aeSLarsGit223    {
20217076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
20339a89382SEsther Brunner    }
20439a89382SEsther Brunner
20593075b01SAndreas Gohr    /**
20693075b01SAndreas Gohr     * Create a horizontal line
20793075b01SAndreas Gohr     */
2083aa984aeSLarsGit223    public function hr()
2093aa984aeSLarsGit223    {
21017076c2aSAndreas Gohr        $this->cdata(DOKU_LF . '----------' . DOKU_LF);
21139a89382SEsther Brunner    }
21239a89382SEsther Brunner
21339a89382SEsther Brunner    /**
21439a89382SEsther Brunner     * Callback for footnote start syntax
21539a89382SEsther Brunner     *
21639a89382SEsther Brunner     * All following content will go to the footnote instead of
21739a89382SEsther Brunner     * the document. To achieve this the previous rendered content
21839a89382SEsther Brunner     * is moved to $store and $doc is cleared
21939a89382SEsther Brunner     *
22039a89382SEsther Brunner     * @author Andreas Gohr <andi@splitbrain.org>
22139a89382SEsther Brunner     */
2223aa984aeSLarsGit223    public function footnote_open()
2233aa984aeSLarsGit223    {
22439a89382SEsther Brunner        if ($this->capture) {
225b8f47726SChristopher Smith            // move current content to store
226b8f47726SChristopher Smith            // this is required to ensure safe behaviour of plugins accessed within footnotes
22739a89382SEsther Brunner            $this->store = $this->doc;
22839a89382SEsther Brunner            $this->doc = '';
229b8f47726SChristopher Smith
230b8f47726SChristopher Smith            // disable capturing
231b8f47726SChristopher Smith            $this->capturing = false;
23239a89382SEsther Brunner        }
23339a89382SEsther Brunner    }
23439a89382SEsther Brunner
23539a89382SEsther Brunner    /**
23639a89382SEsther Brunner     * Callback for footnote end syntax
23739a89382SEsther Brunner     *
238b8f47726SChristopher Smith     * All content rendered whilst within footnote syntax mode is discarded,
239b8f47726SChristopher Smith     * the previously rendered content is restored and capturing is re-enabled.
24039a89382SEsther Brunner     *
24139a89382SEsther Brunner     * @author Andreas Gohr
24239a89382SEsther Brunner     */
2433aa984aeSLarsGit223    public function footnote_close()
2443aa984aeSLarsGit223    {
24539a89382SEsther Brunner        if ($this->capture) {
246b8f47726SChristopher Smith            // re-enable capturing
247b8f47726SChristopher Smith            $this->capturing = true;
248b8f47726SChristopher Smith            // restore previously rendered content
24939a89382SEsther Brunner            $this->doc = $this->store;
25039a89382SEsther Brunner            $this->store = '';
25139a89382SEsther Brunner        }
25239a89382SEsther Brunner    }
25339a89382SEsther Brunner
25493075b01SAndreas Gohr    /**
25593075b01SAndreas Gohr     * Open an unordered list
25693075b01SAndreas Gohr     */
2573aa984aeSLarsGit223    public function listu_open()
2583aa984aeSLarsGit223    {
25917076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
26039a89382SEsther Brunner    }
26139a89382SEsther Brunner
26293075b01SAndreas Gohr    /**
26393075b01SAndreas Gohr     * Open an ordered list
26493075b01SAndreas Gohr     */
2653aa984aeSLarsGit223    public function listo_open()
2663aa984aeSLarsGit223    {
26717076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
26839a89382SEsther Brunner    }
26939a89382SEsther Brunner
27093075b01SAndreas Gohr    /**
27193075b01SAndreas Gohr     * Open a list item
27293075b01SAndreas Gohr     *
27393075b01SAndreas Gohr     * @param int $level the nesting level
274e3a24861SChristopher Smith     * @param bool $node true when a node; false when a leaf
27593075b01SAndreas Gohr     */
2763aa984aeSLarsGit223    public function listitem_open($level, $node = false)
2773aa984aeSLarsGit223    {
27817076c2aSAndreas Gohr        $this->cdata(str_repeat(DOKU_TAB, $level) . '* ');
27939a89382SEsther Brunner    }
28039a89382SEsther Brunner
28193075b01SAndreas Gohr    /**
28293075b01SAndreas Gohr     * Close a list item
28393075b01SAndreas Gohr     */
2843aa984aeSLarsGit223    public function listitem_close()
2853aa984aeSLarsGit223    {
28617076c2aSAndreas Gohr        $this->cdata(DOKU_LF);
28739a89382SEsther Brunner    }
28839a89382SEsther Brunner
28993075b01SAndreas Gohr    /**
29093075b01SAndreas Gohr     * Output preformatted text
29193075b01SAndreas Gohr     *
29293075b01SAndreas Gohr     * @param string $text
29393075b01SAndreas Gohr     */
2943aa984aeSLarsGit223    public function preformatted($text)
2953aa984aeSLarsGit223    {
29617076c2aSAndreas Gohr        $this->cdata($text);
29739a89382SEsther Brunner    }
29839a89382SEsther Brunner
29993075b01SAndreas Gohr    /**
30093075b01SAndreas Gohr     * Start a block quote
30193075b01SAndreas Gohr     */
3023aa984aeSLarsGit223    public function quote_open()
3033aa984aeSLarsGit223    {
30417076c2aSAndreas Gohr        $this->cdata(DOKU_LF . DOKU_TAB . '"');
30539a89382SEsther Brunner    }
30639a89382SEsther Brunner
30793075b01SAndreas Gohr    /**
30893075b01SAndreas Gohr     * Stop a block quote
30993075b01SAndreas Gohr     */
3103aa984aeSLarsGit223    public function quote_close()
3113aa984aeSLarsGit223    {
31217076c2aSAndreas Gohr        $this->cdata('"' . DOKU_LF);
31339a89382SEsther Brunner    }
31439a89382SEsther Brunner
31593075b01SAndreas Gohr    /**
31693075b01SAndreas Gohr     * Display text as file content, optionally syntax highlighted
31793075b01SAndreas Gohr     *
31893075b01SAndreas Gohr     * @param string $text text to show
31993075b01SAndreas Gohr     * @param string $lang programming language to use for syntax highlighting
32093075b01SAndreas Gohr     * @param string $file file path label
32193075b01SAndreas Gohr     */
3223aa984aeSLarsGit223    public function file($text, $lang = null, $file = null)
3233aa984aeSLarsGit223    {
32417076c2aSAndreas Gohr        $this->cdata(DOKU_LF . $text . DOKU_LF);
32593075b01SAndreas Gohr    }
32693075b01SAndreas Gohr
32793075b01SAndreas Gohr    /**
32893075b01SAndreas Gohr     * Display text as code content, optionally syntax highlighted
32993075b01SAndreas Gohr     *
33093075b01SAndreas Gohr     * @param string $text text to show
33193075b01SAndreas Gohr     * @param string $language programming language to use for syntax highlighting
33293075b01SAndreas Gohr     * @param string $file file path label
33393075b01SAndreas Gohr     */
3343aa984aeSLarsGit223    public function code($text, $language = null, $file = null)
3353aa984aeSLarsGit223    {
33617076c2aSAndreas Gohr        $this->cdata(DOKU_LF . $text . DOKU_LF);
33739a89382SEsther Brunner    }
33839a89382SEsther Brunner
33993075b01SAndreas Gohr    /**
34093075b01SAndreas Gohr     * Format an acronym
34193075b01SAndreas Gohr     *
34293075b01SAndreas Gohr     * Uses $this->acronyms
34393075b01SAndreas Gohr     *
34493075b01SAndreas Gohr     * @param string $acronym
34593075b01SAndreas Gohr     */
3463aa984aeSLarsGit223    public function acronym($acronym)
3473aa984aeSLarsGit223    {
34817076c2aSAndreas Gohr        $this->cdata($acronym);
34939a89382SEsther Brunner    }
35039a89382SEsther Brunner
35193075b01SAndreas Gohr    /**
35293075b01SAndreas Gohr     * Format a smiley
35393075b01SAndreas Gohr     *
35493075b01SAndreas Gohr     * Uses $this->smiley
35593075b01SAndreas Gohr     *
35693075b01SAndreas Gohr     * @param string $smiley
35793075b01SAndreas Gohr     */
3583aa984aeSLarsGit223    public function smiley($smiley)
3593aa984aeSLarsGit223    {
36017076c2aSAndreas Gohr        $this->cdata($smiley);
36139a89382SEsther Brunner    }
36239a89382SEsther Brunner
36393075b01SAndreas Gohr    /**
36493075b01SAndreas Gohr     * Format an entity
36593075b01SAndreas Gohr     *
36693075b01SAndreas Gohr     * Entities are basically small text replacements
36793075b01SAndreas Gohr     *
36893075b01SAndreas Gohr     * Uses $this->entities
36993075b01SAndreas Gohr     *
37093075b01SAndreas Gohr     * @param string $entity
37193075b01SAndreas Gohr     */
3723aa984aeSLarsGit223    public function entity($entity)
3733aa984aeSLarsGit223    {
37417076c2aSAndreas Gohr        $this->cdata($entity);
37539a89382SEsther Brunner    }
37639a89382SEsther Brunner
37793075b01SAndreas Gohr    /**
37893075b01SAndreas Gohr     * Typographically format a multiply sign
37993075b01SAndreas Gohr     *
38093075b01SAndreas Gohr     * Example: ($x=640, $y=480) should result in "640×480"
38193075b01SAndreas Gohr     *
38293075b01SAndreas Gohr     * @param string|int $x first value
38393075b01SAndreas Gohr     * @param string|int $y second value
38493075b01SAndreas Gohr     */
3853aa984aeSLarsGit223    public function multiplyentity($x, $y)
3863aa984aeSLarsGit223    {
38717076c2aSAndreas Gohr        $this->cdata($x . '×' . $y);
38839a89382SEsther Brunner    }
38939a89382SEsther Brunner
39093075b01SAndreas Gohr    /**
39193075b01SAndreas Gohr     * Render an opening single quote char (language specific)
39293075b01SAndreas Gohr     */
3933aa984aeSLarsGit223    public function singlequoteopening()
3943aa984aeSLarsGit223    {
39571b40da2SAnika Henke        global $lang;
39617076c2aSAndreas Gohr        $this->cdata($lang['singlequoteopening']);
39739a89382SEsther Brunner    }
39839a89382SEsther Brunner
39993075b01SAndreas Gohr    /**
40093075b01SAndreas Gohr     * Render a closing single quote char (language specific)
40193075b01SAndreas Gohr     */
4023aa984aeSLarsGit223    public function singlequoteclosing()
4033aa984aeSLarsGit223    {
40471b40da2SAnika Henke        global $lang;
40517076c2aSAndreas Gohr        $this->cdata($lang['singlequoteclosing']);
40639a89382SEsther Brunner    }
40739a89382SEsther Brunner
40893075b01SAndreas Gohr    /**
40993075b01SAndreas Gohr     * Render an apostrophe char (language specific)
41093075b01SAndreas Gohr     */
4113aa984aeSLarsGit223    public function apostrophe()
4123aa984aeSLarsGit223    {
41357d757d1SAndreas Gohr        global $lang;
41417076c2aSAndreas Gohr        $this->cdata($lang['apostrophe']);
41557d757d1SAndreas Gohr    }
41657d757d1SAndreas Gohr
41793075b01SAndreas Gohr    /**
41893075b01SAndreas Gohr     * Render an opening double quote char (language specific)
41993075b01SAndreas Gohr     */
4203aa984aeSLarsGit223    public function doublequoteopening()
4213aa984aeSLarsGit223    {
42271b40da2SAnika Henke        global $lang;
42317076c2aSAndreas Gohr        $this->cdata($lang['doublequoteopening']);
42439a89382SEsther Brunner    }
42539a89382SEsther Brunner
42693075b01SAndreas Gohr    /**
42793075b01SAndreas Gohr     * Render an closinging double quote char (language specific)
42893075b01SAndreas Gohr     */
4293aa984aeSLarsGit223    public function doublequoteclosing()
4303aa984aeSLarsGit223    {
43171b40da2SAnika Henke        global $lang;
43217076c2aSAndreas Gohr        $this->cdata($lang['doublequoteclosing']);
43339a89382SEsther Brunner    }
43439a89382SEsther Brunner
43593075b01SAndreas Gohr    /**
43693075b01SAndreas Gohr     * Render a CamelCase link
43793075b01SAndreas Gohr     *
43893075b01SAndreas Gohr     * @param string $link The link name
43993075b01SAndreas Gohr     * @see http://en.wikipedia.org/wiki/CamelCase
44093075b01SAndreas Gohr     */
4413aa984aeSLarsGit223    public function camelcaselink($link)
4423aa984aeSLarsGit223    {
44339a89382SEsther Brunner        $this->internallink($link, $link);
44439a89382SEsther Brunner    }
44539a89382SEsther Brunner
44693075b01SAndreas Gohr    /**
44793075b01SAndreas Gohr     * Render a page local link
44893075b01SAndreas Gohr     *
44993075b01SAndreas Gohr     * @param string $hash hash link identifier
45093075b01SAndreas Gohr     * @param string $name name for the link
45193075b01SAndreas Gohr     */
4523aa984aeSLarsGit223    public function locallink($hash, $name = null)
4533aa984aeSLarsGit223    {
4549269d0b1SMichael Hamann        if (is_array($name)) {
4559269d0b1SMichael Hamann            $this->_firstimage($name['src']);
4563aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
4573aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
4583aa984aeSLarsGit223            }
4599269d0b1SMichael Hamann        }
4609269d0b1SMichael Hamann    }
46139a89382SEsther Brunner
46239a89382SEsther Brunner    /**
46339a89382SEsther Brunner     * keep track of internal links in $this->meta['relation']['references']
46493075b01SAndreas Gohr     *
46593075b01SAndreas Gohr     * @param string $id page ID to link to. eg. 'wiki:syntax'
46659bc3b48SGerrit Uitslag     * @param string|array|null $name name for the link, array for media file
46739a89382SEsther Brunner     */
4683aa984aeSLarsGit223    public function internallink($id, $name = null)
4693aa984aeSLarsGit223    {
47039a89382SEsther Brunner        global $ID;
47139a89382SEsther Brunner
472ffec1009SMichael Hamann        if (is_array($name)) {
473aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
4743aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
4753aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
4763aa984aeSLarsGit223            }
477ffec1009SMichael Hamann        }
478aa5a2937SAndreas Gohr
47966d935e7SMichael Hamann        $parts = explode('?', $id, 2);
48066d935e7SMichael Hamann        if (count($parts) === 2) {
48166d935e7SMichael Hamann            $id = $parts[0];
48266d935e7SMichael Hamann        }
48366d935e7SMichael Hamann
48439a89382SEsther Brunner        $default = $this->_simpleTitle($id);
48539a89382SEsther Brunner
48639a89382SEsther Brunner        // first resolve and clean up the $id
487faf3f01bSAndreas Gohr        $resolver = new PageResolver($ID);
4888c6be208SAndreas Gohr        $id = $resolver->resolveId($id);
489faf3f01bSAndreas Gohr        [$page] = sexplode('#', $id, 2);
49039a89382SEsther Brunner
49139a89382SEsther Brunner        // set metadata
4928c6be208SAndreas Gohr        $this->meta['relation']['references'][$page] = page_exists($page);
49339a89382SEsther Brunner        // $data = array('relation' => array('isreferencedby' => array($ID => true)));
49439a89382SEsther Brunner        // p_set_metadata($id, $data);
49539a89382SEsther Brunner
49639a89382SEsther Brunner        // add link title to summary
49739a89382SEsther Brunner        if ($this->capture) {
49839a89382SEsther Brunner            $name = $this->_getLinkTitle($name, $default, $id);
49939a89382SEsther Brunner            $this->doc .= $name;
50039a89382SEsther Brunner        }
50139a89382SEsther Brunner    }
50239a89382SEsther Brunner
50393075b01SAndreas Gohr    /**
50493075b01SAndreas Gohr     * Render an external link
50593075b01SAndreas Gohr     *
50693075b01SAndreas Gohr     * @param string $url full URL with scheme
50759bc3b48SGerrit Uitslag     * @param string|array|null $name name for the link, array for media file
50893075b01SAndreas Gohr     */
5093aa984aeSLarsGit223    public function externallink($url, $name = null)
5103aa984aeSLarsGit223    {
511ffec1009SMichael Hamann        if (is_array($name)) {
512aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5133aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5143aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5153aa984aeSLarsGit223            }
516ffec1009SMichael Hamann        }
517aa5a2937SAndreas Gohr
51839a89382SEsther Brunner        if ($this->capture) {
519a2ea2dc1SAdrian Lang            $this->doc .= $this->_getLinkTitle($name, '<' . $url . '>');
52039a89382SEsther Brunner        }
52139a89382SEsther Brunner    }
52239a89382SEsther Brunner
52393075b01SAndreas Gohr    /**
52493075b01SAndreas Gohr     * Render an interwiki link
52593075b01SAndreas Gohr     *
52693075b01SAndreas Gohr     * You may want to use $this->_resolveInterWiki() here
52793075b01SAndreas Gohr     *
52893075b01SAndreas Gohr     * @param string $match original link - probably not much use
52993075b01SAndreas Gohr     * @param string|array $name name for the link, array for media file
53093075b01SAndreas Gohr     * @param string $wikiName indentifier (shortcut) for the remote wiki
53193075b01SAndreas Gohr     * @param string $wikiUri the fragment parsed from the original link
53293075b01SAndreas Gohr     */
5333aa984aeSLarsGit223    public function interwikilink($match, $name, $wikiName, $wikiUri)
5343aa984aeSLarsGit223    {
535ffec1009SMichael Hamann        if (is_array($name)) {
536aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5373aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5383aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5393aa984aeSLarsGit223            }
540ffec1009SMichael Hamann        }
541aa5a2937SAndreas Gohr
54239a89382SEsther Brunner        if ($this->capture) {
543faf3f01bSAndreas Gohr            [$wikiUri] = explode('#', $wikiUri, 2);
544a2ea2dc1SAdrian Lang            $name = $this->_getLinkTitle($name, $wikiUri);
54539a89382SEsther Brunner            $this->doc .= $name;
54639a89382SEsther Brunner        }
54739a89382SEsther Brunner    }
54839a89382SEsther Brunner
54993075b01SAndreas Gohr    /**
55093075b01SAndreas Gohr     * Link to windows share
55193075b01SAndreas Gohr     *
55293075b01SAndreas Gohr     * @param string $url the link
55393075b01SAndreas Gohr     * @param string|array $name name for the link, array for media file
55493075b01SAndreas Gohr     */
5553aa984aeSLarsGit223    public function windowssharelink($url, $name = null)
5563aa984aeSLarsGit223    {
557ffec1009SMichael Hamann        if (is_array($name)) {
558aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5593aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5603aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5613aa984aeSLarsGit223            }
562ffec1009SMichael Hamann        }
563aa5a2937SAndreas Gohr
56439a89382SEsther Brunner        if ($this->capture) {
5653aa984aeSLarsGit223            if ($name) {
5663aa984aeSLarsGit223                $this->doc .= $name;
5673aa984aeSLarsGit223            } else {
5683aa984aeSLarsGit223                $this->doc .= '<' . $url . '>';
5693aa984aeSLarsGit223            }
57039a89382SEsther Brunner        }
57139a89382SEsther Brunner    }
57239a89382SEsther Brunner
57393075b01SAndreas Gohr    /**
57493075b01SAndreas Gohr     * Render a linked E-Mail Address
57593075b01SAndreas Gohr     *
57693075b01SAndreas Gohr     * Should honor $conf['mailguard'] setting
57793075b01SAndreas Gohr     *
57893075b01SAndreas Gohr     * @param string $address Email-Address
57993075b01SAndreas Gohr     * @param string|array $name name for the link, array for media file
58093075b01SAndreas Gohr     */
5813aa984aeSLarsGit223    public function emaillink($address, $name = null)
5823aa984aeSLarsGit223    {
583ffec1009SMichael Hamann        if (is_array($name)) {
584aa5a2937SAndreas Gohr            $this->_firstimage($name['src']);
5853aa984aeSLarsGit223            if ($name['type'] == 'internalmedia') {
5863aa984aeSLarsGit223                $this->_recordMediaUsage($name['src']);
5873aa984aeSLarsGit223            }
588ffec1009SMichael Hamann        }
589aa5a2937SAndreas Gohr
59039a89382SEsther Brunner        if ($this->capture) {
5913aa984aeSLarsGit223            if ($name) {
5923aa984aeSLarsGit223                $this->doc .= $name;
5933aa984aeSLarsGit223            } else {
5943aa984aeSLarsGit223                $this->doc .= '<' . $address . '>';
5953aa984aeSLarsGit223            }
59639a89382SEsther Brunner        }
59739a89382SEsther Brunner    }
59839a89382SEsther Brunner
59993075b01SAndreas Gohr    /**
60093075b01SAndreas Gohr     * Render an internal media file
60193075b01SAndreas Gohr     *
60293075b01SAndreas Gohr     * @param string $src media ID
60393075b01SAndreas Gohr     * @param string $title descriptive text
60493075b01SAndreas Gohr     * @param string $align left|center|right
60593075b01SAndreas Gohr     * @param int $width width of media in pixel
60693075b01SAndreas Gohr     * @param int $height height of media in pixel
60793075b01SAndreas Gohr     * @param string $cache cache|recache|nocache
60893075b01SAndreas Gohr     * @param string $linking linkonly|detail|nolink
60993075b01SAndreas Gohr     */
61095078f23SAndreas Gohr    public function internalmedia(
61195078f23SAndreas Gohr        $src,
61295078f23SAndreas Gohr        $title = null,
61395078f23SAndreas Gohr        $align = null,
61495078f23SAndreas Gohr        $width = null,
61595078f23SAndreas Gohr        $height = null,
61695078f23SAndreas Gohr        $cache = null,
61795078f23SAndreas Gohr        $linking = null
61895078f23SAndreas Gohr    ) {
6193aa984aeSLarsGit223        if ($this->capture && $title) {
6203aa984aeSLarsGit223            $this->doc .= '[' . $title . ']';
6213aa984aeSLarsGit223        }
622aa5a2937SAndreas Gohr        $this->_firstimage($src);
623ffec1009SMichael Hamann        $this->_recordMediaUsage($src);
62439a89382SEsther Brunner    }
62539a89382SEsther Brunner
62693075b01SAndreas Gohr    /**
62793075b01SAndreas Gohr     * Render an external media file
62893075b01SAndreas Gohr     *
62993075b01SAndreas Gohr     * @param string $src full media URL
63093075b01SAndreas Gohr     * @param string $title descriptive text
63193075b01SAndreas Gohr     * @param string $align left|center|right
63293075b01SAndreas Gohr     * @param int $width width of media in pixel
63393075b01SAndreas Gohr     * @param int $height height of media in pixel
63493075b01SAndreas Gohr     * @param string $cache cache|recache|nocache
63593075b01SAndreas Gohr     * @param string $linking linkonly|detail|nolink
63693075b01SAndreas Gohr     */
63795078f23SAndreas Gohr    public function externalmedia(
63895078f23SAndreas Gohr        $src,
63995078f23SAndreas Gohr        $title = null,
64095078f23SAndreas Gohr        $align = null,
64195078f23SAndreas Gohr        $width = null,
64295078f23SAndreas Gohr        $height = null,
64395078f23SAndreas Gohr        $cache = null,
64495078f23SAndreas Gohr        $linking = null
64595078f23SAndreas Gohr    ) {
6463aa984aeSLarsGit223        if ($this->capture && $title) {
6473aa984aeSLarsGit223            $this->doc .= '[' . $title . ']';
6483aa984aeSLarsGit223        }
649aa5a2937SAndreas Gohr        $this->_firstimage($src);
65039a89382SEsther Brunner    }
65139a89382SEsther Brunner
65293075b01SAndreas Gohr    /**
65393075b01SAndreas Gohr     * Render the output of an RSS feed
65493075b01SAndreas Gohr     *
65593075b01SAndreas Gohr     * @param string $url URL of the feed
65693075b01SAndreas Gohr     * @param array $params Finetuning of the output
65793075b01SAndreas Gohr     */
6583aa984aeSLarsGit223    public function rss($url, $params)
6593aa984aeSLarsGit223    {
660ce6b63d9Schris        $this->meta['relation']['haspart'][$url] = true;
66164e9144aSchris
66264e9144aSchris        $this->meta['date']['valid']['age'] =
66364e9144aSchris            isset($this->meta['date']['valid']['age']) ?
66464e9144aSchris                min($this->meta['date']['valid']['age'], $params['refresh']) :
66564e9144aSchris                $params['refresh'];
666ce6b63d9Schris    }
66739a89382SEsther Brunner
66893075b01SAndreas Gohr    #region Utils
66939a89382SEsther Brunner
67039a89382SEsther Brunner    /**
67139a89382SEsther Brunner     * Removes any Namespace from the given name but keeps
67239a89382SEsther Brunner     * casing and special chars
67339a89382SEsther Brunner     *
674f50a239bSTakamura     * @param string $name
675f50a239bSTakamura     *
676f50a239bSTakamura     * @return mixed|string
677faf3f01bSAndreas Gohr     * @author Andreas Gohr <andi@splitbrain.org>
678faf3f01bSAndreas Gohr     *
67939a89382SEsther Brunner     */
6803aa984aeSLarsGit223    public function _simpleTitle($name)
6813aa984aeSLarsGit223    {
68239a89382SEsther Brunner        global $conf;
68339a89382SEsther Brunner
6843aa984aeSLarsGit223        if (is_array($name)) {
6853aa984aeSLarsGit223            return '';
6863aa984aeSLarsGit223        }
6879bee852eSAndreas Gohr
68839a89382SEsther Brunner        if ($conf['useslash']) {
68939a89382SEsther Brunner            $nssep = '[:;/]';
69039a89382SEsther Brunner        } else {
69139a89382SEsther Brunner            $nssep = '[:;]';
69239a89382SEsther Brunner        }
69339a89382SEsther Brunner        $name = preg_replace('!.*' . $nssep . '!', '', $name);
6943be6e394Schris        //if there is a hash we use the anchor name only
69539a89382SEsther Brunner        $name = preg_replace('!.*#!', '', $name);
69639a89382SEsther Brunner        return $name;
69739a89382SEsther Brunner    }
69839a89382SEsther Brunner
69939a89382SEsther Brunner    /**
70039a89382SEsther Brunner     * Construct a title and handle images in titles
70139a89382SEsther Brunner     *
70259bc3b48SGerrit Uitslag     * @param string|array|null $title either string title or media array
70393075b01SAndreas Gohr     * @param string $default default title if nothing else is found
70493075b01SAndreas Gohr     * @param null|string $id linked page id (used to extract title from first heading)
70593075b01SAndreas Gohr     * @return string title text
706faf3f01bSAndreas Gohr     * @author Harry Fuecks <hfuecks@gmail.com>
70739a89382SEsther Brunner     */
7083aa984aeSLarsGit223    public function _getLinkTitle($title, $default, $id = null)
7093aa984aeSLarsGit223    {
71085038eabSDanny        if (is_array($title)) {
71193075b01SAndreas Gohr            if ($title['title']) {
71293075b01SAndreas Gohr                return '[' . $title['title'] . ']';
71393075b01SAndreas Gohr            } else {
71493075b01SAndreas Gohr                return $default;
71593075b01SAndreas Gohr            }
71685038eabSDanny        } elseif (is_null($title) || trim($title) == '') {
717fe9ec250SChris Smith            if (useHeading('content') && $id) {
71820f04039SDanny                $heading = p_get_first_heading($id, METADATA_DONT_RENDER);
7193aa984aeSLarsGit223                if ($heading) {
7203aa984aeSLarsGit223                    return $heading;
7213aa984aeSLarsGit223                }
72239a89382SEsther Brunner            }
72339a89382SEsther Brunner            return $default;
72485038eabSDanny        } else {
72539a89382SEsther Brunner            return $title;
72639a89382SEsther Brunner        }
72739a89382SEsther Brunner    }
72839a89382SEsther Brunner
72993075b01SAndreas Gohr    /**
73093075b01SAndreas Gohr     * Remember first image
73193075b01SAndreas Gohr     *
73293075b01SAndreas Gohr     * @param string $src image URL or ID
73393075b01SAndreas Gohr     */
7343aa984aeSLarsGit223    protected function _firstimage($src)
7353aa984aeSLarsGit223    {
736aa5a2937SAndreas Gohr        global $ID;
737aa5a2937SAndreas Gohr
7383aa984aeSLarsGit223        if ($this->firstimage) {
7393aa984aeSLarsGit223            return;
7403aa984aeSLarsGit223        }
7413aa984aeSLarsGit223
742faf3f01bSAndreas Gohr        [$src] = explode('#', $src, 2);
7433e7e6067SKlap-in        if (!media_isexternal($src)) {
744faf3f01bSAndreas Gohr            $src = (new MediaResolver($ID))->resolveId($src);
745aa5a2937SAndreas Gohr        }
74629d63aa5SAndreas Gohr        if (preg_match('/.(jpe?g|gif|png|webp|svg)$/i', $src)) {
747aa5a2937SAndreas Gohr            $this->firstimage = $src;
748aa5a2937SAndreas Gohr        }
749aa5a2937SAndreas Gohr    }
750ffec1009SMichael Hamann
75193075b01SAndreas Gohr    /**
75293075b01SAndreas Gohr     * Store list of used media files in metadata
75393075b01SAndreas Gohr     *
75493075b01SAndreas Gohr     * @param string $src media ID
75593075b01SAndreas Gohr     */
7563aa984aeSLarsGit223    protected function _recordMediaUsage($src)
7573aa984aeSLarsGit223    {
758ffec1009SMichael Hamann        global $ID;
759ffec1009SMichael Hamann
760faf3f01bSAndreas Gohr        [$src] = explode('#', $src, 2);
7613aa984aeSLarsGit223        if (media_isexternal($src)) {
7623aa984aeSLarsGit223            return;
7633aa984aeSLarsGit223        }
764faf3f01bSAndreas Gohr        $src = (new MediaResolver($ID))->resolveId($src);
7658c6be208SAndreas Gohr        $file = mediaFN($src);
7668c6be208SAndreas Gohr        $this->meta['relation']['media'][$src] = file_exists($file);
767ffec1009SMichael Hamann    }
76893075b01SAndreas Gohr
76993075b01SAndreas Gohr    #endregion
77039a89382SEsther Brunner}
77139a89382SEsther Brunner
772e3776c06SMichael Hamann//Setup VIM: ex: et ts=4 :
773