xref: /dokuwiki/inc/parser/metadata.php (revision 357e220245cc608a5421bebf402bd083991714ab)
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 (!$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(!$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 (!$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){
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){
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      if ($name) $this->doc .= $name;
338      else $this->doc .= '<'.$url.'>';
339    }
340  }
341
342  function interwikilink($match, $name = NULL, $wikiName, $wikiUri){
343    if(is_array($name))
344        $this->_firstimage($name['src']);
345
346    if ($this->capture){
347      list($wikiUri, $hash) = explode('#', $wikiUri, 2);
348      $name = $this->_getLinkTitle($name, $wikiName.'>'.$wikiUri);
349      $this->doc .= $name;
350    }
351  }
352
353  function windowssharelink($url, $name = NULL){
354    if(is_array($name))
355        $this->_firstimage($name['src']);
356
357    if ($this->capture){
358      if ($name) $this->doc .= $name;
359      else $this->doc .= '<'.$url.'>';
360    }
361  }
362
363  function emaillink($address, $name = NULL){
364    if(is_array($name))
365        $this->_firstimage($name['src']);
366
367    if ($this->capture){
368      if ($name) $this->doc .= $name;
369      else $this->doc .= '<'.$address.'>';
370    }
371  }
372
373  function internalmedia($src, $title=NULL, $align=NULL, $width=NULL,
374                         $height=NULL, $cache=NULL, $linking=NULL){
375    if ($this->capture && $title) $this->doc .= '['.$title.']';
376    $this->_firstimage($src);
377  }
378
379  function externalmedia($src, $title=NULL, $align=NULL, $width=NULL,
380                         $height=NULL, $cache=NULL, $linking=NULL){
381    if ($this->capture && $title) $this->doc .= '['.$title.']';
382    $this->_firstimage($src);
383  }
384
385  function rss($url,$params) {
386    $this->meta['relation']['haspart'][$url] = true;
387
388    $this->meta['date']['valid']['age'] =
389            isset($this->meta['date']['valid']['age']) ?
390                min($this->meta['date']['valid']['age'],$params['refresh']) :
391                $params['refresh'];
392  }
393
394  function table_open($maxcols = NULL, $numrows = NULL){}
395  function table_close(){}
396
397  function tablerow_open(){}
398  function tablerow_close(){}
399
400  function tableheader_open($colspan = 1, $align = NULL){}
401  function tableheader_close(){}
402
403  function tablecell_open($colspan = 1, $align = NULL){}
404  function tablecell_close(){}
405
406  //----------------------------------------------------------
407  // Utils
408
409  /**
410   * Removes any Namespace from the given name but keeps
411   * casing and special chars
412   *
413   * @author Andreas Gohr <andi@splitbrain.org>
414   */
415  function _simpleTitle($name){
416    global $conf;
417
418    if(is_array($name)) return '';
419
420    if($conf['useslash']){
421        $nssep = '[:;/]';
422    }else{
423        $nssep = '[:;]';
424    }
425    $name = preg_replace('!.*'.$nssep.'!','',$name);
426    //if there is a hash we use the anchor name only
427    $name = preg_replace('!.*#!','',$name);
428    return $name;
429  }
430
431  /**
432   * Creates a linkid from a headline
433   *
434   * @param string  $title   The headline title
435   * @param boolean $create  Create a new unique ID?
436   * @author Andreas Gohr <andi@splitbrain.org>
437   */
438  function _headerToLink($title, $create=false) {
439      if($create){
440          return sectionID($title,$this->headers);
441      }else{
442          $check = false;
443          return sectionID($title,$check);
444      }
445  }
446
447  /**
448   * Construct a title and handle images in titles
449   *
450   * @author Harry Fuecks <hfuecks@gmail.com>
451   */
452  function _getLinkTitle($title, $default, $id=NULL) {
453    global $conf;
454
455    $isImage = false;
456    if (is_null($title)){
457      if (useHeading('content') && $id){
458        $heading = p_get_first_heading($id,false);
459        if ($heading) return $heading;
460      }
461      return $default;
462    } else if (is_string($title)){
463      return $title;
464    } else if (is_array($title)){
465      return '['.$title['title'].']';
466    }
467  }
468
469  function _firstimage($src){
470    if($this->firstimage) return;
471    global $ID;
472
473    list($src,$hash) = explode('#',$src,2);
474    if(!preg_match('/^https?:\/\//i',$src)){
475        resolve_mediaid(getNS($ID),$src, $exists);
476    }
477    if(preg_match('/.(jpe?g|gif|png)$/i',$src)){
478        $this->firstimage = $src;
479    }
480  }
481}
482
483//Setup VIM: ex: et ts=4 enc=utf-8 :
484