xref: /dokuwiki/inc/parser/metadata.php (revision f0acc9bffc02e77fb1db1cf3aeea7034e024ad5c)
1<?php
2/**
3 * Renderer for metadata
4 *
5 * @author Esther Brunner <wikidesign@gmail.com>
6 */
7if(!defined('DOKU_INC')) die('meh.');
8
9if ( !defined('DOKU_LF') ) {
10    // Some whitespace to help View > Source
11    define ('DOKU_LF',"\n");
12}
13
14if ( !defined('DOKU_TAB') ) {
15    // Some whitespace to help View > Source
16    define ('DOKU_TAB',"\t");
17}
18
19require_once DOKU_INC . 'inc/parser/renderer.php';
20
21/**
22 * The Renderer
23 */
24class Doku_Renderer_metadata extends Doku_Renderer {
25
26  var $doc  = '';
27  var $meta = array();
28  var $persistent = array();
29
30  var $headers = array();
31  var $capture = true;
32  var $store   = '';
33  var $firstimage = '';
34
35  function getFormat(){
36    return 'metadata';
37  }
38
39  function document_start(){
40    global $ID;
41    // external pages are missing create date
42    if(!$this->persistent['date']['created']){
43        $this->persistent['date']['created'] = filectime(wikiFN($ID));
44    }
45    if(!isset($this->persistent['creator'])){
46        $this->persistent['creator'] = '';
47    }
48    // reset metadata to persistent values
49    $this->meta = $this->persistent;
50  }
51
52  function document_end(){
53    global $ID;
54
55    // store internal info in metadata (notoc,nocache)
56    $this->meta['internal'] = $this->info;
57
58    if (!$this->meta['description']['abstract']){
59      // cut off too long abstracts
60      $this->doc = trim($this->doc);
61      if (strlen($this->doc) > 500)
62        $this->doc = utf8_substr($this->doc, 0, 500).'…';
63      $this->meta['description']['abstract'] = $this->doc;
64    }
65
66    $this->meta['relation']['firstimage'] = $this->firstimage;
67
68    if(!$this->meta['date']['modified']){
69        $this->meta['date']['modified'] = filemtime(wikiFN($ID));
70    }
71
72  }
73
74  function toc_additem($id, $text, $level) {
75    global $conf;
76
77    //only add items within configured levels
78    if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']){
79      // the TOC is one of our standard ul list arrays ;-)
80      $this->meta['description']['tableofcontents'][] = array(
81        'hid'   => $id,
82        'title' => $text,
83        'type'  => 'ul',
84        'level' => $level-$conf['toptoclevel']+1
85      );
86    }
87
88  }
89
90  function header($text, $level, $pos) {
91    if (!$this->meta['title']) $this->meta['title'] = $text;
92
93    // add the header to the TOC
94    $hid = $this->_headerToLink($text,'true');
95    $this->toc_additem($hid, $text, $level);
96
97    // add to summary
98    if ($this->capture && ($level > 1)) $this->doc .= DOKU_LF.$text.DOKU_LF;
99  }
100
101  function section_open($level){}
102  function section_close(){}
103
104  function cdata($text){
105    if ($this->capture) $this->doc .= $text;
106  }
107
108  function p_open(){
109    if ($this->capture) $this->doc .= DOKU_LF;
110  }
111
112  function p_close(){
113    if ($this->capture){
114      if (strlen($this->doc) > 250) $this->capture = false;
115      else $this->doc .= DOKU_LF;
116    }
117  }
118
119  function linebreak(){
120    if ($this->capture) $this->doc .= DOKU_LF;
121  }
122
123  function hr(){
124    if ($this->capture){
125      if (strlen($this->doc) > 250) $this->capture = false;
126      else $this->doc .= DOKU_LF.'----------'.DOKU_LF;
127    }
128  }
129
130  function strong_open(){}
131  function strong_close(){}
132
133  function emphasis_open(){}
134  function emphasis_close(){}
135
136  function underline_open(){}
137  function underline_close(){}
138
139  function monospace_open(){}
140  function monospace_close(){}
141
142  function subscript_open(){}
143  function subscript_close(){}
144
145  function superscript_open(){}
146  function superscript_close(){}
147
148  function deleted_open(){}
149  function deleted_close(){}
150
151  /**
152   * Callback for footnote start syntax
153   *
154   * All following content will go to the footnote instead of
155   * the document. To achieve this the previous rendered content
156   * is moved to $store and $doc is cleared
157   *
158   * @author Andreas Gohr <andi@splitbrain.org>
159   */
160  function footnote_open() {
161    if ($this->capture){
162      // move current content to store and record footnote
163      $this->store = $this->doc;
164      $this->doc   = '';
165    }
166  }
167
168  /**
169   * Callback for footnote end syntax
170   *
171   * All rendered content is moved to the $footnotes array and the old
172   * content is restored from $store again
173   *
174   * @author Andreas Gohr
175   */
176  function footnote_close() {
177    if ($this->capture){
178      // restore old content
179      $this->doc = $this->store;
180      $this->store = '';
181    }
182  }
183
184  function listu_open(){
185    if ($this->capture) $this->doc .= DOKU_LF;
186  }
187
188  function listu_close(){
189    if ($this->capture && (strlen($this->doc) > 250)) $this->capture = false;
190  }
191
192  function listo_open(){
193    if ($this->capture) $this->doc .= DOKU_LF;
194  }
195
196  function listo_close(){
197    if ($this->capture && (strlen($this->doc) > 250)) $this->capture = false;
198  }
199
200  function listitem_open($level){
201    if ($this->capture) $this->doc .= str_repeat(DOKU_TAB, $level).'* ';
202  }
203
204  function listitem_close(){
205    if ($this->capture) $this->doc .= DOKU_LF;
206  }
207
208  function listcontent_open(){}
209  function listcontent_close(){}
210
211  function unformatted($text){
212    if ($this->capture) $this->doc .= $text;
213  }
214
215  function php($text){}
216
217  function phpblock($text){}
218
219  function html($text){}
220
221  function htmlblock($text){}
222
223  function preformatted($text){
224    if ($this->capture) $this->doc .= $text;
225  }
226
227  function file($text){
228    if ($this->capture){
229      $this->doc .= DOKU_LF.$text;
230      if (strlen($this->doc) > 250) $this->capture = false;
231      else $this->doc .= DOKU_LF;
232    }
233  }
234
235  function quote_open(){
236    if ($this->capture) $this->doc .= DOKU_LF.DOKU_TAB.'"';
237  }
238
239  function quote_close(){
240    if ($this->capture){
241      $this->doc .= '"';
242      if (strlen($this->doc) > 250) $this->capture = false;
243      else $this->doc .= DOKU_LF;
244    }
245  }
246
247  function code($text, $language = NULL){
248    if ($this->capture){
249      $this->doc .= DOKU_LF.$text;
250      if (strlen($this->doc) > 250) $this->capture = false;
251      else $this->doc .= DOKU_LF;
252    }
253  }
254
255  function acronym($acronym){
256    if ($this->capture) $this->doc .= $acronym;
257  }
258
259  function smiley($smiley){
260    if ($this->capture) $this->doc .= $smiley;
261  }
262
263  function entity($entity){
264    if ($this->capture) $this->doc .= $entity;
265  }
266
267  function multiplyentity($x, $y){
268    if ($this->capture) $this->doc .= $x.'×'.$y;
269  }
270
271  function singlequoteopening(){
272    global $lang;
273    if ($this->capture) $this->doc .= $lang['singlequoteopening'];
274  }
275
276  function singlequoteclosing(){
277    global $lang;
278    if ($this->capture) $this->doc .= $lang['singlequoteclosing'];
279  }
280
281  function apostrophe() {
282    global $lang;
283    if ($this->capture) $this->doc .= $lang['apostrophe'];
284  }
285
286  function doublequoteopening(){
287    global $lang;
288    if ($this->capture) $this->doc .= $lang['doublequoteopening'];
289  }
290
291  function doublequoteclosing(){
292    global $lang;
293    if ($this->capture) $this->doc .= $lang['doublequoteclosing'];
294  }
295
296  function camelcaselink($link) {
297    $this->internallink($link, $link);
298  }
299
300  function locallink($hash, $name = NULL){}
301
302  /**
303   * keep track of internal links in $this->meta['relation']['references']
304   */
305  function internallink($id, $name = NULL){
306    global $ID;
307
308    if(is_array($name))
309        $this->_firstimage($name['src']);
310
311    $default = $this->_simpleTitle($id);
312
313    // first resolve and clean up the $id
314    resolve_pageid(getNS($ID), $id, $exists);
315    list($page, $hash) = split('#', $id, 2);
316
317    // set metadata
318    $this->meta['relation']['references'][$page] = $exists;
319    // $data = array('relation' => array('isreferencedby' => array($ID => true)));
320    // p_set_metadata($id, $data);
321
322    // add link title to summary
323    if ($this->capture){
324      $name = $this->_getLinkTitle($name, $default, $id);
325      $this->doc .= $name;
326    }
327  }
328
329  function externallink($url, $name = NULL){
330    if(is_array($name))
331        $this->_firstimage($name['src']);
332
333    if ($this->capture){
334      if ($name) $this->doc .= $name;
335      else $this->doc .= '<'.$url.'>';
336    }
337  }
338
339  function interwikilink($match, $name = NULL, $wikiName, $wikiUri){
340    if(is_array($name))
341        $this->_firstimage($name['src']);
342
343    if ($this->capture){
344      list($wikiUri, $hash) = explode('#', $wikiUri, 2);
345      $name = $this->_getLinkTitle($name, $wikiName.'>'.$wikiUri);
346      $this->doc .= $name;
347    }
348  }
349
350  function windowssharelink($url, $name = NULL){
351    if(is_array($name))
352        $this->_firstimage($name['src']);
353
354    if ($this->capture){
355      if ($name) $this->doc .= $name;
356      else $this->doc .= '<'.$url.'>';
357    }
358  }
359
360  function emaillink($address, $name = NULL){
361    if(is_array($name))
362        $this->_firstimage($name['src']);
363
364    if ($this->capture){
365      if ($name) $this->doc .= $name;
366      else $this->doc .= '<'.$address.'>';
367    }
368  }
369
370  function internalmedia($src, $title=NULL, $align=NULL, $width=NULL,
371                         $height=NULL, $cache=NULL, $linking=NULL){
372    if ($this->capture && $title) $this->doc .= '['.$title.']';
373    $this->_firstimage($src);
374  }
375
376  function externalmedia($src, $title=NULL, $align=NULL, $width=NULL,
377                         $height=NULL, $cache=NULL, $linking=NULL){
378    if ($this->capture && $title) $this->doc .= '['.$title.']';
379    $this->_firstimage($src);
380  }
381
382  function rss($url,$params) {
383    $this->meta['relation']['haspart'][$url] = true;
384
385    $this->meta['date']['valid']['age'] =
386            isset($this->meta['date']['valid']['age']) ?
387                min($this->meta['date']['valid']['age'],$params['refresh']) :
388                $params['refresh'];
389  }
390
391  function table_open($maxcols = NULL, $numrows = NULL){}
392  function table_close(){}
393
394  function tablerow_open(){}
395  function tablerow_close(){}
396
397  function tableheader_open($colspan = 1, $align = NULL){}
398  function tableheader_close(){}
399
400  function tablecell_open($colspan = 1, $align = NULL){}
401  function tablecell_close(){}
402
403  //----------------------------------------------------------
404  // Utils
405
406  /**
407   * Removes any Namespace from the given name but keeps
408   * casing and special chars
409   *
410   * @author Andreas Gohr <andi@splitbrain.org>
411   */
412  function _simpleTitle($name){
413    global $conf;
414
415    if(is_array($name)) return '';
416
417    if($conf['useslash']){
418        $nssep = '[:;/]';
419    }else{
420        $nssep = '[:;]';
421    }
422    $name = preg_replace('!.*'.$nssep.'!','',$name);
423    //if there is a hash we use the anchor name only
424    $name = preg_replace('!.*#!','',$name);
425    return $name;
426  }
427
428  /**
429   * Creates a linkid from a headline
430   *
431   * @param string  $title   The headline title
432   * @param boolean $create  Create a new unique ID?
433   * @author Andreas Gohr <andi@splitbrain.org>
434   */
435  function _headerToLink($title, $create=false) {
436    $title = str_replace(':','',cleanID($title));
437    $title = ltrim($title,'0123456789._-');
438    if(empty($title)) $title='section';
439
440    if($create){
441      // make sure tiles are unique
442      $num = '';
443      while(in_array($title.$num,$this->headers)){
444        ($num) ? $num++ : $num = 1;
445      }
446      $title = $title.$num;
447      $this->headers[] = $title;
448    }
449
450    return $title;
451  }
452
453  /**
454   * Construct a title and handle images in titles
455   *
456   * @author Harry Fuecks <hfuecks@gmail.com>
457   */
458  function _getLinkTitle($title, $default, $id=NULL) {
459    global $conf;
460
461    $isImage = false;
462    if (is_null($title)){
463      if (useHeading('content') && $id){
464        $heading = p_get_first_heading($id,false);
465        if ($heading) return $heading;
466      }
467      return $default;
468    } else if (is_string($title)){
469      return $title;
470    } else if (is_array($title)){
471      return '['.$title['title'].']';
472    }
473  }
474
475  function _firstimage($src){
476    if($this->firstimage) return;
477    global $ID;
478
479    list($src,$hash) = explode('#',$src,2);
480    if(!preg_match('/^https?:\/\//i',$src)){
481        resolve_mediaid(getNS($ID),$src, $exists);
482    }
483    if(preg_match('/.(jpe?g|gif|png)$/i',$src)){
484        $this->firstimage = $src;
485    }
486  }
487}
488
489//Setup VIM: ex: et ts=4 enc=utf-8 :
490