1<?php
2
3use dokuwiki\Parsing\Handler\CallWriterInterface;
4use dokuwiki\plugin\imagemapping\ImageMapHandler;
5
6/**
7 * Image Mapping Plugin: Syntax component
8 *
9 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
10 * @author   Gerry Weißbach <tools@inetsoftware.de>
11 * @author   Michael Große <dokuwiki@cosmocode.de>
12 * @author   Tom N Harris <tools@inetsoftware.de>
13 *
14 * Based upon the non public version by Tom N Harris
15 */
16class syntax_plugin_imagemapping extends DokuWiki_Syntax_Plugin
17{
18
19    /** @inheritdoc */
20    function getType()
21    {
22        return 'container';
23    }
24
25    /** @inheritdoc */
26    function getSort()
27    {
28        return 316;
29    }
30
31    /** @inheritdoc */
32    function getPType()
33    {
34        return 'block';
35    }
36
37    /** @inheritdoc */
38    function getAllowedTypes()
39    {
40        return array('formatting', 'substition', 'disabled', 'protected', 'container', 'paragraphs');
41    }
42
43    /** @inheritdoc */
44    function connectTo($mode)
45    {
46        $this->Lexer->addEntryPattern('\{\{map>[^\}]+\}\}', $mode, 'plugin_imagemapping');
47    }
48
49    /** @inheritdoc */
50    function postConnect()
51    {
52        $this->Lexer->addExitPattern('\{\{<map\}\}', 'plugin_imagemapping');
53    }
54
55    /** @inheritdoc */
56    function handle($match, $state, $pos, Doku_Handler $handler)
57    {
58        global $conf;
59        global $ID;
60        $args = array($state);
61
62        switch ($state) {
63            case DOKU_LEXER_ENTER:
64                $img = Doku_Handler_Parse_Media(substr($match, 6, -2));
65                if ($img['title']) {
66                    $mapname = str_replace(':', '', cleanID($img['title']));
67                    $mapname = ltrim($mapname, '0123456789._-');
68                }
69                if (empty($mapname)) {
70                    if ($img['type'] == 'internalmedia') {
71                        $src = $img['src'];
72                        resolve_mediaid(getNS($ID), $src, $exists);
73                        $nssep = ($conf['useslash']) ? '[:;/]' : '[:;]';
74                        $mapname = preg_replace('!.*' . $nssep . '!', '', $src);
75                    } else {
76                        $src = parse_url($img['src']);
77                        $mapname = str_replace(':', '', cleanID($src['host'] . $src['path'] . $src['query']));
78                        $mapname = ltrim($mapname, '0123456789._-');
79                    }
80                    if (empty($mapname)) {
81                        $mapname = 'imagemap' . $pos;
82                    }
83                }
84                $args = [$state, $img['type'], $img['src'], $img['title'], $mapname,
85                    $img['align'], $img['width'], $img['height'],
86                    $img['cache']];
87
88                $ReWriter = new ImageMapHandler($mapname, $handler->getCallWriter());
89                $handler->setCallWriter($ReWriter);
90                break;
91            case DOKU_LEXER_EXIT:
92                // @var ImageMapHandler $ReWriter
93                $ReWriter = $handler->getCallWriter();
94                $ReWriter->process();
95                $handler->setCallWriter($ReWriter->getCallWriter());
96                break;
97            case DOKU_LEXER_MATCHED:
98                break;
99            case DOKU_LEXER_UNMATCHED:
100                $args[] = $match;
101                break;
102        }
103        return $args;
104    }
105
106    /** @inheritdoc */
107    function render($format, Doku_Renderer $renderer, $data)
108    {
109        global $conf;
110        global $ID;
111        static $has_content = false;
112        $state = $data[0];
113        if (substr($format, 0, 5) == 'xhtml') {
114            switch ($state) {
115                case DOKU_LEXER_ENTER:
116                    list($state, $type, $src, $title, $name, $align, $width, $height, $cache) = $data;
117                    if ($type == 'internalmedia') {
118                        resolve_mediaid(getNS($ID), $src, $exists);
119                    }
120                    $renderer->doc .= '<p>' . DOKU_LF;
121                    $src = ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache));
122                    $renderer->doc .= ' <img src="' . $src . '" class="media' . $align . ' imagemapping-map" usemap="#' . $name . '"';
123                    if ($align == 'right' || $align == 'left')
124                        $renderer->doc .= ' align="' . $align . '"';
125                    if (!is_null($title)) {
126                        $title = $renderer->_xmlEntities($title);
127                        $renderer->doc .= ' title="' . $title . '"';
128                        $renderer->doc .= ' alt="' . $title . '"';
129                    } else {
130                        $renderer->doc .= ' alt=""';
131                    }
132                    if (!is_null($width))
133                        $renderer->doc .= ' width="' . $renderer->_xmlEntities($width) . '"';
134                    if (!is_null($height))
135                        $renderer->doc .= ' height="' . $renderer->_xmlEntities($height) . '"';
136                    $renderer->doc .= ' />' . DOKU_LF;
137                    $renderer->doc .= '</p>' . DOKU_LF;
138                    $renderer->doc .= '<map name="' . $name . '" id="' . $name . '">' . DOKU_LF;
139                    $has_content = false;
140                    break;
141                case DOKU_LEXER_MATCHED:
142                    if ($data[1] == 'area') {
143                        @list($state, $match, $shape, $coords, $type, $title, $url, $wiki) = $data;
144                        $target = '';
145                        switch ($type) {
146                            case 'internallink':
147                                if ($url === '') $url = $ID;
148                                $default = $renderer->_simpleTitle($url);
149                                resolve_pageid(getNS($ID), $url, $exists);
150                                $title = $renderer->_getLinkTitle($title, $default, $isImg, $url);
151                                list($url, $hash) = explode('#', $url, 2);
152                                if (!empty($hash)) $hash = $renderer->_headerToLink($hash);
153                                $url = wl($url);
154                                if ($hash) $url .= '#' . $hash;
155                                $target = $conf['target']['wiki'];
156                                break;
157                            case 'locallink':
158                                $title = $renderer->_getLinkTitle($title, $url, $isImg);
159                                $url = $renderer->_headerToLink($url);
160                                $url = '#' . $url;
161                                break;
162                            case 'externallink':
163                                $title = $renderer->_getLinkTitle($title, $url, $isImg);
164                                // url might be an attack vector, only allow registered protocols
165                                if (is_null($this->schemes)) $this->schemes = getSchemes();
166                                list($scheme) = explode('://', $url);
167                                $scheme = strtolower($scheme);
168                                if (!in_array($scheme, $this->schemes)) $url = '';
169                                $target = $conf['target']['extern'];
170                                break;
171                            case 'interwikilink':
172                                $title = $renderer->_getLinkTitle($title, $url, $isImg);
173                                $url = $renderer->_resolveInterWiki($wiki, $url);
174                                if (strpos($url, DOKU_URL) === 0)
175                                    $target = $conf['target']['wiki'];
176                                else
177                                    $target = $conf['target']['interwiki'];
178                                break;
179                            case 'emaillink':
180                                $url = $renderer->_xmlEntities($url);
181                                $url = obfuscate($url);
182                                $title = $renderer->_getLinkTitle($title, $url, $isImg);
183                                if ($conf['mailguard'] == 'visible')
184                                    $url = rawurlencode($url);
185                                $url = 'mailto:' . $url;
186                                break;
187                            case 'windowssharelink':
188                                $title = $renderer->_getLinkTitle($title, $url, $isImg);
189                                $url = str_replace('\\', '/', $url);
190                                $url = 'file:///' . $url;
191                                $target = $conf['target']['windows'];
192                                break;
193                            case 'internalmedia':
194                                list($url, $hash) = explode('#', $url, 2);
195                                resolve_mediaid(getNS($ID), $url, $exists);
196                                $title = $renderer->_media($url, $title, null, null, null, null, false);
197                                $url = ml($url, ($extra[1] == 'direct'));
198                                if ($hash)
199                                    $url .= '#' . $hash;
200                                break;
201                        }
202                        if ($url) {
203                            $renderer->doc .= '<area href="' . $url . '"';
204                            if (!empty($target))
205                                $renderer->doc .= ' target="' . $target . '"';
206                            $renderer->doc .= ' title="' . $title . '" alt="' . $title . '"';
207
208                            $renderer->doc .= ' shape="' . $shape . '" coords="' . $coords . '"/>';
209                        }
210                    } elseif ($data[1] == 'divstart') {
211                        $renderer->doc .= DOKU_LF . '<div class="imagemapping-content">' . DOKU_LF;
212                        $has_content = true;
213                    } elseif ($data[1] == 'divend') {
214                        $renderer->doc .= DOKU_LF;//.'</div>'.DOKU_LF;
215                    }
216                    break;
217                case DOKU_LEXER_EXIT:
218                    if ($has_content) $renderer->doc .= '</div>' . DOKU_LF;
219                    $renderer->doc .= '</map>';
220                    break;
221                case DOKU_LEXER_UNMATCHED:
222                    $renderer->doc .= $renderer->_xmlEntities($data[1]);
223                    break;
224            }
225            return true;
226        } elseif ($format == 'metadata') {
227            switch ($state) {
228                case DOKU_LEXER_ENTER:
229                    list($state, $type, $src, $title, $name) = $data;
230                    if ($type == 'internalmedia') {
231                        resolve_mediaid(getNS($ID), $src, $exists);
232                        $renderer->meta['relation']['media'][$src] = $exists;
233                    }
234                    if (is_null($title))
235                        $title = $name;
236                    if ($renderer->capture && $title)
237                        $renderer->doc .= '[' . $title . ']';
238                    break;
239                case DOKU_LEXER_EXIT:
240                    break;
241                case DOKU_LEXER_UNMATCHED:
242                    if ($renderer->capture)
243                        $renderer->doc .= $data[1];
244                    break;
245            }
246            return true;
247        }
248        return false;
249    }
250
251}
252
253