Version Description
[2012-01-08] = * final cleanup for public release
Download this release
Release Info
Developer | webaware |
Plugin | Flexible Map |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- class.FlxMapAdmin.php +58 -0
- class.FlxMapPlugin.php +196 -0
- flexible-map.js +252 -0
- flexible-map.min.js +5 -0
- flexible-map.php +70 -0
- instructions.html +65 -0
- readme.txt +72 -0
class.FlxMapAdmin.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* class for admin screens
|
5 |
+
*/
|
6 |
+
class FlxMapAdmin {
|
7 |
+
|
8 |
+
const MENU_PAGE = 'flexible-map'; // slug for menu page(s)
|
9 |
+
|
10 |
+
private $plugin;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param FlxMapPlugin $plugin
|
14 |
+
*/
|
15 |
+
public function __construct($plugin) {
|
16 |
+
$this->plugin = $plugin;
|
17 |
+
|
18 |
+
// add wines admin menu items
|
19 |
+
add_action('admin_menu', array($this, 'addAdminMenu'));
|
20 |
+
|
21 |
+
// add action hook for adding plugin meta links
|
22 |
+
add_filter('plugin_row_meta', array($this, 'addPluginDetailsLinks'), 10, 2);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* action hook for building admin menu
|
27 |
+
*/
|
28 |
+
public function addAdminMenu() {
|
29 |
+
// register the instructions page, only linked from plugin page
|
30 |
+
global $_registered_pages;
|
31 |
+
|
32 |
+
$hookname = get_plugin_page_hookname(self::MENU_PAGE . '-instructions', '');
|
33 |
+
if (!empty($hookname)) {
|
34 |
+
add_action($hookname, array($this, 'instructions'));
|
35 |
+
}
|
36 |
+
$_registered_pages[$hookname] = true;
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* action hook for adding plugin details links
|
41 |
+
*/
|
42 |
+
public function addPluginDetailsLinks($links, $file) {
|
43 |
+
// add settings link
|
44 |
+
if ($file == FLXMAP_PLUGIN_NAME)
|
45 |
+
$links[] = '<a href="admin.php?page=' . self::MENU_PAGE . '-instructions">' . __('Instructions') . '</a>';
|
46 |
+
|
47 |
+
return $links;
|
48 |
+
}
|
49 |
+
|
50 |
+
public function instructions() {
|
51 |
+
echo "<div class='wrap'>\n";
|
52 |
+
screen_icon('plugins');
|
53 |
+
echo "<h2>Flexible Map Instructions</h2>\n";
|
54 |
+
|
55 |
+
echo file_get_contents(FLXMAP_PLUGIN_ROOT . 'instructions.html');
|
56 |
+
echo "</div>\n";
|
57 |
+
}
|
58 |
+
}
|
class.FlxMapPlugin.php
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* class for managing the plugin
|
4 |
+
*/
|
5 |
+
class FlxMapPlugin {
|
6 |
+
public $urlBase; // string: base URL path to files in plugin
|
7 |
+
|
8 |
+
private $admin; // handle to admin object if running in wp-admin
|
9 |
+
private $loadScripts = FALSE; // true when scripts should be loaded
|
10 |
+
|
11 |
+
/**
|
12 |
+
* static method for getting the instance of this singleton object
|
13 |
+
*
|
14 |
+
* @return FlxMapPlugin
|
15 |
+
*/
|
16 |
+
public static function getInstance() {
|
17 |
+
static $instance = NULL;
|
18 |
+
|
19 |
+
if (is_null($instance)) {
|
20 |
+
$class = __CLASS__;
|
21 |
+
$instance = new $class;
|
22 |
+
}
|
23 |
+
|
24 |
+
return $instance;
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* hook the plug-in's initialise event to handle all post-activation initialisation
|
29 |
+
*/
|
30 |
+
private function __construct() {
|
31 |
+
// record plugin URL base
|
32 |
+
$this->urlBase = WP_PLUGIN_URL . '/' . dirname(plugin_basename(__FILE__));
|
33 |
+
|
34 |
+
if (is_admin()) {
|
35 |
+
// kick off the admin handling
|
36 |
+
$this->admin = new FlxMapAdmin($this);
|
37 |
+
}
|
38 |
+
else {
|
39 |
+
// add shortcodes
|
40 |
+
add_shortcode(FLXMAP_PLUGIN_TAG_MAP, array($this, 'shortcodeMap'));
|
41 |
+
|
42 |
+
// non-admin actions and filters for this plugin
|
43 |
+
add_action('wp_footer', array($this, 'actionFooter'));
|
44 |
+
|
45 |
+
// custom actions and filters for this plugin
|
46 |
+
add_filter('flexmap_getmap', array($this, 'shortcodeMap'), 10, 1);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* activate the plug-in (called by activate event): add custom capabilities, etc.
|
52 |
+
*/
|
53 |
+
public function activate() {
|
54 |
+
// NOP
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* deactivate the plug-in (called by deactivate event): remove custom capabilities, etc.
|
59 |
+
*/
|
60 |
+
public function deactivate() {
|
61 |
+
// remove deprecated custom capabilities for administrator (from previous versions)
|
62 |
+
$role = get_role('administrator');
|
63 |
+
$role->remove_cap('flxmap_options');
|
64 |
+
|
65 |
+
// remove deprecated custom capabilities for editor (from previous versions)
|
66 |
+
$role = get_role('editor');
|
67 |
+
$role->remove_cap('flxmap_options');
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* output anything we need in the footer
|
72 |
+
*/
|
73 |
+
public function actionFooter() {
|
74 |
+
if ($this->loadScripts) {
|
75 |
+
// load required scripts
|
76 |
+
$url = parse_url("{$this->urlBase}/flexible-map.min.js", PHP_URL_PATH);
|
77 |
+
|
78 |
+
echo <<<HTML
|
79 |
+
<script src="$url"></script>
|
80 |
+
<script src="http://maps.google.com/maps/api/js?v=3&sensor=false"></script>
|
81 |
+
|
82 |
+
HTML;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* handle shortcode for map display
|
88 |
+
*
|
89 |
+
* @param array shortcode attributes as supplied by the WP shortcode API
|
90 |
+
* @return string output to substitute for the shortcode
|
91 |
+
*/
|
92 |
+
public function shortcodeMap($attrs) {
|
93 |
+
$html = '';
|
94 |
+
|
95 |
+
if (!empty($attrs['src']) || !empty($attrs['center'])) {
|
96 |
+
$this->loadScripts = TRUE;
|
97 |
+
$divID = uniqid('flxmap-');
|
98 |
+
$width = isset($attrs['width']) ? preg_replace('/\D/', '', $attrs['width']) : 400;
|
99 |
+
$height = isset($attrs['height']) ? preg_replace('/\D/', '', $attrs['height']) : 400;
|
100 |
+
|
101 |
+
$directions = FALSE;
|
102 |
+
$divDirections = '';
|
103 |
+
if (isset($attrs['directions'])) {
|
104 |
+
$directions = TRUE;
|
105 |
+
if (preg_match('/^(?:y|yes|true|1)$/i', $attrs['directions'])) {
|
106 |
+
$divDirectionsID = "$divID-dir";
|
107 |
+
$divDirections = "\n<div id='$divDirectionsID' class='flxmap-directions'></div>";
|
108 |
+
}
|
109 |
+
else {
|
110 |
+
$divDirectionsID = $attrs['directions'];
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
$html = <<<HTML
|
115 |
+
<div id="$divID" class='flxmap-container' style="width: {$width}px; height: ${height}px;"></div>$divDirections
|
116 |
+
<script>
|
117 |
+
//<![CDATA[
|
118 |
+
(function (w, fn) {
|
119 |
+
if (w.addEventListener) w.addEventListener("DOMContentLoaded", fn, false);
|
120 |
+
else if (w.attachEvent) w.attachEvent("onload", fn);
|
121 |
+
})(window, function() {
|
122 |
+
var f = new FlexibleMap();
|
123 |
+
|
124 |
+
HTML;
|
125 |
+
|
126 |
+
if (!(isset($attrs['hideMapType']) && preg_match('/^(?:y|yes|true|1)$/i', $attrs['hideMapType']))) {
|
127 |
+
$html .= " f.mapTypeControl = true;\n";
|
128 |
+
}
|
129 |
+
|
130 |
+
if ($directions) {
|
131 |
+
$html .= " f.markerDirections = \"$divDirectionsID\";\n";
|
132 |
+
}
|
133 |
+
|
134 |
+
if (isset($attrs['showinfo']) && preg_match('/^(?:n|no|false|0)$/i', $attrs['showinfo'])) {
|
135 |
+
$html .= " f.markerShowInfo = false;\n";
|
136 |
+
}
|
137 |
+
|
138 |
+
if (isset($attrs['maptype'])) {
|
139 |
+
$html .= " f.mapTypeId = \"{$attrs['maptype']}\";\n";
|
140 |
+
}
|
141 |
+
|
142 |
+
if (isset($attrs['region'])) {
|
143 |
+
$html .= " f.region = \"{$attrs['region']}\";\n";
|
144 |
+
}
|
145 |
+
|
146 |
+
// add map based on coordinates, with optional marker coordinates
|
147 |
+
if (isset($attrs['center']) && preg_match('/^-?\\d+(?:\\.\\d+),-?\\d+(?:\\.\\d+)$/', $attrs['center'])) {
|
148 |
+
$marker = $attrs['center'];
|
149 |
+
if (isset($attrs['marker']) && preg_match('/^-?\\d+(?:\\.\\d+),-?\\d+(?:\\.\\d+)$/', $attrs['marker']))
|
150 |
+
$marker = $attrs['marker'];
|
151 |
+
|
152 |
+
if (isset($attrs['zoom']))
|
153 |
+
$html .= " f.zoom = " . preg_replace('/\D/', '', $attrs['zoom']) . ";\n";
|
154 |
+
|
155 |
+
if (!empty($attrs['title']))
|
156 |
+
$html .= " f.markerTitle = \"{$this->unhtml($attrs['title'])}\";\n";
|
157 |
+
|
158 |
+
if (!empty($attrs['description']))
|
159 |
+
$html .= " f.markerDescription = \"{$this->unhtml($attrs['description'])}\";\n";
|
160 |
+
|
161 |
+
if (!empty($attrs['link']))
|
162 |
+
$html .= " f.markerLink = \"{$attrs['link']}\";\n";
|
163 |
+
|
164 |
+
$html .= " f.showMarker(\"$divID\", [{$attrs['center']}], [{$marker}]);\n";
|
165 |
+
}
|
166 |
+
|
167 |
+
// add map based on KML file
|
168 |
+
else if (isset($attrs['src'])) {
|
169 |
+
$kmlfile = $attrs['src'];
|
170 |
+
$html .= " f.showKML(\"$divID\", \"$kmlfile\"";
|
171 |
+
|
172 |
+
if (isset($attrs['zoom']))
|
173 |
+
$html .= ', ' . preg_replace('/\D/', '', $attrs['zoom']);
|
174 |
+
|
175 |
+
$html .= ");\n";
|
176 |
+
}
|
177 |
+
|
178 |
+
$html .= "});\n//]]>\n</script>\n";
|
179 |
+
}
|
180 |
+
|
181 |
+
return $html;
|
182 |
+
}
|
183 |
+
|
184 |
+
private static function unhtml($text) {
|
185 |
+
return addcslashes(html_entity_decode($text), "\\\'\"&\n\r<>");
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* display a message (already HTML-conformant)
|
190 |
+
*
|
191 |
+
* @param string $msg HTML-encoded message to display inside a paragraph
|
192 |
+
*/
|
193 |
+
public static function showMessage($msg) {
|
194 |
+
echo "<div id='message' class='updated fade'><p><strong>$msg</strong></p></div>\n";
|
195 |
+
}
|
196 |
+
}
|
flexible-map.js
ADDED
@@ -0,0 +1,252 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
JavaScript for the WordPress plugin wp-flexible-map
|
3 |
+
© 2011 WebAware Pty Ltd, released under LGPL v2.1
|
4 |
+
*/
|
5 |
+
|
6 |
+
function FlexibleMap() {
|
7 |
+
// set map defaults
|
8 |
+
this.mapTypeId = google.maps.MapTypeId.ROADMAP;
|
9 |
+
this.mapTypeControl = false; // no control for changing map type
|
10 |
+
this.scaleControl = false; // no control for changing scale
|
11 |
+
this.streetViewControl = false; // no control for street view
|
12 |
+
this.scrollwheel = false; // no scroll wheel zoom
|
13 |
+
this.zoom = 16; // zoom level, smaller is closer
|
14 |
+
this.markerTitle = ''; // title for marker info window
|
15 |
+
this.markerDescription = ''; // description for marker info window
|
16 |
+
this.markerLink = ''; // link for marker title
|
17 |
+
this.markerShowInfo = true; // if have infowin for marker, show it immediately
|
18 |
+
this.markerDirections = false; // show directions link in info window
|
19 |
+
this.navigationControlOptions = { style: google.maps.NavigationControlStyle.SMALL };
|
20 |
+
this.dirService = false;
|
21 |
+
this.dirPanel = false;
|
22 |
+
this.region = false;
|
23 |
+
}
|
24 |
+
|
25 |
+
FlexibleMap.prototype = {
|
26 |
+
constructor: FlexibleMap,
|
27 |
+
|
28 |
+
/**
|
29 |
+
* show a map based on a KML file
|
30 |
+
* @param {String} divID the ID of the div that will contain the map
|
31 |
+
* @param {String} kmlFile path to the KML file to load
|
32 |
+
* @param {Number} zoom [optional] zoom level
|
33 |
+
*/
|
34 |
+
showKML: function(divID, kmlFile, zoom) {
|
35 |
+
var map = this.showMap(divID, [0, 0]),
|
36 |
+
kmlLayer = new google.maps.KmlLayer(kmlFile);
|
37 |
+
|
38 |
+
kmlLayer.setMap(map);
|
39 |
+
|
40 |
+
if (typeof zoom != "undefined") {
|
41 |
+
// listen for KML loaded, and reset zoom
|
42 |
+
google.maps.event.addListenerOnce(map, 'tilesloaded', function() {
|
43 |
+
map.setZoom(zoom);
|
44 |
+
});
|
45 |
+
}
|
46 |
+
|
47 |
+
// stop links opening in a new window (thanks, Stack Overflow!)
|
48 |
+
google.maps.event.addListener(kmlLayer, 'click', function(kmlEvent) {
|
49 |
+
kmlEvent.featureData.description = kmlEvent.featureData.description.replace(/ target="_blank"/ig, "");
|
50 |
+
});
|
51 |
+
},
|
52 |
+
|
53 |
+
/**
|
54 |
+
* show a map centred at latitude / longitude and with marker at latitude / longitude
|
55 |
+
* @param {String} divID the ID of the div that will contain the map
|
56 |
+
* @param {Array} centre an array of two integers: [ latitude, longitude ]
|
57 |
+
* @param {Array} marker an array of two integers: [ latitude, longitude ]
|
58 |
+
* @param {String} title the title for the marker
|
59 |
+
*/
|
60 |
+
showMarker: function(divID, centre, marker) {
|
61 |
+
var map = this.showMap(divID, centre),
|
62 |
+
point = new google.maps.Marker({
|
63 |
+
map: map,
|
64 |
+
position: new google.maps.LatLng(marker[0], marker[1])
|
65 |
+
});
|
66 |
+
|
67 |
+
if (this.markerTitle) {
|
68 |
+
var i, len, lines, infowin, element, a,
|
69 |
+
self = this,
|
70 |
+
container = document.createElement("DIV");
|
71 |
+
|
72 |
+
container.style.fontFamily = "Arial,Helvetica,sans-serif";
|
73 |
+
|
74 |
+
// heading for info window
|
75 |
+
element = document.createElement("DIV");
|
76 |
+
element.style.fontWeight = "bold";
|
77 |
+
element.style.fontSize = "medium";
|
78 |
+
element.appendChild(document.createTextNode(this.markerTitle));
|
79 |
+
container.appendChild(element);
|
80 |
+
|
81 |
+
// body of info window, with link
|
82 |
+
if (this.markerDescription || this.markerLink) {
|
83 |
+
element = document.createElement("DIV");
|
84 |
+
element.style.fontSize = "small";
|
85 |
+
if (this.markerDescription) {
|
86 |
+
lines = this.markerDescription.split("\n");
|
87 |
+
for (i = 0, len = lines.length; i < len; i++) {
|
88 |
+
if (i > 0)
|
89 |
+
element.appendChild(document.createElement("BR"));
|
90 |
+
element.appendChild(document.createTextNode(lines[i]));
|
91 |
+
}
|
92 |
+
if (this.markerLink)
|
93 |
+
element.appendChild(document.createElement("BR"));
|
94 |
+
}
|
95 |
+
if (this.markerLink) {
|
96 |
+
a = document.createElement("A");
|
97 |
+
a.href = this.markerLink;
|
98 |
+
a.appendChild(document.createTextNode("Click for details"));
|
99 |
+
element.appendChild(a);
|
100 |
+
}
|
101 |
+
container.appendChild(element);
|
102 |
+
}
|
103 |
+
|
104 |
+
// add a link for directions if wanted
|
105 |
+
if (this.markerDirections) {
|
106 |
+
element = document.createElement("DIV");
|
107 |
+
element.style.fontSize = "small";
|
108 |
+
a = document.createElement("A");
|
109 |
+
a.href = " ";
|
110 |
+
a.dataLatitude = marker[0];
|
111 |
+
a.dataLongitude = marker[1];
|
112 |
+
a.dataTitle = this.markerTitle;
|
113 |
+
a.onclick = function(event) {
|
114 |
+
if (event.preventDefault)
|
115 |
+
event.preventDefault();
|
116 |
+
else
|
117 |
+
event.returnValue = false;
|
118 |
+
|
119 |
+
self.showDirections(this.dataLatitude, this.dataLongitude, this.dataTitle);
|
120 |
+
};
|
121 |
+
a.appendChild(document.createTextNode("Directions"));
|
122 |
+
element.appendChild(a);
|
123 |
+
container.appendChild(element);
|
124 |
+
|
125 |
+
// make sure we have a directions service
|
126 |
+
if (!this.dirService)
|
127 |
+
this.dirService = new google.maps.DirectionsService();
|
128 |
+
if (!this.dirPanel) {
|
129 |
+
this.dirPanel = new google.maps.DirectionsRenderer({
|
130 |
+
map: map,
|
131 |
+
panel: document.getElementById(this.markerDirections)
|
132 |
+
});
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
infowin = new google.maps.InfoWindow({content: container});
|
137 |
+
if (this.markerShowInfo)
|
138 |
+
infowin.open(map, point);
|
139 |
+
|
140 |
+
google.maps.event.addListener(point, "click", function() {
|
141 |
+
infowin.open(map, point);
|
142 |
+
});
|
143 |
+
}
|
144 |
+
},
|
145 |
+
|
146 |
+
/**
|
147 |
+
* show a map at specified centre latitude / longitude
|
148 |
+
* @param {String} divID the ID of the div that will contain the map
|
149 |
+
* @param {Array} centre an array of two integers: [ latitude, longitude ]
|
150 |
+
* @return {google.maps.Map} the Google Maps map created
|
151 |
+
*/
|
152 |
+
showMap: function(divID, centre) {
|
153 |
+
return new google.maps.Map(document.getElementById(divID), {
|
154 |
+
mapTypeId: this.mapTypeId,
|
155 |
+
mapTypeControl: this.mapTypeControl,
|
156 |
+
scaleControl: this.scaleControl,
|
157 |
+
scrollwheel: this.scrollwheel,
|
158 |
+
streetViewControl: this.streetViewControl,
|
159 |
+
navigationControlOptions: this.navigationControlOptions,
|
160 |
+
center: new google.maps.LatLng(centre[0], centre[1]),
|
161 |
+
zoom: this.zoom
|
162 |
+
});
|
163 |
+
},
|
164 |
+
|
165 |
+
/**
|
166 |
+
* show directions for specified latitude / longitude and title
|
167 |
+
* @param {Number} latitude
|
168 |
+
* @param {Number} longitude
|
169 |
+
* @param {String} title
|
170 |
+
*/
|
171 |
+
showDirections: function(latitude, longitude, title) {
|
172 |
+
var panel = document.getElementById(this.markerDirections),
|
173 |
+
form = document.createElement("form"),
|
174 |
+
self = this,
|
175 |
+
region = this.region || '',
|
176 |
+
input, p;
|
177 |
+
|
178 |
+
// remove all from panel
|
179 |
+
while (p = panel.lastChild)
|
180 |
+
panel.removeChild(p);
|
181 |
+
|
182 |
+
// create form and add to panel
|
183 |
+
p = document.createElement("p");
|
184 |
+
p.appendChild(document.createTextNode("From: "));
|
185 |
+
input = document.createElement("input");
|
186 |
+
input.type = "text";
|
187 |
+
input.name = "from";
|
188 |
+
p.appendChild(input);
|
189 |
+
input = document.createElement("input");
|
190 |
+
input.type = "submit";
|
191 |
+
input.value = "Get directions";
|
192 |
+
p.appendChild(input);
|
193 |
+
form.appendChild(p);
|
194 |
+
panel.appendChild(form);
|
195 |
+
form.elements.from.focus();
|
196 |
+
|
197 |
+
// handle the form submit
|
198 |
+
form.onsubmit = function(event) {
|
199 |
+
if (event.preventDefault)
|
200 |
+
event.preventDefault();
|
201 |
+
else
|
202 |
+
event.returnValue = false;
|
203 |
+
|
204 |
+
var from = this.elements.from.value;
|
205 |
+
|
206 |
+
// only process if something was entered to search on
|
207 |
+
if (/\S/.test(from)) {
|
208 |
+
var request = {
|
209 |
+
origin: from,
|
210 |
+
region: region,
|
211 |
+
destination: new google.maps.LatLng(latitude, longitude),
|
212 |
+
travelMode: google.maps.DirectionsTravelMode.DRIVING
|
213 |
+
};
|
214 |
+
self.dirService.route(request, function(response, status) {
|
215 |
+
var DirectionsStatus = google.maps.DirectionsStatus;
|
216 |
+
|
217 |
+
switch (status) {
|
218 |
+
case DirectionsStatus.OK:
|
219 |
+
self.dirPanel.setDirections(response);
|
220 |
+
break;
|
221 |
+
|
222 |
+
case DirectionsStatus.ZERO_RESULTS:
|
223 |
+
alert("No route could be found between the origin and destination.");
|
224 |
+
break;
|
225 |
+
|
226 |
+
case DirectionsStatus.OVER_QUERY_LIMIT:
|
227 |
+
alert("The webpage has gone over the requests limit in too short a period of time.");
|
228 |
+
break;
|
229 |
+
|
230 |
+
case DirectionsStatus.REQUEST_DENIED:
|
231 |
+
alert("The webpage is not allowed to use the directions service.");
|
232 |
+
break;
|
233 |
+
|
234 |
+
case DirectionsStatus.INVALID_REQUEST:
|
235 |
+
alert("Invalid directions request.");
|
236 |
+
break;
|
237 |
+
|
238 |
+
case DirectionsStatus.NOT_FOUND:
|
239 |
+
alert("Origin or destination was not found.");
|
240 |
+
break;
|
241 |
+
|
242 |
+
default:
|
243 |
+
alert("A directions request could not be processed due to a server error. The request may succeed if you try again.");
|
244 |
+
break;
|
245 |
+
}
|
246 |
+
});
|
247 |
+
}
|
248 |
+
};
|
249 |
+
|
250 |
+
}
|
251 |
+
|
252 |
+
};
|
flexible-map.min.js
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
JavaScript for the WordPress plugin wp-flexible-map
|
3 |
+
© 2011 WebAware Pty Ltd, released under LGPL v2.1
|
4 |
+
*/
|
5 |
+
function FlexibleMap(){this.mapTypeId=google.maps.MapTypeId.ROADMAP;this.mapTypeControl=false;this.scaleControl=false;this.streetViewControl=false;this.scrollwheel=false;this.zoom=16;this.markerTitle="";this.markerDescription="";this.markerLink="";this.markerShowInfo=true;this.markerDirections=false;this.navigationControlOptions={style:google.maps.NavigationControlStyle.SMALL};this.dirService=false;this.dirPanel=false;this.region=false}FlexibleMap.prototype={constructor:FlexibleMap,showKML:function(a,e,b){var d=this.showMap(a,[0,0]),c=new google.maps.KmlLayer(e);c.setMap(d);if(typeof b!="undefined"){google.maps.event.addListenerOnce(d,"tilesloaded",function(){d.setZoom(b)})}google.maps.event.addListener(c,"click",function(f){f.featureData.description=f.featureData.description.replace(/ target="_blank"/ig,"")})},showMarker:function(e,d,j){var c=this.showMap(e,d),m=new google.maps.Marker({map:c,position:new google.maps.LatLng(j[0],j[1])});if(this.markerTitle){var h,k,o,f,g,l,n=this,b=document.createElement("DIV");b.style.fontFamily="Arial,Helvetica,sans-serif";g=document.createElement("DIV");g.style.fontWeight="bold";g.style.fontSize="medium";g.appendChild(document.createTextNode(this.markerTitle));b.appendChild(g);if(this.markerDescription||this.markerLink){g=document.createElement("DIV");g.style.fontSize="small";if(this.markerDescription){o=this.markerDescription.split("\n");for(h=0,k=o.length;h<k;h++){if(h>0){g.appendChild(document.createElement("BR"))}g.appendChild(document.createTextNode(o[h]))}if(this.markerLink){g.appendChild(document.createElement("BR"))}}if(this.markerLink){l=document.createElement("A");l.href=this.markerLink;l.appendChild(document.createTextNode("Click for details"));g.appendChild(l)}b.appendChild(g)}if(this.markerDirections){g=document.createElement("DIV");g.style.fontSize="small";l=document.createElement("A");l.href=" ";l.dataLatitude=j[0];l.dataLongitude=j[1];l.dataTitle=this.markerTitle;l.onclick=function(a){if(a.preventDefault){a.preventDefault()}else{a.returnValue=false}n.showDirections(this.dataLatitude,this.dataLongitude,this.dataTitle)};l.appendChild(document.createTextNode("Directions"));g.appendChild(l);b.appendChild(g);if(!this.dirService){this.dirService=new google.maps.DirectionsService()}if(!this.dirPanel){this.dirPanel=new google.maps.DirectionsRenderer({map:c,panel:document.getElementById(this.markerDirections)})}}f=new google.maps.InfoWindow({content:b});if(this.markerShowInfo){f.open(c,m)}google.maps.event.addListener(m,"click",function(){f.open(c,m)})}},showMap:function(a,b){return new google.maps.Map(document.getElementById(a),{mapTypeId:this.mapTypeId,mapTypeControl:this.mapTypeControl,scaleControl:this.scaleControl,scrollwheel:this.scrollwheel,streetViewControl:this.streetViewControl,navigationControlOptions:this.navigationControlOptions,center:new google.maps.LatLng(b[0],b[1]),zoom:this.zoom})},showDirections:function(e,a,g){var b=document.getElementById(this.markerDirections),d=document.createElement("form"),i=this,f=this.region||"",h,c;while(c=b.lastChild){b.removeChild(c)}c=document.createElement("p");c.appendChild(document.createTextNode("From: "));h=document.createElement("input");h.type="text";h.name="from";c.appendChild(h);h=document.createElement("input");h.type="submit";h.value="Get directions";c.appendChild(h);d.appendChild(c);b.appendChild(d);d.elements.from.focus();d.onsubmit=function(k){if(k.preventDefault){k.preventDefault()}else{k.returnValue=false}var l=this.elements.from.value;if(/\S/.test(l)){var j={origin:l,region:f,destination:new google.maps.LatLng(e,a),travelMode:google.maps.DirectionsTravelMode.DRIVING};i.dirService.route(j,function(o,m){var n=google.maps.DirectionsStatus;switch(m){case n.OK:i.dirPanel.setDirections(o);break;case n.ZERO_RESULTS:alert("No route could be found between the origin and destination.");break;case n.OVER_QUERY_LIMIT:alert("The webpage has gone over the requests limit in too short a period of time.");break;case n.REQUEST_DENIED:alert("The webpage is not allowed to use the directions service.");break;case n.INVALID_REQUEST:alert("Invalid directions request.");break;case n.NOT_FOUND:alert("Origin or destination was not found.");break;default:alert("A directions request could not be processed due to a server error. The request may succeed if you try again.");break}})}}}};
|
flexible-map.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Flexible Map
|
4 |
+
Plugin URI: http://snippets.webaware.com.au/wordpress-plugins/wp-flexible-map/
|
5 |
+
Description: Flexible map using Google Maps, for displaying a map specified by centre coodinates or by Google Earth KML file.
|
6 |
+
Version: 1.0.0
|
7 |
+
Author: WebAware Pty Ltd
|
8 |
+
Author URI: http://www.webaware.com.au/
|
9 |
+
*/
|
10 |
+
|
11 |
+
/*
|
12 |
+
copyright (c) 2011-2012 WebAware Pty Ltd (email : rmckay@webaware.com.au)
|
13 |
+
|
14 |
+
This program is free software; you can redistribute it and/or modify
|
15 |
+
it under the terms of the GNU General Public License, version 2, as
|
16 |
+
published by the Free Software Foundation.
|
17 |
+
|
18 |
+
This program is distributed in the hope that it will be useful,
|
19 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
20 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
21 |
+
GNU General Public License for more details.
|
22 |
+
|
23 |
+
You should have received a copy of the GNU General Public License
|
24 |
+
along with this program; if not, write to the Free Software
|
25 |
+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
26 |
+
*/
|
27 |
+
|
28 |
+
if (!defined('FLXMAP_PLUGIN_ROOT')) {
|
29 |
+
define('FLXMAP_PLUGIN_ROOT', dirname(__FILE__) . '/');
|
30 |
+
define('FLXMAP_PLUGIN_NAME', basename(dirname(__FILE__)) . '/' . basename(__FILE__));
|
31 |
+
|
32 |
+
// shortcode tags
|
33 |
+
define('FLXMAP_PLUGIN_TAG_MAP', 'flexiblemap');
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* autoload classes as/when needed
|
38 |
+
*
|
39 |
+
* use clues from names of library classes to locate them
|
40 |
+
*
|
41 |
+
* @param string $class_name name of class to attempt to load
|
42 |
+
*/
|
43 |
+
function flxmap_autoload($class_name) {
|
44 |
+
static $classMap = array (
|
45 |
+
'FlxMapAdmin' => 'class.FlxMapAdmin.php',
|
46 |
+
'FlxMapPlugin' => 'class.FlxMapPlugin.php',
|
47 |
+
);
|
48 |
+
|
49 |
+
if (isset($classMap[$class_name])) {
|
50 |
+
require FLXMAP_PLUGIN_ROOT . $classMap[$class_name];
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
// register a class (static) method for autoloading required classes
|
55 |
+
spl_autoload_register('flxmap_autoload');
|
56 |
+
|
57 |
+
// instantiate the plug-in
|
58 |
+
$FlxMapPlugin = FlxMapPlugin::getInstance();
|
59 |
+
|
60 |
+
// register plug-in activation / deactivation
|
61 |
+
register_activation_hook(__FILE__, array($FlxMapPlugin, 'activate'));
|
62 |
+
register_deactivation_hook(__FILE__, array($FlxMapPlugin, 'deactivate'));
|
63 |
+
|
64 |
+
/**
|
65 |
+
* utility function so themes can easily display the map
|
66 |
+
* @param array $attrs
|
67 |
+
*/
|
68 |
+
function flexmap_show_map($attrs) {
|
69 |
+
echo apply_filters('flexmap_getmap', $attrs);
|
70 |
+
}
|
instructions.html
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<style type="text/css">
|
2 |
+
.flxmap-instructions-parameters dt {
|
3 |
+
font-weight: bold;
|
4 |
+
}
|
5 |
+
.flxmap-instructions-parameters dd {
|
6 |
+
margin-left: 1.5em;
|
7 |
+
}
|
8 |
+
.flxmap-instructions-parameters code {
|
9 |
+
font-family: "Liberation Mono", monospace;
|
10 |
+
font-size: 110%;
|
11 |
+
}
|
12 |
+
</style>
|
13 |
+
|
14 |
+
<p>To add a Flexible Map to a post or a page, add a shortcode [flexiblemap] and give it some useful parameters.</p>
|
15 |
+
<p>Map can either be specified using centre coordinates, or by loading a KML file.</p>
|
16 |
+
|
17 |
+
<h3>Parameters for centre coordinates map:</h3>
|
18 |
+
<dl class="flxmap-instructions-parameters">
|
19 |
+
<dt>width</dt>
|
20 |
+
<dd>width in pixels, e.g. <em>width="500"</em></dd>
|
21 |
+
<dt>height</dt>
|
22 |
+
<dd>height in pixels, e.g. <em>height="400"</em></dd>
|
23 |
+
<dt>center</dt>
|
24 |
+
<dd>coordinates of centre in latitude,longitude, e.g. <em>center="-34.916721,138.828878"</em></dd>
|
25 |
+
<dt>marker</dt>
|
26 |
+
<dd>coordinates of the marker if different from the centre, in latitude,longitude, e.g. <em>marker="-34.916721,138.828878"</em></dd>
|
27 |
+
<dt>title</dt>
|
28 |
+
<dd>title of the marker, displayed in a text bubble, e.g. <em>title="Adelaide Hills"</em></dd>
|
29 |
+
<dt>link</dt>
|
30 |
+
<dd>URL to link from the marker title, e.g. <em>link="http://example.com/"</em></dd>
|
31 |
+
<dt>description</dt>
|
32 |
+
<dd>a description of the marker location (can have HTML links), e.g. <em>description="Lorem ipsum dolor sit amet"</em></dd>
|
33 |
+
<dt>directions</dt>
|
34 |
+
<dd>show directions link in text bubble; by default, directions will be displayed underneath map, but you can specify the element ID for directions here.</dd>
|
35 |
+
<dt>zoom</dt>
|
36 |
+
<dd>zoom level as an integer, larger is closer, e.g. <em>zoom="16"</em></dd>
|
37 |
+
<dt>maptype</dt>
|
38 |
+
<dd>type of map to show, from [roadmap, satellite], e.g. <em>maptype="roadmap"</em></dd>
|
39 |
+
<dt>hideMapType</dt>
|
40 |
+
<dd>hide the map type controls, from [true, false], e.g. <em>hideMapType="true"</em></dd>
|
41 |
+
<dt>Samples:</dt>
|
42 |
+
<dd><code>[flexiblemap center="-34.916721,138.828878" width="500" height="400" zoom="9" title="Adelaide Hills" description="The Adelaide Hills are repleat with wineries."]</code></dd>
|
43 |
+
<dd><code>[flexiblemap center="-34.916721,138.828878" width="500" height="400" title="Adelaide Hills" directions="true"]</code></dd>
|
44 |
+
<dd><code>[flexiblemap center="-34.916721,138.828878" width="500" height="400" title="Adelaide Hills" directions="my-dir-div"]</code></dd>
|
45 |
+
</dl>
|
46 |
+
|
47 |
+
<hr />
|
48 |
+
|
49 |
+
<h3>Parameters for KML map:</h3>
|
50 |
+
<dl class="flxmap-instructions-parameters">
|
51 |
+
<dt>width</dt>
|
52 |
+
<dd>width in pixels, e.g. <em>width="500"</em></dd>
|
53 |
+
<dt>height</dt>
|
54 |
+
<dd>height in pixels, e.g. <em>height="400"</em></dd>
|
55 |
+
<dt>src</dt>
|
56 |
+
<dd>URL for KML file to load map details from, e.g. <em>src="http://example.com/map.kml"</em></dd>
|
57 |
+
<dt>zoom</dt>
|
58 |
+
<dd>zoom level as an integer, larger is closer, e.g. <em>zoom="16"</em></dd>
|
59 |
+
<dt>maptype</dt>
|
60 |
+
<dd>type of map to show, from [roadmap, satellite], e.g. <em>maptype="roadmap"</em></dd>
|
61 |
+
<dt>hideMapType</dt>
|
62 |
+
<dd>hide the map type controls, from [true, false], e.g. <em>hideMapType="true"</em></dd>
|
63 |
+
<dt>Sample:</dt>
|
64 |
+
<dd><code>[flexiblemap src="http://code.google.com/apis/kml/documentation/KML_Samples.kml" width="500" height="400"]</code></dd>
|
65 |
+
</dl>
|
readme.txt
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== WP Flexible Map ===
|
2 |
+
Contributors: webaware
|
3 |
+
Plugin Name: WP Flexible Map
|
4 |
+
Plugin URI: http://snippets.webaware.com.au/wordpress-plugins/wp-flexible-map/
|
5 |
+
Author URI: http://www.webaware.com.au/
|
6 |
+
Tags: google, maps, shortcode, kml
|
7 |
+
Requires at least: 3.0.1
|
8 |
+
Tested up to: 3.3.1
|
9 |
+
Stable tag: 1.0.0
|
10 |
+
|
11 |
+
Flexible map using Google Maps, for displaying a map specified by centre coodinates or by Google Earth KML file.
|
12 |
+
|
13 |
+
== Description ==
|
14 |
+
|
15 |
+
Flexible map using Google Maps, for displaying a map specified by centre coodinates or by Google Earth KML file.
|
16 |
+
|
17 |
+
== Instructions ==
|
18 |
+
|
19 |
+
To add a Flexible Map to a post or a page, add a shortcode [flexiblemap] and give it some useful parameters. Map can either be specified using centre coordinates, or by loading a KML file.
|
20 |
+
|
21 |
+
**Parameters for centre coordinates map:**
|
22 |
+
|
23 |
+
* *width*
|
24 |
+
* width in pixels, e.g. *width="500"*
|
25 |
+
* *height*
|
26 |
+
* height in pixels, e.g. *height="400"*
|
27 |
+
* *center*
|
28 |
+
* coordinates of centre in latitude,longitude, e.g. *center="-34.916721,138.828878"*
|
29 |
+
* *marker*
|
30 |
+
* coordinates of the marker if different from the centre, in latitude,longitude, e.g. *marker="-34.916721,138.828878"*
|
31 |
+
* *title*
|
32 |
+
* title of the marker, displayed in a text bubble, e.g. *title="Adelaide Hills"*
|
33 |
+
* *link*
|
34 |
+
* URL to link from the marker title, e.g. *link="http://example.com/"*
|
35 |
+
* *description*
|
36 |
+
* a description of the marker location (can have HTML links), e.g. *description="Lorem ipsum dolor sit amet"*
|
37 |
+
* *directions*
|
38 |
+
* show directions link in text bubble; by default, directions will be displayed underneath map, but you can specify the element ID for directions here.
|
39 |
+
* *zoom*
|
40 |
+
* zoom level as an integer, larger is closer, e.g. *zoom="16"*
|
41 |
+
* *maptype*
|
42 |
+
* type of map to show, from [roadmap, satellite], e.g. *maptype="roadmap"*
|
43 |
+
* *hideMapType*
|
44 |
+
* hide the map type controls, from [true, false], e.g. *hideMapType="true"*
|
45 |
+
|
46 |
+
*Samples*:
|
47 |
+
`[flexiblemap center="-34.916721,138.828878" width="500" height="400" zoom="9" title="Adelaide Hills" description="The Adelaide Hills are repleat with wineries."]
|
48 |
+
[flexiblemap center="-34.916721,138.828878" width="500" height="400" title="Adelaide Hills" directions="true"]
|
49 |
+
[flexiblemap center="-34.916721,138.828878" width="500" height="400" title="Adelaide Hills" directions="my-dir-div"]`
|
50 |
+
|
51 |
+
**Parameters for KML map:**
|
52 |
+
|
53 |
+
* *width*
|
54 |
+
* width in pixels, e.g. *width="500"*
|
55 |
+
* *height*
|
56 |
+
* height in pixels, e.g. *height="400"*
|
57 |
+
* *src*
|
58 |
+
* URL for KML file to load map details from, e.g. *src="http://example.com/map.kml"*
|
59 |
+
* *zoom*
|
60 |
+
* zoom level as an integer, larger is closer, e.g. *zoom="16"*
|
61 |
+
* *maptype*
|
62 |
+
* type of map to show, from [roadmap, satellite], e.g. *maptype="roadmap"*
|
63 |
+
* *hideMapType*
|
64 |
+
* hide the map type controls, from [true, false], e.g. *hideMapType="true"*
|
65 |
+
|
66 |
+
*Sample*:
|
67 |
+
`[flexiblemap src="http://code.google.com/apis/kml/documentation/KML_Samples.kml" width="500" height="400"]`
|
68 |
+
|
69 |
+
== Changelog ==
|
70 |
+
|
71 |
+
= 1.0.0 [2012-01-08] =
|
72 |
+
* final cleanup for public release
|