commit d8e5f1be0d95922b6aa1a1678d590eeff6e7599c
Author: Andreas Kohlbecker <a.kohlbecker@bgbm.org>
Date:   Fri Jul 31 13:58:06 2020 +0200

    fix #9175 map detects empty kml layer and removes itself

diff --git a/modules/cdm_dataportal/includes/maps.inc b/modules/cdm_dataportal/includes/maps.inc
index 245c4697..c1304204 100644
--- a/modules/cdm_dataportal/includes/maps.inc
+++ b/modules/cdm_dataportal/includes/maps.inc
@@ -57,34 +57,34 @@ function compose_map($map_id, $occurrence_query = NULL, $kml_request_url, $distr
 
   $map_settings = get_array_variable_merged(CDM_MAP_DISTRIBUTION, CDM_MAP_DISTRIBUTION_DEFAULT);
 
-    if($force_map_type === NULL){
-      $force_map_type = $map_settings['map_type'];
-    }
+  if($force_map_type === NULL){
+    $force_map_type = $map_settings['map_type'];
+  }
 
-    if ($force_map_type == 1) {
-      _add_jquery_ui();
-      $map_html = cdm_map_openlayers(
-        $map_id,
-        $occurrence_query,
-        $kml_request_url,
-        $distribution_query,
-        $legend_format_query,
-        $map_settings['caption'],
-        $event_listeners,
-        $resizable
-      );
-    }
-     else {
-      $map_height = round($map_settings['image_map']['width'] / (float)$map_settings['aspect_ratio']);
-      $map_html = cdm_map_plain_image(
-        $map_settings['image_map']['width'],
-        $map_height,
-        $occurrence_query,
-        $distribution_query,
-        $legend_format_query,
-        $map_settings['caption']
-      );
-     }
+  if ($force_map_type == 1) {
+    _add_jquery_ui();
+    $map_html = cdm_map_openlayers(
+      $map_id,
+      $occurrence_query,
+      $kml_request_url,
+      $distribution_query,
+      $legend_format_query,
+      $map_settings['caption'],
+      $event_listeners,
+      $resizable
+    );
+  }
+   else {
+    $map_height = round($map_settings['image_map']['width'] / (float)$map_settings['aspect_ratio']);
+    $map_html = cdm_map_plain_image(
+      $map_settings['image_map']['width'],
+      $map_height,
+      $occurrence_query,
+      $distribution_query,
+      $legend_format_query,
+      $map_settings['caption']
+    );
+   }
   return markup_to_render_array($map_html);
 }
 
diff --git a/modules/cdm_dataportal/js/map/openlayers_map.js b/modules/cdm_dataportal/js/map/openlayers_map.js
index 778e559c..67ca145a 100644
--- a/modules/cdm_dataportal/js/map/openlayers_map.js
+++ b/modules/cdm_dataportal/js/map/openlayers_map.js
@@ -37,6 +37,8 @@
     defaultBaseLayerName: 'open_topomap',
     maxZoom: 15,
     minZoom: 0,
+      // hide the map when the data layer has no features
+      hideEmptyMap: true,
     debug: true,
     /**
      * allows the map to display parts of the layers which are outside
@@ -268,6 +270,17 @@
         });
       }
 
+        /**
+         * Removes the map and the parent container from the
+         * DOM and destroys the OpenLayers map object
+         */
+        function removeMap() {
+            //  if you are using an application which removes a container
+            //  of the map from the DOM, you need to ensure that you destroy the map before this happens;
+            map.destroy;
+            jQuery(map.div).parent().remove();
+        }
+
         /**
          *
          */
@@ -379,8 +392,13 @@
                     "featureselected": onKmlFeatureSelect,
                     "featureunselected": onKmlFeatureUnselect,
                     'loadend': function(event) {
-                        applyLayerZoomBounds(event);
-                        disablePolygonFeatureClick(event);
+                        if(opts.hideEmptyMap && kmlLayer.features.length == 0){
+                            log("No feature in KML layer, removing map ...")
+                            removeMap();
+                        } else {
+                            applyLayerZoomBounds(event);
+                            disablePolygonFeatureClick(event);
+                        }
                     }
                 });
                 map.addControl(kmlSelectControl);
diff --git a/src/main/java/eu/etaxonomy/dataportal/elements/OpenLayersMap.java b/src/main/java/eu/etaxonomy/dataportal/elements/OpenLayersMap.java
new file mode 100644
index 00000000..591f6444
--- /dev/null
+++ b/src/main/java/eu/etaxonomy/dataportal/elements/OpenLayersMap.java
@@ -0,0 +1,74 @@
+/**
+* Copyright (C) 2020 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.dataportal.elements;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.log4j.Logger;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+
+import eu.etaxonomy.dataportal.pages.PortalPage;
+import eu.etaxonomy.dataportal.selenium.UrlLoaded;
+
+/**
+ * @author a.kohlbecker
+ * @since Jul 31, 2020
+ */
+public class OpenLayersMap {
+
+    private WebElement webElement;
+    private String mapId;
+    private String mapName;
+
+    private OpenLayersMap(WebElement webElement) {
+        this.webElement = webElement;
+        this.mapId = webElement.getAttribute("id");
+        if (this.mapId != null) {
+            this.mapName = webElement.getAttribute("id").replace("openlayers-container-", "");
+        }
+    }
+
+    public static List<OpenLayersMap> findOpenLayersMaps(PortalPage page) {
+        try {
+            page.getWait().until(new UrlLoaded(page.getPageURL().toString()));
+            List<WebElement> maps = page.getDataPortalContent().getElement()
+                    .findElements(By.className("openlayers-container"));
+            return maps.stream().map(m -> new OpenLayersMap(m)).collect(Collectors.toList());
+        } catch (NoSuchElementException e) {
+            Logger.getLogger(OpenLayersMap.class).info("No maps found", e);
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * @return the webElement
+     */
+    public WebElement getWebElement() {
+        return webElement;
+    }
+
+    /**
+     * @return the mapId
+     */
+    public String getMapId() {
+        return mapId;
+    }
+
+    /**
+     * @return the mapName
+     */
+    public String getMapName() {
+        return mapName;
+    }
+
+}
diff --git a/src/test/java/eu/etaxonomy/dataportal/selenium/tests/reference/MapTest.java b/src/test/java/eu/etaxonomy/dataportal/selenium/tests/reference/MapTest.java
new file mode 100644
index 00000000..d7d92bca
--- /dev/null
+++ b/src/test/java/eu/etaxonomy/dataportal/selenium/tests/reference/MapTest.java
@@ -0,0 +1,89 @@
+/**
+* Copyright (C) 2019 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.dataportal.selenium.tests.reference;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import eu.etaxonomy.dataportal.DataPortalSite;
+import eu.etaxonomy.dataportal.elements.OpenLayersMap;
+import eu.etaxonomy.dataportal.junit.CdmDataPortalTestBase;
+import eu.etaxonomy.dataportal.junit.DataPortalContextSuite.DataPortalContexts;
+import eu.etaxonomy.dataportal.pages.NamePage;
+import eu.etaxonomy.dataportal.pages.RegistrationPage;
+
+/**
+ * @author a.kohlbecker
+ * @since Feb 5, 2019
+ *
+ */
+@DataPortalContexts( { DataPortalSite.reference })
+public class MapTest extends CdmDataPortalTestBase {
+
+
+    private static final String nodosilinea_radiophila_regid = "http://testbank.org/100004";
+
+    private static final String ramsaria_regid = "http://testbank.org/100005";
+
+    private static final UUID nodosilinea_radiophila_name_UUID = UUID.fromString("e97cc25b-ec11-4bb8-88d7-ab40a023f3fb");
+
+    private static final UUID ramsaria_name_UUID = UUID.fromString("3a6d4bf2-5c89-4525-9e87-0bacac96990b");
+
+
+    String titleSuffix = " | Integration test reference";
+
+
+
+    @Before
+    public void setUp() throws Exception {
+        driver.get(getContext().getBaseUri().toString());
+    }
+
+    @Test
+    public void namePageMapShown() throws MalformedURLException{
+
+        NamePage p = new NamePage(driver, getContext(), nodosilinea_radiophila_name_UUID);
+        List<OpenLayersMap> openLayersMaps = OpenLayersMap.findOpenLayersMaps(p);
+        assertFalse(openLayersMaps.isEmpty());
+        assertEquals(1, openLayersMaps.size());
+        assertEquals("specimens", openLayersMaps.get(0).getMapName());
+    }
+
+    @Test
+    public void registrationPageMapShown() throws MalformedURLException, UnsupportedEncodingException{
+
+        RegistrationPage p = new RegistrationPage(driver, getContext(), nodosilinea_radiophila_regid);
+        List<OpenLayersMap> openLayersMaps = OpenLayersMap.findOpenLayersMaps(p);
+        assertFalse(openLayersMaps.isEmpty());
+        assertEquals(1, openLayersMaps.size());
+        assertEquals("specimens", openLayersMaps.get(0).getMapName());
+    }
+
+    @Test
+    public void namePageMapHidden() throws MalformedURLException{
+
+        NamePage p = new NamePage(driver, getContext(), ramsaria_name_UUID);
+        List<OpenLayersMap> openLayersMaps = OpenLayersMap.findOpenLayersMaps(p);
+        assertTrue(openLayersMaps.isEmpty());
+    }
+
+    @Test
+    public void registrationPageMapHidden() throws MalformedURLException, UnsupportedEncodingException{
+
+        RegistrationPage p = new RegistrationPage(driver, getContext(), ramsaria_regid);
+        List<OpenLayersMap> openLayersMaps = OpenLayersMap.findOpenLayersMaps(p);
+        assertTrue(openLayersMaps.isEmpty());
+    }
+
+}
