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