1 <?php
2 if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
3 if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
4 
5 /**
6  * Explain Terms and Definitions
7  *
8  * It works like acronym.conf, but for any term (even with more than
9  * one word).
10  *
11  * Evaluates conf/explain.conf which is in the following syntax:
12  *
13  * [<WHITESPACE>]term<TAB>explanation<TAB>link1<TAB>link2
14  *
15  * WHITESPACE:  If term starts with a whitespace character (Tab, Space, …),
16  *              it is considered case-sensitive
17  * term:        the term to explain
18  * explanation: a short description of the term
19  * link1:       link as URL or wiki page (a:b:c) to the definition
20  * link2:       link as URL or wiki page (a:b:c) to alternative definition
21  *
22  * If the first link points to the current page, the second link is used.
23  * Lines starting with # are treated as comments.
24  *
25  * @license  GPL
26  * @author   Marc Wäckerlin <marc@waeckerlin.org>
27  * @author   Adrian Lang <lang@cosmocode.de>
28  * @author   Andreas Gohr <gohr@cosmocode.de>
29  */
30 class syntax_plugin_explain extends DokuWiki_Syntax_Plugin {
31 
32     function getType() {
33         return 'substition';
34     }
35 
36     function getSort() {
37         return 239; // before 'acronym'
38     }
39 
40     function syntax_plugin_explain() {
41         // "static" not allowed in PHP4?!?
42         //if (isset($keys[0]) return; // evaluate at most once
43         $lines = @file(DOKU_CONF.'explain.conf');
44         if ($lines === false) {
45             return;
46         }
47         foreach ($lines as $line) {
48             $i = (trim(substr($line, 0, 1)) !== '');
49             $line = trim($line);
50             if (empty($line)) continue;
51             if (substr($line, 0, 1) === '#') continue;
52             $parts = explode("\t", $line);
53             if ($i) $parts[0] = utf8_strtolower($parts[0]);
54             $this->map[$parts[0]] = array('desc'   => $parts[1],
55                     'target' => $this->link(array_slice($parts, 2)),
56                     'i'      => $i);
57         }
58     }
59 
60     function link($targets) {
61         foreach($targets as $target) {
62             $_ret = $this->_link($target);
63             if ($_ret !== '') {
64                 break;
65             }
66         }
67         return $_ret;
68     }
69 
70     function _link($target) {
71         /* Match an URL. */
72         static $url = '#^https?://#';
73         // '^(http://)?[-_[:alnum:]]+[-_.[:alnum:]]*\.[a-z]{2}'
74         // '(/[-_./[:alnum:]&%?=#]*)?';
75         if (preg_match($url, $target))
76             return $target;
77 
78         /* Match an internal link. */
79         list($id, $hash) = explode('#', $target, 2);
80         global $ID;
81 
82         $_ret = '';
83         if($ID != $id) {
84             $_ret .= wl($id);
85         }
86         if($hash != '') {
87             $_ret .= '#'.$hash;
88         }
89         return $_ret;
90     }
91 
92     function connectTo($mode) {
93         if (count($this->map) === 0)
94             return;
95 
96         $re = '(?<=^|\W)(?i:'.
97                 join('|', array_map('preg_quote_cb', array_keys($this->map))).
98                 ')(?=\W|$)';
99 
100         $this->Lexer->addSpecialPattern($re, $mode, 'plugin_explain');
101     }
102 
103     function handle($match, $state, $pos, Doku_Handler $handler) {
104         /* Supply the matched text in any case. */
105         $data = array('content' => $match);
106         foreach (array_keys($this->map) as $rxmatch) {
107             if ($match === $rxmatch ||
108                     ($this->map[$rxmatch]['i'] && utf8_strtolower($match) === $rxmatch)) {
109                 $data += $this->map[$rxmatch];
110                 /* Handle only the first occurrence. */
111                 unset($this->map[$rxmatch]['desc']);
112                 break;
113             }
114         }
115         return $data;
116     }
117 
118     public function render($format, Doku_Renderer $renderer, $data) {
119         if(is_null($data['desc'])) {
120             $renderer->doc .= hsc($data['content']);
121             return true;
122         }
123         if ($format == 'xhtml') {
124             $renderer->doc .= '<a class="explain"';
125             if(($data['target']) !== '') {
126                 $renderer->doc .= ' href="' . hsc($data['target']) . '"';
127             }
128             $renderer->doc .= '>' . hsc($data['content']);
129             if ($data['desc'] !== '') {
130                 $renderer->doc .= '<span class="tooltip">'.hsc($data['desc']).'</span>';
131             }
132             $renderer->doc .= '</a>';
133             return true;
134         }
135         // generate output for ODT export
136         if ($format == 'odt') {
137             $renderer->doc .= hsc($data['content']);
138             return true;
139         }
140         return false;
141     }
142 }
143