1<?php
2if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
3if(!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 */
30class 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