Flexible Map - Version 1.9.0

Version Description

[2014-12-24] = * fixed: maps broken when hidden in tabs / accordions (not for IE 10 and earlier; uses MutationObserver) * fixed: strip spaces from map coordinates * fixed: suppress border radius on images within map containers * added: server-side lookup of address, to reduce the number of Google Maps queries when only an address is given * added: support for custom map types (inc. styled maps) * added: maptypes attribute for selecting which map types can be picked by visitors * changed: refactored JavaScript for localised strings

Download this release

Release Info

Developer webaware
Plugin Icon 128x128 Flexible Map
Version 1.9.0
Comparing to
See all releases

Code changes from version 1.8.3 to 1.9.0

css/styles.css CHANGED
@@ -12,6 +12,7 @@
12
  -moz-box-shadow: none !important;
13
  box-shadow: none !important;
14
  background-color: transparent !important;
 
15
  }
16
 
17
  .site-content .flxmap-directions img.adp-marker,
12
  -moz-box-shadow: none !important;
13
  box-shadow: none !important;
14
  background-color: transparent !important;
15
+ border-radius: 0px !important;
16
  }
17
 
18
  .site-content .flxmap-directions img.adp-marker,
flexible-map.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Flexible Map
4
  Plugin URI: http://flexible-map.webaware.net.au/
5
  Description: Embed Google Maps in pages and posts, either by centre coodinates or street address, or by URL to a Google Earth KML file.
6
- Version: 1.8.3
7
  Author: WebAware
8
  Author URI: http://webaware.com.au/
9
  Text Domain: flexible-map
@@ -36,7 +36,7 @@ if (!defined('ABSPATH')) {
36
  define('FLXMAP_PLUGIN_FILE', __FILE__);
37
  define('FLXMAP_PLUGIN_ROOT', dirname(__FILE__) . '/');
38
  define('FLXMAP_PLUGIN_NAME', basename(dirname(__FILE__)) . '/' . basename(__FILE__));
39
- define('FLXMAP_PLUGIN_VERSION', '1.8.3');
40
 
41
  // shortcode tags
42
  define('FLXMAP_PLUGIN_TAG_MAP', 'flexiblemap');
3
  Plugin Name: Flexible Map
4
  Plugin URI: http://flexible-map.webaware.net.au/
5
  Description: Embed Google Maps in pages and posts, either by centre coodinates or street address, or by URL to a Google Earth KML file.
6
+ Version: 1.9.0
7
  Author: WebAware
8
  Author URI: http://webaware.com.au/
9
  Text Domain: flexible-map
36
  define('FLXMAP_PLUGIN_FILE', __FILE__);
37
  define('FLXMAP_PLUGIN_ROOT', dirname(__FILE__) . '/');
38
  define('FLXMAP_PLUGIN_NAME', basename(dirname(__FILE__)) . '/' . basename(__FILE__));
39
+ define('FLXMAP_PLUGIN_VERSION', '1.9.0');
40
 
41
  // shortcode tags
42
  define('FLXMAP_PLUGIN_TAG_MAP', 'flexiblemap');
includes/class.FlxMapPlugin.php CHANGED
@@ -6,7 +6,8 @@ class FlxMapPlugin {
6
  public $urlBase; // string: base URL path to files in plugin
7
 
8
  protected $locale; // locale of current website
9
- protected $locales = array(); // list of locales enqueued for localisation of maps
 
10
 
11
  /**
12
  * static method for getting the instance of this singleton object
@@ -103,7 +104,7 @@ class FlxMapPlugin {
103
  }
104
 
105
  /**
106
- * load any enqueued locales as localisations on the main script
107
  */
108
  public function justInTimeLocalisation() {
109
  if (!empty($this->locales)) {
@@ -144,6 +145,11 @@ class FlxMapPlugin {
144
  // TODO: handle plurals (not yet needed, don't have any)
145
  $strings = array();
146
  foreach ($mo->entries as $original => $translation) {
 
 
 
 
 
147
  $strings[$original] = $translation->translations[0];
148
  }
149
  $i18n[$locale] = $strings;
@@ -153,8 +159,17 @@ class FlxMapPlugin {
153
  }
154
  }
155
 
 
 
156
  if (!empty($i18n)) {
157
- wp_localize_script('flxmap', 'flxmap', array('i18n' => $i18n));
 
 
 
 
 
 
 
158
  }
159
  }
160
  }
@@ -178,9 +193,12 @@ class FlxMapPlugin {
178
  public function getMap($attrs) {
179
  $html = '';
180
 
181
- // allow others to change the shortcode attributes used
182
  $attrs = apply_filters('flexmap_shortcode_attrs', $attrs);
183
 
 
 
 
184
  if (!empty($attrs['src']) || !empty($attrs['center']) || !empty($attrs['address'])) {
185
  $this->loadScripts = true;
186
  if (empty($attrs['id'])) {
@@ -324,6 +342,10 @@ HTML;
324
  $script .= " f.mapTypeId = \"{$this->str2js($attrs['maptype'])}\";\n";
325
  }
326
 
 
 
 
 
327
  if (isset($attrs['region'])) {
328
  $script .= " f.region = \"{$this->str2js($attrs['region'])}\";\n";
329
  }
@@ -339,11 +361,20 @@ HTML;
339
  $this->enqueueLocale($locale);
340
  }
341
 
 
 
 
 
 
 
 
 
 
342
  // add map based on coordinates, with optional marker coordinates
343
  if (isset($attrs['center']) && self::isCoordinates($attrs['center'])) {
344
- $marker = self::str2js($attrs['center']);
345
  if (isset($attrs['marker']) && self::isCoordinates($attrs['marker']))
346
- $marker = self::str2js($attrs['marker']);
347
 
348
  if (isset($attrs['zoom']))
349
  $script .= " f.zoom = " . preg_replace('/\D/', '', $attrs['zoom']) . ";\n";
@@ -489,6 +520,63 @@ HTML;
489
  return $units;
490
  }
491
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
492
  /**
493
  * test string to see if contents equate to yes/true
494
  * @param string $text
@@ -513,7 +601,19 @@ HTML;
513
  * @return boolean
514
  */
515
  public static function isCoordinates($text) {
516
- return preg_match('/^-?\\d+(?:\\.\\d+),-?\\d+(?:\\.\\d+)$/', $text);
 
 
 
 
 
 
 
 
 
 
 
 
517
  }
518
 
519
  /**
6
  public $urlBase; // string: base URL path to files in plugin
7
 
8
  protected $locale; // locale of current website
9
+ protected $locales = array(); // list of locales enqueued for localisation of maps
10
+ protected $mapTypes = array(); // custom Google Maps map types to be loaded with maps, keyed by mapTypeId
11
 
12
  /**
13
  * static method for getting the instance of this singleton object
104
  }
105
 
106
  /**
107
+ * load any enqueued locales and map types as localisations on the main script
108
  */
109
  public function justInTimeLocalisation() {
110
  if (!empty($this->locales)) {
145
  // TODO: handle plurals (not yet needed, don't have any)
146
  $strings = array();
147
  foreach ($mo->entries as $original => $translation) {
148
+ // skip admin-side strings, identified by context
149
+ if ($translation->context == 'plugin details links') {
150
+ continue;
151
+ }
152
+
153
  $strings[$original] = $translation->translations[0];
154
  }
155
  $i18n[$locale] = $strings;
159
  }
160
  }
161
 
162
+ // build and enqueue localisations for map script
163
+ $localise = array();
164
  if (!empty($i18n)) {
165
+ $localise['i18n'] = $i18n;
166
+ }
167
+ if (!empty($this->mapTypes)) {
168
+ $localise['mapTypes'] = $this->mapTypes;
169
+ }
170
+
171
+ if (!empty($localise)) {
172
+ wp_localize_script('flxmap', 'flxmap', $localise);
173
  }
174
  }
175
  }
193
  public function getMap($attrs) {
194
  $html = '';
195
 
196
+ // allow plugins / themes to change the shortcode attributes used
197
  $attrs = apply_filters('flexmap_shortcode_attrs', $attrs);
198
 
199
+ // allow plugins / themes to register custom Google Maps map types
200
+ $this->mapTypes = apply_filters('flexmap_custom_map_types', $this->mapTypes, $attrs);
201
+
202
  if (!empty($attrs['src']) || !empty($attrs['center']) || !empty($attrs['address'])) {
203
  $this->loadScripts = true;
204
  if (empty($attrs['id'])) {
342
  $script .= " f.mapTypeId = \"{$this->str2js($attrs['maptype'])}\";\n";
343
  }
344
 
345
+ if (isset($attrs['maptypes'])) {
346
+ $script .= " f.mapTypeIds = \"{$this->str2js($attrs['maptypes'])}\";\n";
347
+ }
348
+
349
  if (isset($attrs['region'])) {
350
  $script .= " f.region = \"{$this->str2js($attrs['region'])}\";\n";
351
  }
361
  $this->enqueueLocale($locale);
362
  }
363
 
364
+ // if have address but not coordinates, attempt to retrieve coordinates for address
365
+ if (empty($attrs['center']) && !empty($attrs['address'])) {
366
+ $region = empty($attrs['region']) ? '' : $attrs['region'];
367
+ $center = self::getAddressCoordinates($attrs['address'], $region);
368
+ if ($center) {
369
+ $attrs['center'] = implode(',', $center);
370
+ }
371
+ }
372
+
373
  // add map based on coordinates, with optional marker coordinates
374
  if (isset($attrs['center']) && self::isCoordinates($attrs['center'])) {
375
+ $marker = self::str2js(self::getCoordinates($attrs['center']));
376
  if (isset($attrs['marker']) && self::isCoordinates($attrs['marker']))
377
+ $marker = self::str2js(self::getCoordinates($attrs['marker']));
378
 
379
  if (isset($attrs['zoom']))
380
  $script .= " f.zoom = " . preg_replace('/\D/', '', $attrs['zoom']) . ";\n";
520
  return $units;
521
  }
522
 
523
+ /**
524
+ * get coordinate for given address
525
+ * @param string $address
526
+ * @param string $region
527
+ * @return array|false
528
+ */
529
+ protected static function getAddressCoordinates($address, $region) {
530
+ // try to get a cached answer first
531
+ $cacheKey = 'flxmap_' . md5("$address|$region");
532
+ $coords = get_transient($cacheKey);
533
+
534
+ if ($coords === false) {
535
+ // build Google Maps geocoding query
536
+ $args = array('address' => urlencode($address));
537
+ if (!empty($region)) {
538
+ $args['region'] = urlencode($region);
539
+ }
540
+ $url = add_query_arg($args, 'https://maps.googleapis.com/maps/api/geocode/json');
541
+
542
+ try {
543
+ // fetch coordinates
544
+ $response = wp_remote_get($url);
545
+
546
+ if (is_wp_error($response)) {
547
+ throw new Exception('http error = ' . $response->get_error_message());
548
+ }
549
+
550
+ $result = json_decode($response['body']);
551
+ if (!$result) {
552
+ throw new Exception("error decoding JSON\n" . $response['body']);
553
+ }
554
+
555
+ if ($result->status != 'OK') {
556
+ throw new Exception("error retrieving address: " . $result->status);
557
+ }
558
+
559
+ // success, return array with latitude and longitude
560
+ $location = $result->results[0]->geometry->location;
561
+ $coords = array($location->lat, $location->lng);
562
+ }
563
+ catch (Exception $e) {
564
+ $coords = "address: $address; " . $e->getMessage();
565
+ error_log(__METHOD__ . ': ' . $coords);
566
+ }
567
+
568
+ // save coordinates to prevent unnecessary requery
569
+ set_transient($cacheKey, $coords, WEEK_IN_SECONDS);
570
+ }
571
+
572
+ // handle failure to map address to coordinates by returning false
573
+ if (!is_array($coords)) {
574
+ $coords = false;
575
+ }
576
+
577
+ return $coords;
578
+ }
579
+
580
  /**
581
  * test string to see if contents equate to yes/true
582
  * @param string $text
601
  * @return boolean
602
  */
603
  public static function isCoordinates($text) {
604
+ // TODO: handle degrees minutes seconds, degrees minutes.decimal, NSEW
605
+ return preg_match('/^-?[0-9]+(?:\.[0-9]+),\s*-?[0-9]+(?:\.[0-9]+)$/', $text);
606
+ }
607
+
608
+ /**
609
+ * return standardised coordinates from text
610
+ * NB: assumes text passes isCoordinates() above
611
+ * @param string $text
612
+ * @return boolean
613
+ */
614
+ protected static function getCoordinates($text) {
615
+ // TODO: handle degrees minutes seconds, degrees minutes.decimal, NSEW
616
+ return str_replace(' ', '', $text);
617
  }
618
 
619
  /**
js/flexible-map.js CHANGED
@@ -10,6 +10,8 @@ function FlexibleMap() {
10
  var map, // google.maps.Map object
11
  centre, // google.maps.LatLng object for map centre
12
  markerLocation, // google.maps.LatLng object for single marker, when using showMarker()
 
 
13
  kmlLayer, // if map has a KML layer, this is the layer object
14
  hasRedrawn = false; // boolean, whether map has been asked to redrawOnce() already
15
 
@@ -54,6 +56,38 @@ function FlexibleMap() {
54
  return markerLocation;
55
  };
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  /**
58
  * get the map's KML layer if set
59
  * @return {google.maps.KmlLayer}
@@ -81,35 +115,49 @@ function FlexibleMap() {
81
  this.showMap = function(divID, latLng) {
82
  centre = new google.maps.LatLng(latLng[0], latLng[1]);
83
 
84
- // style the zoom control
85
- var zoomControlStyle, zoomControlStyles = {
86
- "small" : google.maps.ZoomControlStyle.SMALL,
87
- "large" : google.maps.ZoomControlStyle.LARGE,
88
- "default" : google.maps.ZoomControlStyle.DEFAULT
 
89
  };
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  if (this.zoomControlStyle in zoomControlStyles) {
92
- zoomControlStyle = zoomControlStyles[this.zoomControlStyle];
93
  }
94
- else {
95
- zoomControlStyle = zoomControlStyles.small;
 
 
 
 
96
  }
97
 
98
  // create a map
99
- map = new google.maps.Map(document.getElementById(divID), {
100
- mapTypeId: this.mapTypeId,
101
- mapTypeControl: this.mapTypeControl,
102
- scaleControl: this.scaleControl,
103
- panControl: this.panControl,
104
- streetViewControl: this.streetViewControl,
105
- zoomControl: this.zoomControl,
106
- zoomControlOptions: { style: zoomControlStyle },
107
- draggable: this.draggable,
108
- disableDoubleClickZoom: !this.dblclickZoom,
109
- scrollwheel: this.scrollwheel,
110
- center: centre,
111
- zoom: this.zoom
112
- });
113
 
114
  return map;
115
  };
@@ -132,6 +180,11 @@ function FlexibleMap() {
132
  return kmlLayer;
133
  };
134
 
 
 
 
 
 
135
  // set map defaults
136
  this.mapTypeId = google.maps.MapTypeId.ROADMAP;
137
  this.mapTypeControl = true; // no control for changing map type
@@ -163,14 +216,14 @@ function FlexibleMap() {
163
  this.dirShowSearch = true; // show the directions form for searching directions
164
  this.region = "";
165
  this.locale = "en";
166
- this.localeActive = "en";
167
  this.kmlcache = "none";
168
  }
169
 
170
  FlexibleMap.prototype = (function() {
171
  "use strict";
172
 
173
- var addEventListener, stopEvent;
174
 
175
  // detect standard event model
176
  if (document.addEventListener) {
@@ -196,6 +249,41 @@ FlexibleMap.prototype = (function() {
196
  };
197
  }
198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  /**
200
  * encode special JavaScript characters, so text is safe when building JavaScript/HTML dynamically
201
  * NB: conservatively assumes that HTML special characters are unsafe, and encodes them too
@@ -279,15 +367,39 @@ FlexibleMap.prototype = (function() {
279
  /**
280
  * collection of locale / phrase mapping for internationalisation of messages
281
  */
282
- i18n: {
283
- "en": {
284
- "Click for details" : "Click for details",
285
- "Directions" : "Directions",
286
- "From" : "From",
287
- "Get directions" : "Get directions"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  }
 
 
289
  },
290
- i18n_loaded: false, // set to true once localisations have been loaded
291
 
292
  /**
293
  * set the locale used for i18n phrase lookup, picking the best match
@@ -297,14 +409,6 @@ FlexibleMap.prototype = (function() {
297
  setlocale: function(localeWanted) {
298
  this.locale = localeWanted;
299
 
300
- // load localisations if they haven't already been loaded
301
- if (!this.i18n_loaded && "flxmap" in window) {
302
- for (var locale in flxmap.i18n) {
303
- this.i18n[locale] = flxmap.i18n[locale];
304
- }
305
- FlexibleMap.prototype.i18n_loaded = true;
306
- }
307
-
308
  // attempt to set this locale as active
309
  if (localeWanted in this.i18n) {
310
  this.localeActive = localeWanted;
@@ -316,8 +420,8 @@ FlexibleMap.prototype = (function() {
316
  this.localeActive = localeWanted;
317
  }
318
  else {
319
- // still not found, use default (en)
320
- this.localeActive = "en";
321
  }
322
  }
323
 
@@ -330,10 +434,11 @@ FlexibleMap.prototype = (function() {
330
  * @return {String}
331
  */
332
  gettext: function(key) {
333
- var phrases = this.i18n[this.localeActive];
334
 
335
- if (key in phrases)
336
- return phrases[key];
 
337
 
338
  return key;
339
  },
@@ -354,6 +459,8 @@ FlexibleMap.prototype = (function() {
354
  map = this.showMap(divID, [0, 0]),
355
  kmlLayer = this.loadKmlMap(kmlCacheBuster(kmlFileURL, this.kmlcache));
356
 
 
 
357
  // set zoom if specified
358
  if (typeof zoom != "undefined") {
359
  // listen for zoom changing to fit markers on KML layer, force it back to what we asked for
@@ -423,8 +530,10 @@ FlexibleMap.prototype = (function() {
423
  icon: this.markerIcon
424
  });
425
 
 
426
  this.setMarkerLocation(markerLocation);
427
 
 
428
 
429
  if (!this.markerTitle) {
430
  this.markerTitle = this.markerAddress;
@@ -505,6 +614,7 @@ FlexibleMap.prototype = (function() {
505
  }
506
 
507
  infowin = new google.maps.InfoWindow({content: container});
 
508
 
509
  if (this.markerShowInfo) {
510
  // open after map is loaded, so that infowindow will auto-pan and won't be cropped at top
@@ -594,6 +704,12 @@ FlexibleMap.prototype = (function() {
594
  else {
595
  map.setCenter(this.getCenter());
596
  map.setZoom(this.zoom);
 
 
 
 
 
 
597
  }
598
  },
599
 
10
  var map, // google.maps.Map object
11
  centre, // google.maps.LatLng object for map centre
12
  markerLocation, // google.maps.LatLng object for single marker, when using showMarker()
13
+ markerPoint, // google.maps.Marker object for single marker, when using showMarker()
14
+ markerInfowin, // google.maps.InfoWindow object for single marker, when using showMarker()
15
  kmlLayer, // if map has a KML layer, this is the layer object
16
  hasRedrawn = false; // boolean, whether map has been asked to redrawOnce() already
17
 
56
  return markerLocation;
57
  };
58
 
59
+ /**
60
+ * record the single marker point
61
+ * @param {google.maps.Marker} point
62
+ */
63
+ this.setMarkerPoint = function(point) {
64
+ markerPoint = point;
65
+ };
66
+
67
+ /**
68
+ * get the single marker point
69
+ * @return {google.maps.Marker}
70
+ */
71
+ this.getMarkerPoint = function() {
72
+ return markerPoint;
73
+ };
74
+
75
+ /**
76
+ * record the single marker infowindow
77
+ * @param {google.maps.InfoWindow} infowin
78
+ */
79
+ this.setMarkerInfowin = function(infowin) {
80
+ markerInfowin = infowin;
81
+ };
82
+
83
+ /**
84
+ * get the single marker infowindow
85
+ * @return {google.maps.InfoWindow}
86
+ */
87
+ this.getMarkerInfowin = function() {
88
+ return markerInfowin;
89
+ };
90
+
91
  /**
92
  * get the map's KML layer if set
93
  * @return {google.maps.KmlLayer}
115
  this.showMap = function(divID, latLng) {
116
  centre = new google.maps.LatLng(latLng[0], latLng[1]);
117
 
118
+ var mapOptions,
119
+ zoomControlStyle,
120
+ zoomControlStyles = {
121
+ "small" : google.maps.ZoomControlStyle.SMALL,
122
+ "large" : google.maps.ZoomControlStyle.LARGE,
123
+ "default" : google.maps.ZoomControlStyle.DEFAULT
124
  };
125
 
126
+ // basic options
127
+ mapOptions = {
128
+ mapTypeId: this.mapTypeId,
129
+ mapTypeControl: this.mapTypeControl,
130
+ scaleControl: this.scaleControl,
131
+ panControl: this.panControl,
132
+ streetViewControl: this.streetViewControl,
133
+ zoomControl: zoomControlStyles.small,
134
+ zoomControlOptions: { style: zoomControlStyle },
135
+ draggable: this.draggable,
136
+ disableDoubleClickZoom: !this.dblclickZoom,
137
+ scrollwheel: this.scrollwheel,
138
+ center: centre,
139
+ zoom: this.zoom
140
+ };
141
+
142
+ // style the zoom control
143
  if (this.zoomControlStyle in zoomControlStyles) {
144
+ mapOptions.zoomControlStyle = zoomControlStyles[this.zoomControlStyle];
145
  }
146
+
147
+ // select which map types for map type control, if specified as comma-separated list of map type IDs
148
+ if (this.mapTypeIds) {
149
+ mapOptions.mapTypeControlOptions = {
150
+ mapTypeIds: this.mapTypeIds.split(",")
151
+ };
152
  }
153
 
154
  // create a map
155
+ map = new google.maps.Map(document.getElementById(divID), mapOptions);
156
+
157
+ // set custom map type if specified
158
+ if (this.mapTypeId in this.mapTypes) {
159
+ map.mapTypes.set(this.mapTypeId, this.mapTypes[this.mapTypeId]._styled_map);
160
+ }
 
 
 
 
 
 
 
 
161
 
162
  return map;
163
  };
180
  return kmlLayer;
181
  };
182
 
183
+ // load localisations if they haven't already been loaded
184
+ if (!this.localised && "flxmap" in window) {
185
+ this.localise();
186
+ }
187
+
188
  // set map defaults
189
  this.mapTypeId = google.maps.MapTypeId.ROADMAP;
190
  this.mapTypeControl = true; // no control for changing map type
216
  this.dirShowSearch = true; // show the directions form for searching directions
217
  this.region = "";
218
  this.locale = "en";
219
+ this.localeActive = false;
220
  this.kmlcache = "none";
221
  }
222
 
223
  FlexibleMap.prototype = (function() {
224
  "use strict";
225
 
226
+ var addEventListener, stopEvent, handleHiddenMap;
227
 
228
  // detect standard event model
229
  if (document.addEventListener) {
249
  };
250
  }
251
 
252
+ // handle hidden maps, trigger a resize on first display
253
+ if (typeof MutationObserver !== "undefined") {
254
+ handleHiddenMap = function(flxmap, divID) {
255
+ var mapDiv = document.getElementById(divID),
256
+ container = mapDiv.parentNode,
257
+ observer;
258
+
259
+ function isHidden(element) {
260
+ var style = window.getComputedStyle(element);
261
+ return style.display === "none";
262
+ }
263
+
264
+ // only need to watch and act if the parent container is hidden from display
265
+ if (isHidden(container)) {
266
+ observer = new MutationObserver(function(mutations, self) {
267
+ // only proceed if map is visible now
268
+ if (!isHidden(container)) {
269
+ flxmap.redrawOnce();
270
+
271
+ // stop observing, we're done
272
+ self.disconnect();
273
+ }
274
+ });
275
+
276
+ observer.observe(container, {
277
+ attributes: true,
278
+ attributeFilter: ["style"]
279
+ });
280
+ }
281
+ };
282
+ }
283
+ else {
284
+ handleHiddenMap = function() { };
285
+ }
286
+
287
  /**
288
  * encode special JavaScript characters, so text is safe when building JavaScript/HTML dynamically
289
  * NB: conservatively assumes that HTML special characters are unsafe, and encodes them too
367
  /**
368
  * collection of locale / phrase mapping for internationalisation of messages
369
  */
370
+ i18n: { },
371
+
372
+ /**
373
+ * collection of custom Google Maps map types for styling maps
374
+ */
375
+ mapTypes: { },
376
+
377
+ localised: false, // set to true once localisations have been loaded
378
+
379
+ /**
380
+ * load localisations into class prototype
381
+ */
382
+ localise: function() {
383
+ var key, mapTypes;
384
+
385
+ // load translations
386
+ if ("i18n" in flxmap) {
387
+ FlexibleMap.prototype.i18n = flxmap.i18n;
388
+ }
389
+
390
+ // load custom map types
391
+ if ("mapTypes" in flxmap) {
392
+ mapTypes = flxmap.mapTypes;
393
+
394
+ for (key in mapTypes) {
395
+ mapTypes[key]._styled_map = new google.maps.StyledMapType(mapTypes[key].styles, mapTypes[key].options);
396
+ }
397
+
398
+ FlexibleMap.prototype.mapTypes = mapTypes;
399
  }
400
+
401
+ FlexibleMap.prototype.localised = true;
402
  },
 
403
 
404
  /**
405
  * set the locale used for i18n phrase lookup, picking the best match
409
  setlocale: function(localeWanted) {
410
  this.locale = localeWanted;
411
 
 
 
 
 
 
 
 
 
412
  // attempt to set this locale as active
413
  if (localeWanted in this.i18n) {
414
  this.localeActive = localeWanted;
420
  this.localeActive = localeWanted;
421
  }
422
  else {
423
+ // still not found
424
+ this.localeActive = false;
425
  }
426
  }
427
 
434
  * @return {String}
435
  */
436
  gettext: function(key) {
437
+ var locale = this.localeActive;
438
 
439
+ if (locale && key in this.i18n[locale]) {
440
+ return this.i18n[locale][key];
441
+ }
442
 
443
  return key;
444
  },
459
  map = this.showMap(divID, [0, 0]),
460
  kmlLayer = this.loadKmlMap(kmlCacheBuster(kmlFileURL, this.kmlcache));
461
 
462
+ handleHiddenMap(this, divID);
463
+
464
  // set zoom if specified
465
  if (typeof zoom != "undefined") {
466
  // listen for zoom changing to fit markers on KML layer, force it back to what we asked for
530
  icon: this.markerIcon
531
  });
532
 
533
+ this.setMarkerPoint(point);
534
  this.setMarkerLocation(markerLocation);
535
 
536
+ handleHiddenMap(this, divID);
537
 
538
  if (!this.markerTitle) {
539
  this.markerTitle = this.markerAddress;
614
  }
615
 
616
  infowin = new google.maps.InfoWindow({content: container});
617
+ this.setMarkerInfowin(infowin);
618
 
619
  if (this.markerShowInfo) {
620
  // open after map is loaded, so that infowindow will auto-pan and won't be cropped at top
704
  else {
705
  map.setCenter(this.getCenter());
706
  map.setZoom(this.zoom);
707
+
708
+ // redraw the marker's infowindow if it has one
709
+ var infowin = this.getMarkerInfowin();
710
+ if (infowin) {
711
+ infowin.open(map, this.getMarkerPoint());
712
+ }
713
  }
714
  },
715
 
js/flexible-map.min.js CHANGED
@@ -2,4 +2,4 @@
2
  JavaScript for the WordPress plugin wp-flexible-map
3
  copyright (c) 2011-2014 WebAware Pty Ltd, released under LGPL v2.1
4
  */
5
- ;function FlexibleMap(){var e,c,a,d,b=false;this.getMap=function(){return e};this.getCenter=function(){return c};this.setCenter=function(f){c=f;e.setCenter(c)};this.setMarkerLocation=function(f){a=f};this.getMarkerLocation=function(){return a};this.getKmlLayer=function(){return d};this.redrawOnce=function(){if(!b){b=true;this.redraw()}};this.showMap=function(f,h){c=new google.maps.LatLng(h[0],h[1]);var i,g={small:google.maps.ZoomControlStyle.SMALL,large:google.maps.ZoomControlStyle.LARGE,"default":google.maps.ZoomControlStyle.DEFAULT};if(this.zoomControlStyle in g){i=g[this.zoomControlStyle]}else{i=g.small}e=new google.maps.Map(document.getElementById(f),{mapTypeId:this.mapTypeId,mapTypeControl:this.mapTypeControl,scaleControl:this.scaleControl,panControl:this.panControl,streetViewControl:this.streetViewControl,zoomControl:this.zoomControl,zoomControlOptions:{style:i},draggable:this.draggable,disableDoubleClickZoom:!this.dblclickZoom,scrollwheel:this.scrollwheel,center:c,zoom:this.zoom});return e};this.loadKmlMap=function(f){d=new google.maps.KmlLayer({map:e,url:f});google.maps.event.addListenerOnce(d,"defaultviewport_changed",function(){c=d.getDefaultViewport().getCenter()});return d};this.mapTypeId=google.maps.MapTypeId.ROADMAP;this.mapTypeControl=true;this.scaleControl=false;this.panControl=false;this.zoomControl=true;this.zoomControlStyle="small";this.streetViewControl=false;this.scrollwheel=false;this.draggable=true;this.dblclickZoom=true;this.zoom=16;this.markerTitle="";this.markerDescription="";this.markerHTML="";this.markerLink="";this.markerIcon="";this.markerShowInfo=true;this.markerDirections=false;this.markerDirectionsShow=false;this.markerDirectionsDefault="";this.markerAddress="";this.targetFix=true;this.dirService=false;this.dirRenderer=false;this.dirDraggable=false;this.dirSuppressMarkers=false;this.dirShowSteps=true;this.dirShowSearch=true;this.region="";this.locale="en";this.localeActive="en";this.kmlcache="none"}FlexibleMap.prototype=(function(){var d,b;if(document.addEventListener){d=function(f,e,g){f.addEventListener(e,g,false)};b=function(e){e.stopPropagation();e.preventDefault()}}else{if(document.attachEvent){d=function(e,f,g){e.attachEvent("on"+f,function(){g.call(e,window.event)})};b=function(e){e.cancelBubble=true;e.returnValue=0}}}var a=(function(){function e(g){var h=g.charCodeAt(0),f=h.toString(16);if(h<256){return"\\x"+("00"+f).slice(-2)}return"\\u"+("0000"+f).slice(-4)}return function(f){return f.replace(/[\\\/"'&<>\x00-\x1f\x7f-\xa0\u2000-\u200f\u2028-\u202f]/g,e)}})();function c(f,i){var e,g,j,h=/^(\d+)\s*(minute|hour|day)s?$/.exec(i);if(h){e=(new Date()).getTime();j=+h[1];switch(h[2]){case"minute":if(j<5){j=5}g=e/(60000*j);break;case"hour":g=e/(3600000*j);break;case"day":g=e/(86400000*j);break;default:g=false;break}if(g){g=Math.floor(g);f+=(f.indexOf("?")>-1?"&":"?")+"nocache="+g}}return f}return{constructor:FlexibleMap,i18n:{en:{"Click for details":"Click for details",Directions:"Directions",From:"From","Get directions":"Get directions"}},i18n_loaded:false,setlocale:function(f){this.locale=f;if(!this.i18n_loaded&&"flxmap" in window){for(var e in flxmap.i18n){this.i18n[e]=flxmap.i18n[e]}FlexibleMap.prototype.i18n_loaded=true}if(f in this.i18n){this.localeActive=f}else{f=f.substr(0,2);if(f in this.i18n){this.localeActive=f}else{this.localeActive="en"}}return this.localeActive},gettext:function(f){var e=this.i18n[this.localeActive];if(f in e){return e[f]}return f},showKML:function(e,h,i){if(typeof i!="undefined"){this.zoom=i}var g=this,f=document.getElementById(e),l=f.getAttribute("data-flxmap"),k=this.showMap(e,[0,0]),j=this.loadKmlMap(c(h,this.kmlcache));if(typeof i!="undefined"){google.maps.event.addListenerOnce(k,"zoom_changed",function(){k.setZoom(i);g.zoom=i})}if(this.markerDirections||this.markerDirectionsShow){this.startDirService(k)}google.maps.event.addListener(j,"click",function(r){var p=r.featureData;if(!p._flxmapOnce){p._flxmapOnce=true;if(g.targetFix){var o=/ target="_blank"/ig;p.description=p.description.replace(o,"");p.infoWindowHtml=p.infoWindowHtml.replace(o,"")}if(g.markerDirections){var n=r.latLng,q=n.lat()+","+n.lng()+",'"+a(p.name)+"',true",m='<br /><a href="#" data-flxmap-fix-opera="1" onclick="'+l+".showDirections("+q+'); return false;">'+g.gettext("Directions")+"</a>";p.infoWindowHtml=p.infoWindowHtml.replace(/<\/div><\/div>$/i,m+"</div></div>")}}});if(window.opera&&this.markerDirections){d(f,"click",function(m){if(m.target.getAttribute("data-flxmap-fix-opera")){b(m)}})}},showMarker:function(j,h,n){var g=this.showMap(j,h),e=new google.maps.LatLng(n[0],n[1]),r=new google.maps.Marker({map:g,position:e,icon:this.markerIcon});this.setMarkerLocation(e);if(!this.markerTitle){this.markerTitle=this.markerAddress}if(this.markerTitle){var m,o,t,k,l,q,s=this,f=document.createElement("DIV");f.className="flxmap-infowin";r.setTitle(this.markerTitle);l=document.createElement("DIV");l.className="flxmap-marker-title";l.appendChild(document.createTextNode(this.markerTitle));f.appendChild(l);if(this.markerHTML){l=document.createElement("DIV");l.innerHTML=this.markerHTML;f.appendChild(l)}if(this.markerDescription||this.markerLink){l=document.createElement("DIV");l.className="flxmap-marker-link";if(this.markerDescription){t=this.markerDescription.split("\n");for(m=0,o=t.length;m<o;m++){if(m>0){l.appendChild(document.createElement("BR"))}l.appendChild(document.createTextNode(t[m]))}if(this.markerLink){l.appendChild(document.createElement("BR"))}}if(this.markerLink){q=document.createElement("A");q.href=this.markerLink;q.appendChild(document.createTextNode(this.gettext("Click for details")));l.appendChild(q)}f.appendChild(l)}if(this.markerDirections){l=document.createElement("DIV");l.className="flxmap-directions-link";q=document.createElement("A");q.href="#";q.dataLatitude=n[0];q.dataLongitude=n[1];q.dataTitle=this.markerTitle;d(q,"click",function(i){b(i);s.showDirections(this.dataLatitude,this.dataLongitude,this.dataTitle,true)});q.appendChild(document.createTextNode(this.gettext("Directions")));l.appendChild(q);f.appendChild(l)}if(this.markerDirections||this.markerDirectionsShow){this.startDirService(g);if(this.markerDirectionsShow){this.showDirections(n[0],n[1],this.markerTitle,false)}}k=new google.maps.InfoWindow({content:f});if(this.markerShowInfo){google.maps.event.addListenerOnce(g,"tilesloaded",function(){k.open(g,r)})}google.maps.event.addListener(r,"click",function(){k.open(g,r)});var p=function(){s.updateGoogleLink()};google.maps.event.addListener(g,"idle",p);google.maps.event.addListener(g,"center_changed",p);google.maps.event.addListenerOnce(g,"tilesloaded",p)}},showAddress:function(e,f){var g=this,h=new google.maps.Geocoder();this.markerAddress=f;if(this.markerTitle===""){this.markerTitle=f}h.geocode({address:f,region:this.region},function(k,j){if(j==google.maps.GeocoderStatus.OK){var i=k[0].geometry.location,l=[i.lat(),i.lng()];g.showMarker(e,l,l)}else{window.alert("Map address returns error: "+j)}})},updateGoogleLink:function(){if("querySelectorAll" in document){try{var m=this.getMap().getDiv(),g=this.getMarkerLocation(),j=m.querySelectorAll("a[href*='maps.google.com/maps']:not([href*='mps_dialog']):not([href*='&q='])"),h=0,f=j.length,k=encodeURIComponent((this.markerAddress?this.markerAddress:this.markerTitle)+" @"+g.lat()+","+g.lng());for(;h<f;h++){j[h].href+="&mrt=loc&iwloc=A&q="+k}}catch(l){}}},redraw:function(){var f=this.getMap(),e=this.getKmlLayer();google.maps.event.trigger(f,"resize");if(e){f.fitBounds(e.getDefaultViewport())}else{f.setCenter(this.getCenter());f.setZoom(this.zoom)}},startDirService:function(e){if(!this.dirService){this.dirService=new google.maps.DirectionsService()}if(!this.dirRenderer){this.dirRenderer=new google.maps.DirectionsRenderer({map:e,draggable:this.dirDraggable,suppressMarkers:this.dirSuppressMarkers,panel:this.dirShowSteps?document.getElementById(this.markerDirectionsDiv):null})}},showDirections:function(l,h,k,e){var f=this;function j(){var m=document.getElementById(f.markerDirectionsDiv),o=document.createElement("form"),n,q,r;while(!!(q=m.lastChild)){m.removeChild(q)}q=document.createElement("p");q.appendChild(document.createTextNode(f.gettext("From")+": "));r=document.createElement("input");r.type="text";r.name="from";r.value=f.markerDirectionsDefault;q.appendChild(r);n=document.createElement("input");n.type="submit";n.value=f.gettext("Get directions");q.appendChild(n);o.appendChild(q);m.appendChild(o);if(typeof o.elements.from=="undefined"){o.elements.from=r}if(e){r.focus()}d(o,"submit",function(p){b(p);var s=this.elements.from.value;if(/\S/.test(s)){i(s)}})}function i(o){var m=(f.markerAddress==="")?new google.maps.LatLng(l,h):f.markerAddress,n={origin:o,region:f.region||"",destination:m,travelMode:google.maps.DirectionsTravelMode.DRIVING};f.dirService.route(n,g)}function g(o,m){var n=google.maps.DirectionsStatus;switch(m){case n.OK:f.dirRenderer.setDirections(o);break;case n.ZERO_RESULTS:window.alert("No route could be found between the origin and destination.");break;case n.OVER_QUERY_LIMIT:window.alert("The webpage has gone over the requests limit in too short a period of time.");break;case n.REQUEST_DENIED:window.alert("The webpage is not allowed to use the directions service.");break;case n.INVALID_REQUEST:window.alert("Invalid directions request.");break;case n.NOT_FOUND:window.alert("Origin or destination was not found.");break;default:window.alert("A directions request could not be processed due to a server error. The request may succeed if you try again.");break}}if(this.markerDirectionsDiv&&this.dirShowSearch){j()}if(this.markerDirectionsDefault){i(this.markerDirectionsDefault)}}}})();
2
  JavaScript for the WordPress plugin wp-flexible-map
3
  copyright (c) 2011-2014 WebAware Pty Ltd, released under LGPL v2.1
4
  */
5
+ ;function FlexibleMap(){var f,d,b,g,a,e,c=false;this.getMap=function(){return f};this.getCenter=function(){return d};this.setCenter=function(h){d=h;f.setCenter(d)};this.setMarkerLocation=function(h){b=h};this.getMarkerLocation=function(){return b};this.setMarkerPoint=function(h){g=h};this.getMarkerPoint=function(){return g};this.setMarkerInfowin=function(h){a=h};this.getMarkerInfowin=function(){return a};this.getKmlLayer=function(){return e};this.redrawOnce=function(){if(!c){c=true;this.redraw()}};this.showMap=function(h,k){d=new google.maps.LatLng(k[0],k[1]);var i,l,j={small:google.maps.ZoomControlStyle.SMALL,large:google.maps.ZoomControlStyle.LARGE,"default":google.maps.ZoomControlStyle.DEFAULT};i={mapTypeId:this.mapTypeId,mapTypeControl:this.mapTypeControl,scaleControl:this.scaleControl,panControl:this.panControl,streetViewControl:this.streetViewControl,zoomControl:j.small,zoomControlOptions:{style:l},draggable:this.draggable,disableDoubleClickZoom:!this.dblclickZoom,scrollwheel:this.scrollwheel,center:d,zoom:this.zoom};if(this.zoomControlStyle in j){i.zoomControlStyle=j[this.zoomControlStyle]}if(this.mapTypeIds){i.mapTypeControlOptions={mapTypeIds:this.mapTypeIds.split(",")}}f=new google.maps.Map(document.getElementById(h),i);if(this.mapTypeId in this.mapTypes){f.mapTypes.set(this.mapTypeId,this.mapTypes[this.mapTypeId]._styled_map)}return f};this.loadKmlMap=function(h){e=new google.maps.KmlLayer({map:f,url:h});google.maps.event.addListenerOnce(e,"defaultviewport_changed",function(){d=e.getDefaultViewport().getCenter()});return e};if(!this.localised&&"flxmap" in window){this.localise()}this.mapTypeId=google.maps.MapTypeId.ROADMAP;this.mapTypeControl=true;this.scaleControl=false;this.panControl=false;this.zoomControl=true;this.zoomControlStyle="small";this.streetViewControl=false;this.scrollwheel=false;this.draggable=true;this.dblclickZoom=true;this.zoom=16;this.markerTitle="";this.markerDescription="";this.markerHTML="";this.markerLink="";this.markerIcon="";this.markerShowInfo=true;this.markerDirections=false;this.markerDirectionsShow=false;this.markerDirectionsDefault="";this.markerAddress="";this.targetFix=true;this.dirService=false;this.dirRenderer=false;this.dirDraggable=false;this.dirSuppressMarkers=false;this.dirShowSteps=true;this.dirShowSearch=true;this.region="";this.locale="en";this.localeActive=false;this.kmlcache="none"}FlexibleMap.prototype=(function(){var d,b,e;if(document.addEventListener){d=function(g,f,h){g.addEventListener(f,h,false)};b=function(f){f.stopPropagation();f.preventDefault()}}else{if(document.attachEvent){d=function(f,g,h){f.attachEvent("on"+g,function(){h.call(f,window.event)})};b=function(f){f.cancelBubble=true;f.returnValue=0}}}if(typeof MutationObserver!=="undefined"){e=function(k,f){var i=document.getElementById(f),g=i.parentNode,h;function j(l){var m=window.getComputedStyle(l);return m.display==="none"}if(j(g)){h=new MutationObserver(function(l,m){if(!j(g)){k.redrawOnce();m.disconnect()}});h.observe(g,{attributes:true,attributeFilter:["style"]})}}}else{e=function(){}}var a=(function(){function f(h){var i=h.charCodeAt(0),g=i.toString(16);if(i<256){return"\\x"+("00"+g).slice(-2)}return"\\u"+("0000"+g).slice(-4)}return function(g){return g.replace(/[\\\/"'&<>\x00-\x1f\x7f-\xa0\u2000-\u200f\u2028-\u202f]/g,f)}})();function c(g,j){var f,h,k,i=/^(\d+)\s*(minute|hour|day)s?$/.exec(j);if(i){f=(new Date()).getTime();k=+i[1];switch(i[2]){case"minute":if(k<5){k=5}h=f/(60000*k);break;case"hour":h=f/(3600000*k);break;case"day":h=f/(86400000*k);break;default:h=false;break}if(h){h=Math.floor(h);g+=(g.indexOf("?")>-1?"&":"?")+"nocache="+h}}return g}return{constructor:FlexibleMap,i18n:{},mapTypes:{},localised:false,localise:function(){var g,f;if("i18n" in flxmap){FlexibleMap.prototype.i18n=flxmap.i18n}if("mapTypes" in flxmap){f=flxmap.mapTypes;for(g in f){f[g]._styled_map=new google.maps.StyledMapType(f[g].styles,f[g].options)}FlexibleMap.prototype.mapTypes=f}FlexibleMap.prototype.localised=true},setlocale:function(f){this.locale=f;if(f in this.i18n){this.localeActive=f}else{f=f.substr(0,2);if(f in this.i18n){this.localeActive=f}else{this.localeActive=false}}return this.localeActive},gettext:function(g){var f=this.localeActive;if(f&&g in this.i18n[f]){return this.i18n[f][g]}return g},showKML:function(f,i,j){if(typeof j!="undefined"){this.zoom=j}var h=this,g=document.getElementById(f),m=g.getAttribute("data-flxmap"),l=this.showMap(f,[0,0]),k=this.loadKmlMap(c(i,this.kmlcache));e(this,f);if(typeof j!="undefined"){google.maps.event.addListenerOnce(l,"zoom_changed",function(){l.setZoom(j);h.zoom=j})}if(this.markerDirections||this.markerDirectionsShow){this.startDirService(l)}google.maps.event.addListener(k,"click",function(s){var q=s.featureData;if(!q._flxmapOnce){q._flxmapOnce=true;if(h.targetFix){var p=/ target="_blank"/ig;q.description=q.description.replace(p,"");q.infoWindowHtml=q.infoWindowHtml.replace(p,"")}if(h.markerDirections){var o=s.latLng,r=o.lat()+","+o.lng()+",'"+a(q.name)+"',true",n='<br /><a href="#" data-flxmap-fix-opera="1" onclick="'+m+".showDirections("+r+'); return false;">'+h.gettext("Directions")+"</a>";q.infoWindowHtml=q.infoWindowHtml.replace(/<\/div><\/div>$/i,n+"</div></div>")}}});if(window.opera&&this.markerDirections){d(g,"click",function(n){if(n.target.getAttribute("data-flxmap-fix-opera")){b(n)}})}},showMarker:function(k,j,o){var h=this.showMap(k,j),f=new google.maps.LatLng(o[0],o[1]),s=new google.maps.Marker({map:h,position:f,icon:this.markerIcon});this.setMarkerPoint(s);this.setMarkerLocation(f);e(this,k);if(!this.markerTitle){this.markerTitle=this.markerAddress}if(this.markerTitle){var n,p,u,l,m,r,t=this,g=document.createElement("DIV");g.className="flxmap-infowin";s.setTitle(this.markerTitle);m=document.createElement("DIV");m.className="flxmap-marker-title";m.appendChild(document.createTextNode(this.markerTitle));g.appendChild(m);if(this.markerHTML){m=document.createElement("DIV");m.innerHTML=this.markerHTML;g.appendChild(m)}if(this.markerDescription||this.markerLink){m=document.createElement("DIV");m.className="flxmap-marker-link";if(this.markerDescription){u=this.markerDescription.split("\n");for(n=0,p=u.length;n<p;n++){if(n>0){m.appendChild(document.createElement("BR"))}m.appendChild(document.createTextNode(u[n]))}if(this.markerLink){m.appendChild(document.createElement("BR"))}}if(this.markerLink){r=document.createElement("A");r.href=this.markerLink;r.appendChild(document.createTextNode(this.gettext("Click for details")));m.appendChild(r)}g.appendChild(m)}if(this.markerDirections){m=document.createElement("DIV");m.className="flxmap-directions-link";r=document.createElement("A");r.href="#";r.dataLatitude=o[0];r.dataLongitude=o[1];r.dataTitle=this.markerTitle;d(r,"click",function(i){b(i);t.showDirections(this.dataLatitude,this.dataLongitude,this.dataTitle,true)});r.appendChild(document.createTextNode(this.gettext("Directions")));m.appendChild(r);g.appendChild(m)}if(this.markerDirections||this.markerDirectionsShow){this.startDirService(h);if(this.markerDirectionsShow){this.showDirections(o[0],o[1],this.markerTitle,false)}}l=new google.maps.InfoWindow({content:g});this.setMarkerInfowin(l);if(this.markerShowInfo){google.maps.event.addListenerOnce(h,"tilesloaded",function(){l.open(h,s)})}google.maps.event.addListener(s,"click",function(){l.open(h,s)});var q=function(){t.updateGoogleLink()};google.maps.event.addListener(h,"idle",q);google.maps.event.addListener(h,"center_changed",q);google.maps.event.addListenerOnce(h,"tilesloaded",q)}},showAddress:function(f,g){var h=this,i=new google.maps.Geocoder();this.markerAddress=g;if(this.markerTitle===""){this.markerTitle=g}i.geocode({address:g,region:this.region},function(l,k){if(k==google.maps.GeocoderStatus.OK){var j=l[0].geometry.location,m=[j.lat(),j.lng()];h.showMarker(f,m,m)}else{window.alert("Map address returns error: "+k)}})},updateGoogleLink:function(){if("querySelectorAll" in document){try{var m=this.getMap().getDiv(),g=this.getMarkerLocation(),j=m.querySelectorAll("a[href*='maps.google.com/maps']:not([href*='mps_dialog']):not([href*='&q='])"),h=0,f=j.length,k=encodeURIComponent((this.markerAddress?this.markerAddress:this.markerTitle)+" @"+g.lat()+","+g.lng());for(;h<f;h++){j[h].href+="&mrt=loc&iwloc=A&q="+k}}catch(l){}}},redraw:function(){var h=this.getMap(),g=this.getKmlLayer();google.maps.event.trigger(h,"resize");if(g){h.fitBounds(g.getDefaultViewport())}else{h.setCenter(this.getCenter());h.setZoom(this.zoom);var f=this.getMarkerInfowin();if(f){f.open(h,this.getMarkerPoint())}}},startDirService:function(f){if(!this.dirService){this.dirService=new google.maps.DirectionsService()}if(!this.dirRenderer){this.dirRenderer=new google.maps.DirectionsRenderer({map:f,draggable:this.dirDraggable,suppressMarkers:this.dirSuppressMarkers,panel:this.dirShowSteps?document.getElementById(this.markerDirectionsDiv):null})}},showDirections:function(m,i,l,f){var g=this;function k(){var n=document.getElementById(g.markerDirectionsDiv),q=document.createElement("form"),o,r,s;while(!!(r=n.lastChild)){n.removeChild(r)}r=document.createElement("p");r.appendChild(document.createTextNode(g.gettext("From")+": "));s=document.createElement("input");s.type="text";s.name="from";s.value=g.markerDirectionsDefault;r.appendChild(s);o=document.createElement("input");o.type="submit";o.value=g.gettext("Get directions");r.appendChild(o);q.appendChild(r);n.appendChild(q);if(typeof q.elements.from=="undefined"){q.elements.from=s}if(f){s.focus()}d(q,"submit",function(p){b(p);var t=this.elements.from.value;if(/\S/.test(t)){j(t)}})}function j(p){var n=(g.markerAddress==="")?new google.maps.LatLng(m,i):g.markerAddress,o={origin:p,region:g.region||"",destination:n,travelMode:google.maps.DirectionsTravelMode.DRIVING};g.dirService.route(o,h)}function h(p,n){var o=google.maps.DirectionsStatus;switch(n){case o.OK:g.dirRenderer.setDirections(p);break;case o.ZERO_RESULTS:window.alert("No route could be found between the origin and destination.");break;case o.OVER_QUERY_LIMIT:window.alert("The webpage has gone over the requests limit in too short a period of time.");break;case o.REQUEST_DENIED:window.alert("The webpage is not allowed to use the directions service.");break;case o.INVALID_REQUEST:window.alert("Invalid directions request.");break;case o.NOT_FOUND:window.alert("Origin or destination was not found.");break;default:window.alert("A directions request could not be processed due to a server error. The request may succeed if you try again.");break}}if(this.markerDirectionsDiv&&this.dirShowSearch){k()}if(this.markerDirectionsDefault){j(this.markerDirectionsDefault)}}}})();
readme.txt CHANGED
@@ -7,7 +7,7 @@ Donate link: http://shop.webaware.com.au/downloads/flexible-map/
7
  Tags: google, map, maps, google maps, shortcode, google maps shortcode, kml
8
  Requires at least: 3.2.1
9
  Tested up to: 4.1
10
- Stable tag: 1.8.3
11
  License: GPLv2 or later
12
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
 
@@ -34,7 +34,7 @@ Flexible Map allows you to add Google Maps to your WordPress website.
34
  * directions can be dropped into any div element with an ID
35
  * minimal dependencies -- just WordPress and the Google Maps API
36
 
37
- Click to see [WP Flexible Map in action](http://flexible-map.webaware.net.au/).
38
 
39
  = Sponsorships =
40
 
@@ -55,7 +55,7 @@ Many thanks to the generous efforts of our translators:
55
  * Norwegian: Bokmål (nb_NO) -- [neonnero](http://www.neonnero.com/)
56
  * Norwegian: Nynorsk (nn_NO) -- [neonnero](http://www.neonnero.com/)
57
  * Spanish (es) -- [edurramos](http://profiles.wordpress.org/edurramos/)
58
- * Welsh (cy) -- ([Dylan](https://profiles.wordpress.org/dtom-ct-wp/))
59
 
60
  The initial translations for all other languages were made using Google Translate, so it's likely that some will be truly awful! If you'd like to help out by translating this plugin, please [sign up for an account and dig in](http://translate.webaware.com.au/projects/flexible-map).
61
 
@@ -108,6 +108,7 @@ Either the center or the address paramater is required. If you provide both, the
108
  * **id**: the CSS id of the container div (instead of a random generated unique ID), e.g. *id="my_map"*
109
  * **zoom**: zoom level as an integer, larger is closer, e.g. *zoom="16"*
110
  * **maptype**: type of map to show, from [roadmap, satellite, hybrid, terrain], e.g. *maptype="satellite"*; default=roadmap
 
111
  * **hidemaptype**: hide the map type controls, from [true, false], e.g. *hidemaptype="true"*; default=false
112
  * **hidepanning**: hide the panning controls, from [true, false], e.g. *hidepanning="true"*; default=true
113
  * **hidezooming**: hide the zoom controls, from [true, false], e.g. *hidezooming="true"*; default=false
@@ -147,14 +148,15 @@ There is a PHP function `flexmap_show_map()` for theme and plugin developers. Al
147
 
148
  There are also some filter hooks that allow you to change the behaviour of the plugin.
149
 
150
- * **flexmap_google_maps_api_args**: filter the array of arguments that will be passed to the Google Maps API, e.g. `'v'=>'3.exp'`, `'sensor'=>'false'`
151
- * **flexmap_google_maps_api_url**: filter the Google Maps API URL, as a string
152
- * **flexmap_shortcode_attrs**: filter the array of shortcode attributes, e.g. change the width and height
153
- * **flexmap_shortcode_styles**: filter the array of inline styles applied to the div wrapping the map, e.g. remove width and height so that it can be specified in the theme's stylesheets
154
- * **flexmap_shortcode_html**: filter the generated HTML, e.g. wrap another div around it, add a link to Google Maps, add some additonal script, etc.
155
- * **flexmap_shortcode_script**: filter the generated JavaScript
 
156
 
157
- For more information and examples, see [the website](http://flexible-map.webaware.net.au/).
158
 
159
  == Frequently Asked Questions ==
160
 
@@ -214,22 +216,30 @@ function force_flexmap_map_language($args) {
214
 
215
  The initial translations were made using Google Translate, so it's likely that some will be truly awful! If you'd like to help out by translating this plugin, please [sign up for an account and dig in](http://translate.webaware.com.au/projects/flexible-map).
216
 
217
- = The map is broken in jQuery UI tabs =
218
 
219
- When you hide the map in a tab, and then click on the tab to reveal its contents, the map doesn't know how big to draw until it is revealed. You need to give Google Maps a nudge so that it will pick up the correct size and position when you reveal it. Download the .php file from [this gist](https://gist.github.com/webaware/05b27e3a99ccb00200f5), and install / activate to fix. If you'd prefer to add the jQuery code yourself, add this somewhere on the page (e.g. in your theme's footer):
 
 
220
 
221
  `<script>
222
- jQuery("body").on("tabsactivate", function(event, ui) {
223
- if (ui.newPanel.length) {
224
- $("#" + ui.newPanel[0].id + " div.flxmap-container").each(function() {
225
- var flxmap = window[this.getAttribute("data-flxmap")];
226
- flxmap.redrawOnce();
227
- });
 
 
 
228
  }
229
- });
 
 
 
230
  </script>`
231
 
232
- For jQuery versions 1.8 or older:
233
 
234
  `<script>
235
  jQuery("body").bind("tabsshow", function(event, ui) {
@@ -296,6 +306,15 @@ Either turn off CloudFlare Rocketscript :) or install the [Flxmap No Rocketscrip
296
 
297
  == Changelog ==
298
 
 
 
 
 
 
 
 
 
 
299
  = 1.8.3 [2014-12-17] =
300
  * fixed: CSS for directions in twentyfifteen theme and others that toss table-layout:fixed around willy nilly
301
 
7
  Tags: google, map, maps, google maps, shortcode, google maps shortcode, kml
8
  Requires at least: 3.2.1
9
  Tested up to: 4.1
10
+ Stable tag: 1.9.0
11
  License: GPLv2 or later
12
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
 
34
  * directions can be dropped into any div element with an ID
35
  * minimal dependencies -- just WordPress and the Google Maps API
36
 
37
+ [Try WP Flexible Map online](http://flexible-map.webaware.net.au/).
38
 
39
  = Sponsorships =
40
 
55
  * Norwegian: Bokmål (nb_NO) -- [neonnero](http://www.neonnero.com/)
56
  * Norwegian: Nynorsk (nn_NO) -- [neonnero](http://www.neonnero.com/)
57
  * Spanish (es) -- [edurramos](http://profiles.wordpress.org/edurramos/)
58
+ * Welsh (cy) -- [Dylan](https://profiles.wordpress.org/dtom-ct-wp/)
59
 
60
  The initial translations for all other languages were made using Google Translate, so it's likely that some will be truly awful! If you'd like to help out by translating this plugin, please [sign up for an account and dig in](http://translate.webaware.com.au/projects/flexible-map).
61
 
108
  * **id**: the CSS id of the container div (instead of a random generated unique ID), e.g. *id="my_map"*
109
  * **zoom**: zoom level as an integer, larger is closer, e.g. *zoom="16"*
110
  * **maptype**: type of map to show, from [roadmap, satellite, hybrid, terrain], e.g. *maptype="satellite"*; default=roadmap
111
+ * **maptypes**: types of maps in the map type controls, e.g. *maptypes="custom_type,satellite"*
112
  * **hidemaptype**: hide the map type controls, from [true, false], e.g. *hidemaptype="true"*; default=false
113
  * **hidepanning**: hide the panning controls, from [true, false], e.g. *hidepanning="true"*; default=true
114
  * **hidezooming**: hide the zoom controls, from [true, false], e.g. *hidezooming="true"*; default=false
148
 
149
  There are also some filter hooks that allow you to change the behaviour of the plugin.
150
 
151
+ * `flexmap_google_maps_api_args`: filter the array of arguments that will be passed to the Google Maps API, e.g. `'v'=>'3.exp'`, `'sensor'=>'false'`
152
+ * `flexmap_google_maps_api_url`: filter the Google Maps API URL, as a string
153
+ * `flexmap_shortcode_attrs`: filter the array of shortcode attributes, e.g. change the width and height
154
+ * `flexmap_shortcode_styles`: filter the array of inline styles applied to the div wrapping the map, e.g. remove width and height so that it can be specified in the theme's stylesheets
155
+ * `flexmap_shortcode_html`: filter the generated HTML, e.g. wrap another div around it, add a link to Google Maps, add some additonal script, etc.
156
+ * `flexmap_shortcode_script`: filter the generated JavaScript
157
+ * `flexmap_custom_map_types`: register custom Google Maps map types
158
 
159
+ For more information and examples, see [the reference website](http://flexible-map.webaware.net.au/).
160
 
161
  == Frequently Asked Questions ==
162
 
216
 
217
  The initial translations were made using Google Translate, so it's likely that some will be truly awful! If you'd like to help out by translating this plugin, please [sign up for an account and dig in](http://translate.webaware.com.au/projects/flexible-map).
218
 
219
+ = The map is broken in tabs / accordions =
220
 
221
+ When you hide the map in a tab, and then click on the tab to reveal its contents, sometimes the map doesn't know how big to draw until it is revealed. Since v1.9.0 most such problems are automatically resolved for modern browsers, including Internet Explorer 11 or later. If you need to support earlier versions that don't support [MutationObserver](http://caniuse.com/#feat=mutationobserver), add some script to your website to handle this yourself.
222
+
223
+ For jQuery UI tabs and accordions, download the .php file from [this gist](https://gist.github.com/webaware/05b27e3a99ccb00200f5), and install / activate it. If you'd prefer to add the jQuery code yourself, add this somewhere on the page (e.g. in your theme's footer):
224
 
225
  `<script>
226
+ (function($) {
227
+
228
+ function mapRedraw(event, ui) {
229
+ if (ui.newPanel.length) {
230
+ $("#" + ui.newPanel[0].id + " div.flxmap-container").each(function() {
231
+ var flxmap = window[this.getAttribute("data-flxmap")];
232
+ flxmap.redrawOnce();
233
+ });
234
+ }
235
  }
236
+
237
+ $("body").on("accordionactivate", mapRedraw).on("tabsactivate", mapRedraw);
238
+
239
+ })(jQuery);
240
  </script>`
241
 
242
+ For jQuery UI tabs versions 1.8 or older:
243
 
244
  `<script>
245
  jQuery("body").bind("tabsshow", function(event, ui) {
306
 
307
  == Changelog ==
308
 
309
+ = 1.9.0 [2014-12-24] =
310
+ * fixed: maps broken when hidden in tabs / accordions (not for IE 10 and earlier; uses MutationObserver)
311
+ * fixed: strip spaces from map coordinates
312
+ * fixed: suppress border radius on images within map containers
313
+ * added: server-side lookup of address, to reduce the number of Google Maps queries when only an address is given
314
+ * added: support for custom map types (inc. styled maps)
315
+ * added: `maptypes` attribute for selecting which map types can be picked by visitors
316
+ * changed: refactored JavaScript for localised strings
317
+
318
  = 1.8.3 [2014-12-17] =
319
  * fixed: CSS for directions in twentyfifteen theme and others that toss table-layout:fixed around willy nilly
320