diff --git a/templates/internal/base.html b/templates/internal/base.html
index 4717e66a66c23e452dbdf106b7c426413d4b28c1..c5393eb1c641d92d525fb203078e6be07f7d3b99 100644
--- a/templates/internal/base.html
+++ b/templates/internal/base.html
@@ -163,7 +163,7 @@
 			};
 
 			// another jquery "plugin" for modifying the behaviour of external links
-			// TODO: disable when not running on the display
+			// - this is probably not really enough, consider adding a tab blocker on the display and/or disable iframes, object tags, etc.
 			$.fn.disableExternalLinks = function(force = false) {
 				// for some extra security the first condition is resolved when templates are compiled
 				if (({{ (not g.is_kiosk)|tojson|safe }} && !force) || this.data('links-disabled'))
@@ -183,8 +183,13 @@
 					}).modal();
 				};
 
-				// the to slashes are for the benefit of urls that contain refering URI in the query string
+				// the two slashes are for the benefit of urls that contain refering URI in the query string
 				this.on('click', 'a[href^="http"]:not([href*="//{{ request.host }}"])', handler);
+				// disable links for foreign protocols, just in case
+				this.on('click', 'a[href^="mailto:"]', function(e) { e.preventDefault(); });
+				this.on('click', 'a[href*="://"]:not([href^="http"])', function(e) { e.preventDefault(); });
+
+				// avoid duplicate calls (see info page, twitter widget)
 				this.data('links-disabled', true);
 				return this;
 			};
diff --git a/templates/map.html b/templates/map.html
index 46539269a1b2e65ba22755ba5b433412f8ffb7c6..39db1c248f23aa10ce8b41f3c27e70999593a4e0 100644
--- a/templates/map.html
+++ b/templates/map.html
@@ -73,15 +73,23 @@
 
 		// focusedMarker is the title of the focused marker
 		var focusedMarker = undefined;
+		// the currently focused bus information
 		var focusedBus = undefined;
+		// shapes currently drawn on map
 		var mapShapes = [];
+		// info window for currently focused bus
 		var focusedBusWindow = undefined;
-		var apiEndpoint = "{{ url_for('apiLocatorService', version = 1, stopId = stop_info.stop_id, type = 'nearby', _external = True) }}";
-		var trackingLoop = null;
-		var currentMode = null;
+
+		// map zoom and centered stop
 		var busStop = {{ stop_info|tojson|safe }};
 		var mapZoom = 16;
 
+		// map updating related variables
+		var mapUpdating = false; // block mode changes when map is busy
+		var pendingEvent = null;
+		var trackingLoop = null;
+		var currentMode = null;
+
 		var positionToGoogleLatLng = function(lat, lon) {
 			return new google.maps.LatLng(lat, lon);
 		};
@@ -151,6 +159,23 @@
 			}
 		};
 
+		// handle events skipped due to ongoing map update, see variable mapUpdating and click handlers
+		var completeMapUpdate = function() {
+			if (!mapUpdating)
+				console.log('superfluous call to completeMapUpdate(), map is not busy...');
+
+			mapUpdating = false;
+			if (pendingEvent !== null) {
+				if (pendingEvent === "mapClicked") {
+					mapClicked();
+				} else if (gmarkers[pendingEvent] !== undefined) {
+					markerClicked(gmarkers[pendingEvent]);
+				}
+
+				pendingEvent = null;
+			}
+		};
+
 		// this function will determine what to draw on the map every 3 seconds
 		var busTrackingLoop = function(mode, pollTime = 3000) {
 			if (trackingLoop !== null) {
@@ -178,12 +203,24 @@
 				}
 			}
 
+			// store the skipped event for when update has finished
+			if (mapUpdating) {
+				pendingEvent = marker.title;
+				return;
+			}
+
 			focusedMarker = marker.title;
 			initOneBusTracking();
 		}
 
 		var mapClicked = function() {
 			if (focusedMarker !== undefined) {
+				// store the skipped event for when update has finished
+				if (mapUpdating) {
+					pendingEvent = "mapClicked";
+					return;
+				}
+
 				gmap.setZoom(mapZoom);
 				gmap.panTo(positionToGoogleLatLng(busStop.stop_lat, busStop.stop_lon));
 
@@ -210,7 +247,7 @@
 			}
 
 			markers = {};
-			$.getJSON(apiEndpoint,
+			$.getJSON("{{ url_for('apiLocatorService', version = 1, stopId = stop_info.stop_id, type = 'nearby', _external = True) }}",
 				function (data) {
 					console.log('found this many buses: ' + Object.keys(data).length);
 					$.each( data, function( key, value ) {
@@ -227,7 +264,10 @@
 		};
 
 		var drawAllBuses = function() {
-			$.getJSON(apiEndpoint,
+			// mark the map as busy
+			mapUpdating = true;
+
+			$.getJSON("{{ url_for('apiLocatorService', version = 1, stopId = stop_info.stop_id, type = 'nearby', _external = True) }}",
 				function (data) {
 					// poor man's locking
 					if (trackingLoop === null)
@@ -259,6 +299,8 @@
 							value.setMap(null);
 						}
 					});
+
+					completeMapUpdate();
 				}
 			)
 		};
@@ -329,6 +371,9 @@
 		};
 
 		var drawOneBus = function() {
+			// mark the map as busy
+			mapUpdating = true;
+
 			var requestFocus = focusedMarker;
 			$.post(
 				"{{ url_for('apiBusInfo', version = 1, _external = True) }}",
@@ -354,6 +399,8 @@
 						marker.setPosition(position);
 						gmap.panTo(position);
 					}
+
+					completeMapUpdate();
 				},
 				'json'
 			)
@@ -364,9 +411,9 @@
 			// TODO is there a better way of doing this, this way is pretty ugly
 			var infoWindowContent = `
 			<h4>` + focusedBus.lineref + ' - ' + focusedBus.destinationname + `</h4>
-			Next Stop: ` + focusedBus.next_stoppointname + ` <br>
-			Aimed Arrival: ` + moment.unix(focusedBus.next_aimedarrivaltime).format('HH:mm:ss') + ` <br>
-			Expected Arrival: ` + moment.unix(focusedBus.next_expectedarrivaltime).format('HH:mm:ss') + ` <br>
+			{{ _("Next Stop") }}: ` + focusedBus.next_stoppointname + ` <br>
+			{{ _("Aimed Arrival") }}: ` + moment.unix(focusedBus.next_aimedarrivaltime).format('HH:mm:ss') + ` <br>
+			{{ _("Expected Arrival") }}: ` + moment.unix(focusedBus.next_expectedarrivaltime).format('HH:mm:ss') + ` <br>
 			`;
 
 			if (focusedBusWindow === undefined || recreate) {
@@ -385,21 +432,24 @@
 		$(document).ready(function() {
 			console.log(busStop);
 
-			console.log("hello world");
-
 			// this draws an initial map that is zoomed and centered on the bus stop
 			// this map is used then to start drawing buses dynamically on it
-			gmap = drawMap(busStop, $('#map-canvas'));
-			google.maps.event.addListener(gmap, 'click', function() { mapClicked() });
+			$canvas = $('#map-canvas');
+			gmap = drawMap(busStop, $canvas);
 
-			drawBusStop(gmap, busStop.stop_lat, busStop.stop_lon, busStop.stop_name, busStop.stop_id);
+			// wait for the map to load before we queue other work
+			google.maps.event.addListenerOnce(gmap, 'tilesloaded', function() {
+				// this may or may not violate Google Maps ToS (9.4), but frankly not allowing users to break out
+				// of the application on public displays is more important (and its not like we are removing attribution)
+				$canvas.disableExternalLinks();
 
-			// start bus tracking loop
-			initAllBusesTracking();
+				google.maps.event.addListener(gmap, 'click', function() { mapClicked() });
 
-			// this may or may not violate Google Maps ToS (10.1.1, 9.4), but frankly not allowing users to break out
-			// of the application on public displays is more important (and its not like we are removing attribution)
-			google.maps.event.addListenerOnce(gmap, 'tilesloaded', function() { $('#map-canvas').disableExternalLinks(); })
+				drawBusStop(gmap, busStop.stop_lat, busStop.stop_lon, busStop.stop_name, busStop.stop_id);
+
+				// start bus tracking loop
+				initAllBusesTracking();
+			});
 		});
 	</script>
 {% endblock scripts %}
diff --git a/translations/en/LC_MESSAGES/messages.po b/translations/en/LC_MESSAGES/messages.po
index a340c8a5ad1001ad99a6eab6d65904f5778b8333..0cf6a7999029a670b2bf03470b64fc45d7d0f95e 100644
--- a/translations/en/LC_MESSAGES/messages.po
+++ b/translations/en/LC_MESSAGES/messages.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PROJECT VERSION\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2018-03-05 20:03+0200\n"
+"POT-Creation-Date: 2018-03-07 20:32+0200\n"
 "PO-Revision-Date: 2018-02-10 01:33+0200\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language: en\n"
@@ -76,6 +76,18 @@ msgid ""
 "to move in an unrealistic way."
 msgstr ""
 
+#: templates/map.html:414
+msgid "Next Stop"
+msgstr ""
+
+#: templates/map.html:415
+msgid "Aimed Arrival"
+msgstr ""
+
+#: templates/map.html:416
+msgid "Expected Arrival"
+msgstr ""
+
 #: templates/timetables.html:10
 msgid "Busses Arriving Soon"
 msgstr ""
diff --git a/translations/fi/LC_MESSAGES/messages.po b/translations/fi/LC_MESSAGES/messages.po
index 024781cf5a9f3e725afd2ac0455de52267ced0d5..663ccee03bc3b0db17dc7bf5935cb64f378d7456 100644
--- a/translations/fi/LC_MESSAGES/messages.po
+++ b/translations/fi/LC_MESSAGES/messages.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PROJECT VERSION\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2018-03-05 20:03+0200\n"
+"POT-Creation-Date: 2018-03-07 20:32+0200\n"
 "PO-Revision-Date: 2018-02-10 01:35+0200\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language: fi\n"
@@ -79,6 +79,18 @@ msgstr ""
 " puutteellisesta paikannuksesta johtuen bussit saattavat paikoitellen "
 "liikkua epärealistisella tavalla"
 
+#: templates/map.html:414
+msgid "Next Stop"
+msgstr "Seuraava pysäkki"
+
+#: templates/map.html:415
+msgid "Aimed Arrival"
+msgstr "Tavoitteellinen saapumisaika"
+
+#: templates/map.html:416
+msgid "Expected Arrival"
+msgstr "Odotettu saapumisaika"
+
 #: templates/timetables.html:10
 msgid "Busses Arriving Soon"
 msgstr "Pian saapuvat bussit"