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