====== Plugin google_maps for DikuWiki ====== ===== Description & Requirements ===== Plugin allows to embed Google map frames to the page or create external links to Google Maps service. Useful when listing addresses. Works with any browser, where [[http://maps.google.com|Google Maps]] works. ===== Syntax ===== Complete list: ''%%{{googlemaps>address[zoom=16,size=small,control=hierarchical,overviewmap=true,width=800,height=600,type=internal]|alternate text}}%%'' where: | **zoom**,**size**,**control**,**overviewmap** | see in [[#default_parameters|section below]] | | **type** | **internal** -- show google maps in embedded frame \\ //(default)// -- generate link to google maps | If **alternate text** is skipped then **address** is used. ==== Default parameters ==== ^ Parameter name ^ Possible valid values ^ | **google_api_key** | Valid Google API key for the current site. See [[#configuration|below]] for more details about how to generate it. | | **size** | **small** //(default)// -- generate small size window \\ **large** -- generate large size window \\ The sizes for the frames are taken from **%%small_*%%** and **%%large_*%%** parameters below. | | **control** | **hierarchical** //(default)// -- show two buttons in top-right corner: "Map" and "Satellite" \\ **default** -- show three buttons: "Map", "Satellite" and "Hybrid" \\ **none** -- show no buttons | | **overviewmap** | **true** //(default)// -- show the link to overview map in right-bottom corner \\ **false** -- do not show overview map | | **small_width** | //(default is **425**)// size in px -- the width of small frame, if **size=small** was specified | | **small_height** | //(default is **350**)// size in px -- the height of small frame, if **size=small** was specified | | **large_width** | //(default is **550**)// size in px -- the width of large frame, if **size=large** was specified | | **large_height** | //(default is **450**)// size in px -- the height of large frame, if **size=large** was specified | | **zoom** | //(default is **15**)// number from 1 to 19 which specifies the initial zoom | ===== Demonstration ===== The following wiki-code {{googlemaps>Gomel, Belarus|I was ''born'' here}}. I lived here: {{googlemaps>Tuinstraat 23, Delft, NL[type=internal]}} produces the following result: {{:plugin:google_maps_sample.png|The sample result of plugin's output}} You may try in [[wiki:playground]]. ===== Installation ===== Download the package from {{:plugin:google_maps-2008-10-03.tar.bz2|here}} and unpack it to your dokuwiki installation e.g. to ''wiki/lib/plugins/''. ===== Configuration ===== Important is to register your site at Google to receive an access to Google services. Registration is free: * Register your website [[http://code.google.com/apis/maps/signup.html|here]] and receive you unique Google API key. * Modify the configuration file and put a newly generated key to **google_api_key**. ===== Documentation ===== * Plugin uses the JSON (JavaScript Object Notation) technique (described in [[http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html?|JSON and the Dynamic Script Tag: Easy, XML-less Web Services for JavaScript]]) to access [[http://www.geonames.org/export/ws-overview.html|GeoNames WebServices]]. Examples: * [[http://www.geonames.org/maps/json-googlemaps-example.html|Example of GoogleMaps and GeoNames interaction]] with use of JSON technique * [[http://www.ewebsite.biz/modules.php?name=gMap2|Example of GoogleMaps]] when JS code is server-side generated * [[http://developer.yahoo.com/maps/rest/V1/geocode.html|Yahoo Maps WS]]. Example: * [[http://theurer.cc/code/devx/mapProxy.html|Example of and Yahoo Maps interaction]], which uses full-blown AJAX ''XMLHttpRequest'' technique * [[http://code.google.com/apis/maps/documentation/services.html|Google Geocoder]]. Example: * [[http://code.google.com/apis/maps/documentation/examples/geocoding-extraction.html|extended data access]] * See also [[http://code.google.com/apis/maps/documentation/reference.html#GMap2|GMap2]] and [[http://code.google.com/apis/maps/documentation/reference.html#GClientGeocoder|GClientGeocoder]] API reference ===== Source ===== */ if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_google_maps extends DokuWiki_Syntax_Plugin { var $re_non_syntax_seq = '[^\[\]{}|]+'; var $re_plugin_body; function syntax_plugin_google_maps() { $this->re_plugin_body = "{$this->re_non_syntax_seq}(?:\\[{$this->re_non_syntax_seq}\\])?"; } function getInfo() { return array( 'author' => 'Dmitry Katsubo', 'email' => 'dma_k@mail.ru', 'date' => '2008-10-03', 'name' => 'Google Maps Plugin', 'desc' => 'Adds a Google Maps frame syntax: {{googlemaps>address[zoom=16,size=small,control=hierarchical,overviewmap=true,width=800,height=600,type=internal]|alternate text}}', 'url' => 'http://centurion.dynalias.com/wiki/plugin/google_maps', ); } function getAllowedTypes() { return array('formatting'); } function getType() { return 'substition'; } function getSort() { return 159; } function connectTo($mode) { $this->Lexer->addSpecialPattern("{{googlemaps>{$this->re_plugin_body}}}", $mode, 'plugin_google_maps'); $this->Lexer->addEntryPattern("{{googlemaps>{$this->re_plugin_body}\|(?={$this->re_non_syntax_seq}}})", $mode, 'plugin_google_maps'); } function postConnect() { $this->Lexer->addExitPattern("}}", 'plugin_google_maps'); } private function getConfigValue($options, $option_name, $config_prefix = null) { // Also escape HTML to protect the page: return(htmlspecialchars( isset($options[$option_name]) ? $options[$option_name] : $this->getConf($config_prefix . $option_name) )); } function handle($match, $state, $pos, &$handler) { switch ($state) { case DOKU_LEXER_SPECIAL: case DOKU_LEXER_ENTER: $matches = array(); if (!preg_match("/{{googlemaps>({$this->re_non_syntax_seq})(?:\\[({$this->re_non_syntax_seq})\\])?/", $match, $matches)) { // syslog(LOG_DEBUG, "Input $match cannot be matched against /{{googlemaps>{$this->re_plugin_body}"); return array(''); // this is an error } $options = array(); if (isset($matches[2])) { preg_replace('/\s+/', '', $matches[2]); $entries = explode(',', $matches[2]); foreach ($entries as $entry) { $key_value = explode('=', $entry); $options[$key_value[0]] = $key_value[1]; } } return array($state, array($matches[1], &$options)); } return array($state, $match); } function render($mode, &$renderer, $data) { if ($mode == 'xhtml') { list($state, $match) = $data; switch($state) { case DOKU_LEXER_SPECIAL: case DOKU_LEXER_ENTER: list($text, $options) = $match; $query = htmlspecialchars(html_entity_decode(trim($text))); // This type is available only in DOKU_LEXER_SPECIAL state: if ($state == DOKU_LEXER_SPECIAL && $options['type'] == 'internal') { // Injection of this script causes FF to hang. so we have to generate it for each map: $renderer->doc .= "\n"; // Default values: $size = $this->getConfigValue($options, 'size'); $width = $this->getConfigValue($options, 'width', $size . '_') . "px"; $height = $this->getConfigValue($options, 'height', $size . '_') . "px"; // Internal div: $renderer->doc .= "\n
doc .= " $attr_name='" . $this->getConfigValue($options, $attr_name) . "'"; } // Important to leave one hanging node inside
, otherwise maps start overlappig. // That is done implicitly here. $renderer->doc .= '>
'; return true; } if ($options['type'] != 'internal') { // Concat params: $params = '&'; // If not defined, Google Maps engine will automatically select the best zoom: if ($options['zoom']) { $params .= "z=" . $options['zoom']; } // Query is already escaped, params are taken from options: $url = "http://maps.google.com/maps?q=$query$params"; // External link: $renderer->doc .= ""; if ($state == DOKU_LEXER_SPECIAL) { $renderer->doc .= "$text"; } return true; } return false; case DOKU_LEXER_UNMATCHED: $renderer->doc .= $renderer->_xmlEntities($match); return true; case DOKU_LEXER_EXIT: $renderer->doc .= ''; return true; default: //$renderer->doc .= "
Cannot handle mode $style
"; } } return false; } } ?>
var max_geo_results = 5; function createMarker(point, desc) { var marker = new GMarker(point); // Note: Without wrapping into a function, listeners are added to the same objects! GEvent.addListener(marker, "click", function() { marker.openInfoWindowHtml(desc); }); return marker; } function queryGoogleGeo(map, query, zoom) { var geocoder = new GClientGeocoder(); geocoder.getLocations(query, function generateMarkersFromGoogleGeoResult(response) { // Was not able to locate any data: if (response == null || response.Status.code != 200) { alert("Sorry, we were unable to locate " + query + " address"); return; } var places = response.Placemark; for (var i = 0; i < places.length && i < max_geo_results; i++) { var place = places[i]; var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]); if (i == 0) { map.setCenter(point, zoom); } map.addOverlay(createMarker(point, '
' + place.address + '
' + place.AddressDetails.Country.CountryNameCode )); } }); } /** * Initialisation function. Creates Gmap objects and loads Geo information. */ function loadMaps() { var headNode = document.getElementsByTagName("head").item(0); var divNodes = document.body.getElementsByTagName('div'); for (var i = 0; i < divNodes.length; i++) { if (divNodes[i].className.match(/\bgmapsint\b/)) { var attrs = divNodes[i].attributes; // Create a map: var map = new GMap2(divNodes[i]); map.setCenter(new GLatLng(34, 0), 1); // default point // left-top navigator and zoomer if (attrs.size.value == 'small') map.addControl(new GSmallMapControl()); else if (attrs.size.value == 'large') map.addControl(new GLargeMapControl()); // right-top map type switch buttons if (attrs.control.value == 'hierarchical') map.addControl(new GHierarchicalMapTypeControl()); else if (attrs.control.value == 'default') map.addControl(new GMapTypeControl()); // mini-map in the bottom-right corner if (attrs.overviewmap.value == 'true') { var overviewMap = new GOverviewMapControl(); map.addControl(overviewMap); overviewMap.hide(); } map.enableScrollWheelZoom(); var query = attrs.query.value; var zoom = parseInt(attrs.zoom.value); //queryGeonames(map, query, zoom); queryGoogleGeo(map, query, zoom); } } } // A special Wiki-wide function, defined in lib/scripts/events.js: addInitEvent(loadMaps);
a.gmapsext { background: transparent url(gmaps_link.png) no-repeat left center; padding: 1px 0px 1px 12px; } div.gmapsint { border: 1px solid __border__; } div.gmapsmarker { // margin-top: 10px; font-size: 90%; } The latest source code snapshot can be taken from SVN: ''svn co https://centurion.dynalias.com/svn/public/trunk/web/dokuwiki/lib/plugins/google_maps/'' ===== Revision History ===== * 2008-03-17 --- Version r05. * 2008-10-03 --- Version r47. Plugin was refactored to allow formatting in comment. Also aligned in compliance with common practices how to process the flow. ===== ToDo ===== There is nothing right now in my ToDo list, as the aim was achieved. Please, send your suggestions to [[dma_k@mail.ru]]. ===== Bugs ===== Tested with IE 6.0 SP1, FF 2.0.0.11. No bugs at the moment. Please, report bugs or feature requests to [[http://centurion.dynalias.com/jira/browse/dokuwiki|JIRA]].