139a89382SEsther Brunner<?php 2*faf3f01bSAndreas Gohr 3*faf3f01bSAndreas Gohruse dokuwiki\File\MediaResolver; 4*faf3f01bSAndreas Gohruse dokuwiki\File\PageResolver; 5*faf3f01bSAndreas Gohruse dokuwiki\Utf8\PhpString; 6*faf3f01bSAndreas 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 */ 2117076c2aSAndreas Gohr const ABSTRACT_LEN = 250; 2217076c2aSAndreas Gohr 2317076c2aSAndreas Gohr /** the maximum UTF8 character length for the abstract */ 2417076c2aSAndreas Gohr const ABSTRACT_MAX = 500; 2539a89382SEsther Brunner 2693075b01SAndreas Gohr /** @var array transient meta data, will be reset on each rendering */ 27*faf3f01bSAndreas Gohr public $meta = []; 2839a89382SEsther Brunner 2993075b01SAndreas Gohr /** @var array persistent meta data, will be kept until explicitly deleted */ 30*faf3f01bSAndreas Gohr public $persistent = []; 3139a89382SEsther Brunner 3293075b01SAndreas Gohr /** @var array the list of headers used to create unique link ids */ 33*faf3f01bSAndreas 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 69*faf3f01bSAndreas 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) { 101*faf3f01bSAndreas 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 ;-) 149*faf3f01bSAndreas Gohr $this->meta['description']['tableofcontents'][] = [ 150e7856beaSchris 'hid' => $id, 15139a89382SEsther Brunner 'title' => $text, 15239a89382SEsther Brunner 'type' => 'ul', 15339a89382SEsther Brunner 'level' => $level - $conf['toptoclevel'] + 1 154*faf3f01bSAndreas 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 485*faf3f01bSAndreas Gohr $resolver = new PageResolver($ID); 4868c6be208SAndreas Gohr $id = $resolver->resolveId($id); 487*faf3f01bSAndreas 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) { 541*faf3f01bSAndreas 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 663*faf3f01bSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 664*faf3f01bSAndreas 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 692*faf3f01bSAndreas 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 728*faf3f01bSAndreas Gohr [$src] = explode('#', $src, 2); 7293e7e6067SKlap-in if (!media_isexternal($src)) { 730*faf3f01bSAndreas 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 746*faf3f01bSAndreas Gohr [$src] = explode('#', $src, 2); 7473aa984aeSLarsGit223 if (media_isexternal($src)) { 7483aa984aeSLarsGit223 return; 7493aa984aeSLarsGit223 } 750*faf3f01bSAndreas 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