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