{{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 .= "\ndoc .= " $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]].