* @version 2021-05-12, for Google Maps v3 API and DokuWiki Hogfather * @see https://www.dokuwiki.org/plugin:googlemaps3 * @see https://www.dokuwiki.org/plugin:googlemaps * * Complete rewrite of Christopher Smith's Google Maps Plugin from 2008 with additional functionality * syntax.php plugin syntax definition */ // Must be run within Dokuwiki if(!defined('DOKU_INC')) die(); /** * Syntax for Google Maps v3 */ class syntax_plugin_googlemaps3 extends DokuWiki_Syntax_Plugin { private $mapID = 0; private $markerID = 0; private $defaultMapOptions = array( 'mapID' => 0, // used to allow css override 'type' => 'roadmap', // roadmap, hybrid, satellite, terrain 'width' => '', // default style in css file 'height' => '', // default style in css file 'lat' => 12.57076, // lat+lng are mandatory 'lng' => 99.96260, // lat+lng are mandatory 'address' => '', 'zoom' => 0, // zoom is mandatory 'language' => '', // google maps defaults to language set in browser 'region' => '', // google maps defaults region bias to US 'disableDefaultUI' => 0, // google maps UI defaults 'zoomControl' => 1, 'mapTypeControl' => 1, 'scaleControl' => 1, 'streetViewControl' => 1, 'rotateControl' => 1, 'fullscreenControl' => 1, 'kml' => 'off', ); private $defaultMarkerOptions = array( 'markerID' => 0, // used to allow css override 'lat' => 0, 'lng' => 0, 'title' => '', 'icon' => '', 'info' => '', 'dir' => '', 'img' => '', 'width' => '', ); /** * Syntax Type * * Needs to return one of the mode types defined in $PARSER_MODES in parser.php * * @return string */ public function getType() { return 'substition'; } /** * Paragraph Handling * * @return string */ public function getPType() { return 'block'; } /** * Sort for applying this mode * * @return int */ public function getSort() { return 900; } /** * @param string $mode */ function connectTo($mode) { $this->Lexer->addSpecialPattern('\n]*>.*?',$mode,'plugin_googlemaps3'); } /** * Handler to prepare matched data for the rendering process * * @param string $match The text matched by the patterns * @param int $state The lexer state for the match * @param int $pos The character position of the matched text * @param Doku_Handler $handler The Doku_Handler object * @return bool|array Return an array with all data you want to use in render, false don't add an instruction */ function handle($match, $state, $pos, Doku_Handler $handler){ static $initialised = false; list($mapOptions, $markerOptions) = explode('>',substr($match,12,-14),2); $map = $this->getMapOptions($mapOptions); $markers = $this->getMarkers($markerOptions); // determine width and height (inline styles) for the map image if ($map['width'] || $map['height']) { $style = $map['width'] ? 'width: '.(is_numeric($map['width']) ? $map['width'].'px' : $map['width']).";" : ""; $style .= $map['height'] ? 'height: '.(is_numeric($map['height']) ? $map['height'].'px' : $map['height']).";" : ""; // $style = $map['width'] ? 'width: '.$map['width'].";" : ""; // $style .= $map['height'] ? 'height: '.$map['height'].";" : ""; $style = "style='$style'"; } else { $style = ''; } unset($map['width'],$map['height']); // determine region and language $lang = ($map['region'] ? '®ion='.$map['region'] : ($this->getConf('region') ? '®ion='.$this->getConf('region') : '')); $lang .= ($map['language'] ? '&language='.$map['language'] : ($this->getConf('language') ? '&language='.$this->getConf('language') : '')); unset($map['region'],$map['language']); // create a javascript parameter string for the map $jsOptions = ''; foreach ($map as $key => $val) { $jsOptions .= is_numeric($val) ? "$key : $val," : (is_bool($val) ? "$key : ".(int)$val."," : "$key : '".hsc($val)."',"); } // create a javascript serialisation of the markers data $jsMarker = ''; if (!empty($markers)) { foreach ($markers as $marker) { $jsMarker .= "{markerID:".$marker['markerID'].", lat:".$marker['lat'].", lng:".$marker['lng']. ($marker['title'] ? ", title:'".$marker['title']."'" : ""). ($marker['icon'] ? ", icon:'".$marker['icon']."'" : ""). ($marker['info'] ? ", info:'".$marker['info']."'" : ""). ($marker['dir'] ? ", dir:'".$marker['dir']."'" : ""). ($marker['img'] ? ", img:'".$marker['img']."'" : ""). ($marker['width'] ? ", width:'".$marker['width']."'" : ""). "},"; } $jsMarker = "marker : [ ".$jsMarker." ]"; } if ($initialised) { $jsData = ''; } else { $initialised = true; $jsData = 'var googlemaps3 = new Array();'; } $jsData .= "googlemaps3[googlemaps3.length] = {".$jsOptions.$jsMarker." };"; return array($map['mapID'], $style, $lang, $jsData); } /** * Renders the map in the wiki page * * @param string $mode output format being rendered * @param Doku_Renderer $renderer the current renderer object * @param array $data data created by handler() * @return boolean rendered correctly? (however, returned value is not used at the moment) */ function render($mode, Doku_Renderer $renderer, $data) { static $initialised = false; if ($mode == 'xhtml') { list($mapID, $style, $lang, $jsData) = $data; // include script only once if (!$initialised) { $initialised = true; $renderer->doc .= ""; } $renderer->doc .= ""; $renderer->doc .= "
"; return true; } return false; } /** * extract map options * * @param string $pattern string of map options * @return array associative array of map options */ private function getMapOptions($pattern) { $options = array(); preg_match_all('/(\w*)="(.*?)"/us', $pattern, $options, PREG_SET_ORDER); // parse match for instructions $map = $this->defaultMapOptions; $map['mapID'] = ++$this->mapID; foreach($options as $option) { list($match, $key, $val) = $option; if (isset($map[$key])) if ($key=='kml') $map[$key] = $val; else $map[$key] = strtolower($val); if (isset($map[$key])) { if ($val=='true') $val = 1; elseif ($val=='false') $val = 0; $map[$key] = $val; } } return $map; } /** * extract markers information * * @param string $pattern multi-line string of markers * @return array multi-dimensional associative array of markers */ private function getMarkers($pattern) { $dlm = $this->getConf('delim'); $markers = array(); preg_match_all('/.+/', $pattern, $lines, PREG_PATTERN_ORDER); // get all markers foreach ($lines[0] AS $line) { preg_match_all('/(?<=\\'.$dlm.'|^|\n)(.*?)(?=\\'.$dlm.'|$|\n)/u', $line, $matches,PREG_PATTERN_ORDER); // get marker options $markers[] = array_combine(array_keys($this->defaultMarkerOptions), array_merge(array(0), $matches[0], array_fill(0, count($this->defaultMarkerOptions)-count($matches[0])-1,''))); } // trim leading "delimiter" if any and get default if option empty foreach ($markers as $mark => $marker) { foreach ($marker as $option => $value) { if ($value) $markers[$mark][$option] = ltrim($markers[$mark][$option], $dlm); if (!$value) $markers[$mark][$option] = $this->defaultMarkerOptions[$option]; } } foreach ($markers as $mark => $marker) { $markers[$mark]['markerID'] = ++$this->markerID; if ($markers[$mark]['lat'] == 'address') { $markers[$mark]['lat'] = "'".$markers[$mark]['lat']."'"; $markers[$mark]['lng'] = "'".$markers[$mark]['lng']."'"; } else { $markers[$mark]['lat'] = is_numeric($marker['lat']) ? floatval($marker['lat']) : 0; $markers[$mark]['lng'] = is_numeric($marker['lng']) ? floatval($marker['lng']) : 0; } $markers[$mark]['icon'] = ($marker['icon'] && strpos($marker['icon'], '.') ? $this->getConf('path').$marker['icon'] : $marker['icon']); $markers[$mark]['info'] = str_replace("\n","", p_render("xhtml", p_get_instructions($markers[$mark]['info']), $info)); } return $markers; } }