diff --git a/frontend-js/src/main/js/ObjectWithListeners.js b/frontend-js/src/main/js/ObjectWithListeners.js
index 41b332c6d21c8e2259321b4ec0eab7d23f199d24..219b102584047cffa147a2700984cd134a2cb59b 100644
--- a/frontend-js/src/main/js/ObjectWithListeners.js
+++ b/frontend-js/src/main/js/ObjectWithListeners.js
@@ -144,7 +144,7 @@ ObjectWithListeners.prototype.removePropertyListener = function (name, fun) {
  *
  * @param {string} type
  *          type of the listener (string)
- * @param arg
+ * @param {Object} [arg]
  *          argument data passed to the handler
  *
  * @returns {PromiseLike}
diff --git a/frontend-js/src/main/js/gui/admin/ConfigurationAdminPanel.js b/frontend-js/src/main/js/gui/admin/ConfigurationAdminPanel.js
index fe173b2b8ecbc4738a8674e1e7f27533197bcf72..17657ccd8a8ef51ee833ceca1f64165e835b1fc5 100644
--- a/frontend-js/src/main/js/gui/admin/ConfigurationAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/ConfigurationAdminPanel.js
@@ -271,8 +271,6 @@ ConfigurationAdminPanel.prototype.saveOption = function (type) {
       }).then(function (status) {
         if (status) {
           return self.getServerConnector().resetUserTos();
-        } else {
-          console.log("no");
         }
       });
     }
diff --git a/frontend-js/src/main/js/map/Submap.js b/frontend-js/src/main/js/map/Submap.js
index 37979fe92a2dd4e454daced37f806fb7441fec97..26dcb67cd97e4cf3bbb982d3c02115bf74e304c1 100644
--- a/frontend-js/src/main/js/map/Submap.js
+++ b/frontend-js/src/main/js/map/Submap.js
@@ -19,9 +19,10 @@ var CustomMapOptions = require('./CustomMapOptions');
  * @extends AbstractCustomMap
  */
 function Submap(customMap, model) {
+  var self = this;
   this.setCustomMap(customMap);
 
-  AbstractCustomMap.call(this, model, new CustomMapOptions({
+  AbstractCustomMap.call(self, model, new CustomMapOptions({
     element: customMap.getElement(),
     bigLogo: customMap.isBigLogo(),
     project: customMap.getProject(),
@@ -31,7 +32,17 @@ function Submap(customMap, model) {
     serverConnector: customMap.getServerConnector()
   }));
 
-  this.initialized = false;
+  self.registerListenerType("onOpen");
+  self.registerListenerType("onClose");
+  self.registerListenerType("onDrag");
+  self.registerListenerType("onDragStart");
+  self.registerListenerType("onDragStop");
+  self.registerListenerType("onResize");
+  self.registerListenerType("onResizeStart");
+  self.registerListenerType("onResizeStop");
+  self.registerListenerType("onFocus");
+
+  self.initialized = false;
 }
 
 // implementation of object inheritance
@@ -62,6 +73,7 @@ Submap.prototype.open = function (htmlTag) {
     mapDiv.style.height = "100%";
     contentDiv.appendChild(mapDiv);
 
+    // noinspection JSUnusedGlobalSymbols
     $(self.getElement()).dialog({
       title: self.getModel().getName(),
       width: Math.floor(window.innerWidth * 2 / 3),
@@ -72,7 +84,33 @@ Submap.prototype.open = function (htmlTag) {
         of: $(self.getTopMap().getElement())
       },
       resize: function () {
-        self.getMapCanvas().triggerListeners('resize');
+        return self.getMapCanvas().triggerListeners('resize').then(function () {
+          return self.callListeners('onResize');
+        });
+      },
+      resizeStart: function () {
+        return self.callListeners('onResizeStart');
+      },
+      resizeStop: function () {
+        return self.callListeners('onResizeStop');
+      },
+      open: function () {
+        return self.callListeners('onOpen');
+      },
+      close: function () {
+        return self.callListeners('onClose');
+      },
+      focus: function () {
+        return self.callListeners('onFocus');
+      },
+      dragStop: function () {
+        return self.callListeners('onDragStop');
+      },
+      dragStart: function () {
+        return self.callListeners('onDragStart');
+      },
+      drag: function () {
+        return self.callListeners('onDrag');
       }
     });
 
@@ -89,9 +127,16 @@ Submap.prototype.open = function (htmlTag) {
   } else {
     $(self.getElement()).dialog("open");
   }
+};
 
+Submap.prototype.close = function () {
+  var self = this;
+  if (self.isInitialized()) {
+    $(self.getElement()).dialog("close");
+  }
 };
 
+
 /**
  *
  * @param {number} identifier
diff --git a/frontend-js/src/main/js/map/data/MapModel.js b/frontend-js/src/main/js/map/data/MapModel.js
index 7e75d0e1d5eba0034b7002142b8d8e0cef042e1b..0586050a26ec45b08cf8ad0c2ae677cf777a330a 100644
--- a/frontend-js/src/main/js/map/data/MapModel.js
+++ b/frontend-js/src/main/js/map/data/MapModel.js
@@ -90,9 +90,9 @@ function MapModel(configuration) {
  * Return list of all aliases that were added to the model.
  *
  * @param {Object} params
- * @param {string} params.type
- * @param {number[]} params.includedCompartmentIds
- * @param {number[]} params.excludedCompartmentIds
+ * @param {string|string[]} params.type
+ * @param {number[]} [params.includedCompartmentIds]
+ * @param {number[]} [params.excludedCompartmentIds]
  * @param {boolean} params.complete
  * @returns {Promise}
  */
diff --git a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
index 594cd2fb9452cb8b902654d337b6ee8492e1790a..6a30568a937a07888ecc4bd7b106fbfde43e8a02 100644
--- a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
+++ b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
@@ -8,6 +8,7 @@ var Configuration = require('../Configuration');
 var Bounds = require('../map/canvas/Bounds');
 var Point = require('../map/canvas/Point');
 
+// noinspection JSUnusedLocalSymbols
 var logger = require('../logger');
 
 var Promise = require("bluebird");
@@ -279,6 +280,32 @@ function createMarkerElements(options) {
   return markerElements;
 }
 
+/**
+ *
+ * @param {Object} param
+ * @returns {function(*): *}
+ */
+function createWrapperFunctionForDialogGuiUpdate(param) {
+  /**
+   *
+   * @param {AbstractCustomMap} e.object
+   * @returns {Promise}
+   */
+  return function (e) {
+    var submap = e.object;
+    var div = $("[name^='submap-div-']", submap.getElement())[0];
+    var x = div.getBoundingClientRect().left - document.body.getBoundingClientRect().left;
+    var y = div.getBoundingClientRect().top - document.body.getBoundingClientRect().top;
+    var width = div.getBoundingClientRect().width;
+    var height = div.getBoundingClientRect().height;
+    return param.callback({
+      modelId: submap.getId(),
+      position: new Point(x, y),
+      size: {width: width, height: height}
+    });
+  }
+}
+
 /**
  *
  * @param {Object} options
@@ -299,6 +326,14 @@ function createProjectMap(options) {
     getVisibleDataOverlays: function () {
       return map.getVisibleDataOverlays();
     },
+    /**
+     *
+     * @param {Object} param
+     * @param {string} param.type
+     * @param {Object} [param.object]
+     * @param {function} param.callback
+     * @param {string} [param.dbOverlayName]
+     */
     addListener: function (param) {
       var objects = [];
       var listenerWrapper = null;
@@ -341,6 +376,25 @@ function createProjectMap(options) {
           throw new Error("Unknown listener type: " + param.type);
         }
         objects = objects.concat(map.getSubmaps());
+      } else if (param.object === "map-dialog") {
+        objects = objects.concat(map.getSubmaps());
+        if (param.type === "onDrag" || param.type === "onDragStart" || param.type === "onDragStop" ||
+          param.type === "onResize" || param.type === "onResizeStart" || param.type === "onResizeStop" ||
+          param.type === "onOpen") {
+          listenerWrapper = createWrapperFunctionForDialogGuiUpdate(param);
+        } else if (param.type === "onFocus") {
+          listenerWrapper = function (e) {
+            var submap = e.object;
+            return param.callback({modelId: submap.getId()});
+          };
+        } else if (param.type === "onClose") {
+          listenerWrapper = function (e) {
+            var submap = e.object;
+            return param.callback({modelId: submap.getId()});
+          };
+        } else {
+          throw new Error("Unknown listener type: " + param.type);
+        }
       } else {
         throw new Error("Invalid argument");
       }
@@ -351,6 +405,13 @@ function createProjectMap(options) {
         listenersData.push({listener: param.callback, wrapper: listenerWrapper, object: object, type: listenerType});
       }
     },
+    /**
+     *
+     * @param {Object} param
+     * @param {string} param.type
+     * @param {function} param.callback
+     * @param {string} param.dbOverlayName
+     */
     removeListener: function (param) {
       var dbOverlay = getOverlayByName(map, param.dbOverlayName);
       var indexToBeRemoved = -1;
@@ -521,8 +582,8 @@ function createProject(options) {
  *
  * @param {Object} options
  * @param {Configuration} options.configuration
- * @returns {{options: ConfigurationOption[], overlayTypes: string[], imageConverters: *, modelConverters: *, elementTypes: *, reactionTypes: *, miriamTypes: MiriamType, mapTypes: *, modificationStateTypes: *, privilegeTypes: PrivilegeType[], annotators: *}}
- */
+ * @returns {{options: ConfigurationOption[],  overlayTypes: string[],  imageConverters: ImageConverter[],  modelConverters: ModelConverter[],  elementTypes: BioEntityType[],  reactionTypes: BioEntityType[],  miriamTypes: MiriamType[],  mapTypes: MapType[],  modificationStateTypes: ModificationStateType[],  privilegeTypes: PrivilegeType[],  annotators: Annotator[]}}
+ * */
 function createConfiguration(options) {
   var configuration = new Configuration(options.configuration);
   return {
@@ -544,21 +605,22 @@ function createConfiguration(options) {
  *
  * @param {Object} options
  * @param {string} options.hash
+ * @param {ServerConnector} options.serverConnector
  * @returns {{setGlobalParam: function(*=, *=): *, getGlobalParam: function(*=): *, setUserParam: function(*=, *=): *, getUserParam: function(*=): *}}
  */
 function createPluginData(options) {
   return {
     setGlobalParam: function (key, value) {
-      return ServerConnector.setPluginGlobalParam({hash: options.hash, key: key, value: value});
+      return options.serverConnector.setPluginGlobalParam({hash: options.hash, key: key, value: value});
     },
     getGlobalParam: function (key) {
-      return ServerConnector.getPluginGlobalParam({hash: options.hash, key: key});
+      return options.serverConnector.getPluginGlobalParam({hash: options.hash, key: key});
     },
     setUserParam: function (key, value) {
-      return ServerConnector.setPluginUserParam({hash: options.hash, key: key, value: value});
+      return options.serverConnector.setPluginUserParam({hash: options.hash, key: key, value: value});
     },
     getUserParam: function (key) {
-      return ServerConnector.getPluginUserParam({hash: options.hash, key: key});
+      return options.serverConnector.getPluginUserParam({hash: options.hash, key: key});
     }
   };
 }
@@ -572,7 +634,8 @@ function createPluginData(options) {
  * @param {string} options.hash
  * @param {HTMLElement} options.element
  * @param {Configuration} options.configuration
- * @returns {{pluginId: string|string, element: *, project: {data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: *, modelConverters: *, elementTypes: *, reactionTypes: *, miriamTypes: MiriamType, mapTypes: *, modificationStateTypes: *, privilegeTypes: PrivilegeType[], annotators: *}, pluginData: {setGlobalParam: function(*=, *=): *, getGlobalParam: function(*=): *, setUserParam: function(*=, *=): *, getUserParam: function(*=): *}}}
+ * @param {ServerConnector} options.serverConnector
+ * @returns {{pluginId: string|string, element: *, project: {data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: ImageConverter[], modelConverters: ModelConverter[], elementTypes: BioEntityType[], reactionTypes: BioEntityType[], miriamTypes: MiriamType[], mapTypes: MapType[], modificationStateTypes: ModificationStateType[], privilegeTypes: PrivilegeType[], annotators: Annotator[]}, pluginData: {setGlobalParam: function(*=, *=): *, getGlobalParam: function(*=): *, setUserParam: function(*=, *=): *, getUserParam: function(*=): *}}}
  * @constructor
  */
 function MinervaPluginProxy(options) {
diff --git a/frontend-js/src/main/js/plugin/Plugin.js b/frontend-js/src/main/js/plugin/Plugin.js
index 153e3e2d5c238a39f2ac2b7b115636c10dd0b3e0..c097c0c4fa5bb4f6f5cf0c7474ae88131aea7663 100644
--- a/frontend-js/src/main/js/plugin/Plugin.js
+++ b/frontend-js/src/main/js/plugin/Plugin.js
@@ -14,6 +14,7 @@ var pluginId = 0;
  * @typedef {Object} PluginOptions
  * @property {CustomMap} map
  * @property {Configuration} configuration
+ * @property {ServerConnector} serverConnector
  * @property {HTMLElement} element
  * @property {string} [url]
  */
@@ -92,7 +93,7 @@ Plugin.prototype.getPluginId = function () {
 
 /**
  *
- * @returns {Promise}
+ * @returns {Promise|PromiseLike}
  */
 Plugin.prototype.load = function () {
   var self = this;
@@ -102,7 +103,7 @@ Plugin.prototype.load = function () {
   var error = false;
   var registerPromise = null;
 
-  return ServerConnector.sendRequest({
+  return options.serverConnector.sendRequest({
     url: options.url,
     description: "Loading plugin: " + options.url,
     method: "GET"
@@ -125,7 +126,8 @@ Plugin.prototype.load = function () {
             configuration: options.configuration,
             element: options.element,
             plugin: self,
-            pluginId: "plugin" + (pluginId++)
+            pluginId: "plugin" + (pluginId++),
+            serverConnector: options.serverConnector
           });
           self.setLoadedPluginData(pluginData);
           self.setMinervaPluginProxy(minervaPluginProxy);
@@ -141,7 +143,7 @@ Plugin.prototype.load = function () {
     } catch (e) {
       error = e;
     }
-    return ServerConnector.registerPlugin({
+    return options.serverConnector.registerPlugin({
       hash: hash,
       url: options.url,
       name: self.getName(),
@@ -222,12 +224,4 @@ Plugin.prototype.destroy = function () {
   return Promise.resolve();
 };
 
-/**
- *
- * @param {string} hash
- */
-Plugin.prototype.setHash = function (hash) {
-  this.getMinervaPluginProxy().hash = hash;
-};
-
 module.exports = Plugin;
diff --git a/frontend-js/src/main/js/plugin/PluginManager.js b/frontend-js/src/main/js/plugin/PluginManager.js
index de602f325921ade893a36966e39b703786c48f67..064259bd8f5ebe76542065e682f9fbafa7d946cb 100644
--- a/frontend-js/src/main/js/plugin/PluginManager.js
+++ b/frontend-js/src/main/js/plugin/PluginManager.js
@@ -20,6 +20,7 @@ var Functions = require('../Functions');
  * @param {CustomMap} options.customMap
  * @param {Configuration} options.configuration
  * @param {Project} options.project
+ * @param {ServerConnector} [options.serverConnector]
  * @constructor
  * @extends {AbstractGuiElement}
  */
@@ -42,6 +43,7 @@ function PluginManager(options) {
 PluginManager.prototype = Object.create(AbstractGuiElement.prototype);
 PluginManager.prototype.constructor = AbstractGuiElement;
 
+// noinspection JSUnusedGlobalSymbols
 /**
  *
  * @returns {Plugin[]}
@@ -64,7 +66,7 @@ PluginManager.prototype.getGuiUtils = function () {
 /**
  *
  * @param {Plugin|{url:string}} options
- * @returns {Plugin}
+ * @returns {Promise|PromiseLike}
  */
 PluginManager.prototype.addPlugin = function (options) {
   var self = this;
@@ -82,7 +84,8 @@ PluginManager.prototype.addPlugin = function (options) {
     plugin.setOptions({
       element: element,
       configuration: self.getConfiguration(),
-      map: self.getMap()
+      map: self.getMap(),
+      serverConnector: self.getServerConnector()
     });
   } else {
     if (!self.isValidUrl(options.url)) {
@@ -92,7 +95,8 @@ PluginManager.prototype.addPlugin = function (options) {
       url: options.url,
       element: element,
       configuration: self.getConfiguration(),
-      map: self.getMap()
+      map: self.getMap(),
+      serverConnector: self.getServerConnector()
     });
     plugin.addListener("onUnload", function () {
       self.getGuiUtils().hideTab(self, element);
@@ -100,7 +104,7 @@ PluginManager.prototype.addPlugin = function (options) {
   }
   self._plugins.push(plugin);
   return plugin.load().then(function () {
-    var liElement = $("a[href='#" + element.parentNode.id + "']", $(self.getElement()))[0].innerHTML = plugin.getName();
+    $("a[href='#" + element.parentNode.id + "']", $(self.getElement()))[0].innerHTML = plugin.getName();
     var tab = $(element.parentNode);
     var adjustHeight = function () {
       tab.css('height', 'calc( 100vh - ' + $(element.parentNode.parentNode).offset().top + 'px )');
@@ -130,7 +134,7 @@ PluginManager.prototype.isValidUrl = function (url) {
 
 /**
  *
- * @returns {Promise}
+ * @returns {Promise|PromiseLike}
  */
 PluginManager.prototype.adjustMinWidth = function () {
   var self = this;
diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js
index 11fc0efa1884a43783a7801b84373de106a9b633..a3ee154868a21a0bcab028a081a782d359c0527d 100644
--- a/frontend-js/src/test/js/helper.js
+++ b/frontend-js/src/test/js/helper.js
@@ -48,9 +48,18 @@ function Helper(configuration) {
   this.EPSILON = Helper.EPSILON;
 }
 
+/**
+ *
+ * @param {Configuration} configuration
+ */
 Helper.prototype.setConfiguration = function (configuration) {
   this._configuration = configuration;
 };
+
+/**
+ *
+ * @returns {Configuration}
+ */
 Helper.prototype.getConfiguration = function () {
   return this._configuration;
 };
diff --git a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
index 010051e604d0db1bf76b3c749bbeb57d593512d3..4715ed3b0fed6036022550d246f856fe9a689e75 100644
--- a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
+++ b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
@@ -8,6 +8,7 @@ var Promise = require("bluebird");
 var Alias = require('../../../main/js/map/data/Alias');
 var DataOverlay = require('../../../main/js/map/data/DataOverlay');
 var MinervaPluginProxy = require('../../../main/js/plugin/MinervaPluginProxy');
+var Plugin = require('../../../main/js/plugin/Plugin');
 var ServerConnector = require('../ServerConnector-mock');
 var Point = require('../../../main/js/map/canvas/Point');
 
@@ -27,20 +28,23 @@ function createProxy(map) {
     hash: "8f2112859d40de86dacc1994a224ea3d",
     map: map,
     element: testDiv,
+    plugin: new Plugin({
+      url: "./testFiles/plugin/empty.js",
+      map: map,
+      element: testDiv,
+      configuration: helper.getConfiguration(),
+      serverConnector: ServerConnector
+    }),
     pluginId: "xx",
-    configuration: helper.getConfiguration()
+    configuration: helper.getConfiguration(),
+    serverConnector: ServerConnector
   });
 }
 
 describe('MinervaPluginProxy', function () {
   it('constructor', function () {
     var map = helper.createCustomMap();
-    var proxy = new MinervaPluginProxy({
-      map: map,
-      element: testDiv,
-      pluginId: "xx",
-      configuration: helper.getConfiguration()
-    });
+    var proxy = createProxy(map);
     assert.ok(proxy);
     assert.ok(proxy.pluginId);
     assert.ok(proxy.element);
@@ -429,10 +433,10 @@ describe('MinervaPluginProxy', function () {
       center = map.getCenter();
       return proxy.project.map.fitBounds({
         modelId: 15781,
-        x1:10,
-        x2:10,
-        y1:20,
-        y2:30
+        x1: 10,
+        x2: 10,
+        y1: 20,
+        y2: 30
       });
     }).then(function () {
       var center2 = map.getCenter();
@@ -622,7 +626,7 @@ describe('MinervaPluginProxy', function () {
           type: "onCenterChanged",
           callback: function (data) {
             assert.equal(map.getId(), data.modelId);
-            var center =  data.center;
+            var center = data.center;
             assert.ok(center instanceof Point);
             assert.closeTo(parseFloat(center.x), 10, helper.EPSILON);
             assert.closeTo(parseFloat(center.y), 20, helper.EPSILON);
@@ -639,7 +643,83 @@ describe('MinervaPluginProxy', function () {
         return map.destroy();
       });
     });
-  });
 
+    describe('map-dialog', function () {
+      it('onOpen', function () {
+        helper.setUrl("http://test/?id=complex_model_with_submaps");
+        var callbackOk = false;
+        var map, submap;
+        return ServerConnector.getProject().then(function (project) {
+          map = helper.createCustomMap(project);
+          submap = map.getSubmaps()[0];
+          var proxy = createProxy(map);
+
+          proxy.project.map.addListener({
+            object: "map-dialog",
+            type: "onOpen",
+            callback: function (data) {
+              assert.equal(submap.getId(), data.modelId);
+              assert.ok(data.position);
+              assert.ok(data.size);
+              callbackOk = true;
+            }
+          });
+          return submap.open(testDiv);
+        }).then(function () {
+          assert.ok(callbackOk);
+          return map.destroy();
+        });
+      });
+
+      it('onClose', function () {
+        helper.setUrl("http://test/?id=complex_model_with_submaps");
+        var callbackOk = false;
+        var map, submap;
+        return ServerConnector.getProject().then(function (project) {
+          map = helper.createCustomMap(project);
+          submap = map.getSubmaps()[0];
+          var proxy = createProxy(map);
+
+          proxy.project.map.addListener({
+            object: "map-dialog",
+            type: "onClose",
+            callback: function (data) {
+              assert.equal(submap.getId(), data.modelId);
+              callbackOk = true;
+            }
+          });
+          return submap.open(testDiv);
+        }).then(function () {
+          return submap.close();
+        }).then(function () {
+          assert.ok(callbackOk);
+          return map.destroy();
+        });
+      });
+    });
+
+    it('onFocus', function () {
+      helper.setUrl("http://test/?id=complex_model_with_submaps");
+      var callbackOk = false;
+      var map, submap;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        submap = map.getSubmaps()[0];
+        var proxy = createProxy(map);
 
+        proxy.project.map.addListener({
+          object: "map-dialog",
+          type: "onFocus",
+          callback: function (data) {
+            assert.equal(submap.getId(), data.modelId);
+            callbackOk = true;
+          }
+        });
+        return submap.open(testDiv);
+      }).then(function () {
+        assert.ok(callbackOk);
+        return map.destroy();
+      });
+    });
+  });
 });
diff --git a/frontend-js/src/test/js/plugin/Plugin-test.js b/frontend-js/src/test/js/plugin/Plugin-test.js
index 9030472fbda476a9673729f4c272af211f79f21a..adbf4c968546a73102228882c0480cf9a0b01b82 100644
--- a/frontend-js/src/test/js/plugin/Plugin-test.js
+++ b/frontend-js/src/test/js/plugin/Plugin-test.js
@@ -5,6 +5,7 @@ require("../mocha-config");
 // noinspection JSUnusedLocalSymbols
 var Promise = require("bluebird");
 var Plugin = require('../../../main/js/plugin/Plugin');
+var ServerConnector = require('../ServerConnector-mock');
 
 var logger = require('../logger');
 var chai = require('chai');
@@ -12,28 +13,44 @@ var assert = chai.assert;
 
 var fs = require('fs');
 
+/**
+ *
+ * @param {string} file
+ * @param {CustomMap} [map]
+ * @returns {Plugin}
+ */
+function createPlugin(file, map) {
+  if (map === undefined) {
+    map = helper.createCustomMap();
+  }
+  return new Plugin({
+    url: file,
+    map: map,
+    element: testDiv,
+    configuration: helper.getConfiguration(),
+    serverConnector: ServerConnector
+  });
+}
+
 describe('Plugin', function () {
   it('constructor', function () {
     var plugin = new Plugin({
       url: "./testFiles/plugin/empty.js",
-      configuration: helper.getConfiguration()
+      configuration: helper.getConfiguration(),
+      serverConnector: ServerConnector,
+      element: testDiv,
+      map: helper.createCustomMap()
     });
     assert.ok(plugin);
   });
 
   it('test plugins', function () {
-    var map = helper.createCustomMap();
     var promises = [];
 
     fs.readdirSync('./testFiles/plugin/').forEach(function (file) {
       var element = document.createElement("div");
       testDiv.appendChild(element);
-      var plugin = new Plugin({
-        url: "./testFiles/plugin/" + file,
-        map: map,
-        element: element,
-        configuration: helper.getConfiguration()
-      });
+      var plugin = createPlugin("./testFiles/plugin/" + file);
       promises.push(plugin.load());
     });
     return Promise.all(promises);
@@ -41,13 +58,7 @@ describe('Plugin', function () {
 
   describe('load', function () {
     it('default', function () {
-      var map = helper.createCustomMap();
-
-      var plugin = new Plugin({
-        url: "./testFiles/plugin/empty.js",
-        map: map,
-        configuration: helper.getConfiguration()
-      });
+      var plugin = createPlugin("./testFiles/plugin/empty.js");
       return plugin.load().then(function () {
         assert.equal("test plugin", plugin.getName());
         assert.equal("0.0.1", plugin.getVersion());
@@ -56,11 +67,7 @@ describe('Plugin', function () {
     });
 
     it('invalid javascript code', function () {
-      var plugin = new Plugin({
-        url: "./testFiles/plugin-invalid/invalid_javascript.js",
-        map: helper.createCustomMap(),
-        configuration: helper.getConfiguration()
-      });
+      var plugin = createPlugin("./testFiles/plugin-invalid/invalid_javascript.js");
       return plugin.load().then(function () {
         assert.notOk("expected error");
       }, function (error) {
@@ -69,11 +76,7 @@ describe('Plugin', function () {
     });
 
     it('plugin register crash', function () {
-      var plugin = new Plugin({
-        url: "./testFiles/plugin-invalid/invalid_register.js",
-        map: helper.createCustomMap(),
-        configuration: helper.getConfiguration()
-      });
+      var plugin = createPlugin("./testFiles/plugin-invalid/invalid_register.js");
       return plugin.load().then(function () {
         assert.false("expected error");
       }, function (error) {
@@ -81,14 +84,10 @@ describe('Plugin', function () {
       });
     });
     it('plugin register promise reject', function () {
-      var plugin = new Plugin({
-        url: "./testFiles/plugin-invalid/result-promise-crash.js",
-        map: helper.createCustomMap(),
-        configuration: helper.getConfiguration()
-      });
+      var plugin = createPlugin("./testFiles/plugin-invalid/result-promise-crash.js");
       return plugin.load().then(function () {
         assert.false("expected error");
-      }).catch( function (error) {
+      }).catch(function (error) {
         assert.ok(error.message.indexOf("Let's reject") >= 0, "Wrong message: " + error.message);
       });
     });
@@ -98,11 +97,7 @@ describe('Plugin', function () {
       var map = helper.createCustomMap();
       helper.createSearchDbOverlay(map);
 
-      var plugin = new Plugin({
-        url: "./testFiles/plugin-invalid/unclean-unregister.js",
-        map: map,
-        configuration: helper.getConfiguration()
-      });
+      var plugin = createPlugin("./testFiles/plugin-invalid/unclean-unregister.js", map);
       return plugin.load().then(function () {
         assert.equal(0, logger.getWarnings().length);
         return plugin.unload();
diff --git a/frontend-js/src/test/js/plugin/PluginManager-test.js b/frontend-js/src/test/js/plugin/PluginManager-test.js
index 8a5e800a5b34b3d15830ec05f30bd72bf244a95b..4f76d3cde926377c2e86debf595718d8d85d726b 100644
--- a/frontend-js/src/test/js/plugin/PluginManager-test.js
+++ b/frontend-js/src/test/js/plugin/PluginManager-test.js
@@ -16,7 +16,8 @@ describe('PluginManager', function () {
     return {
       customMap: map,
       configuration: helper.getConfiguration(),
-      element: testDiv
+      element: testDiv,
+      project: map.getProject()
     };
   };
   var createPluginManager = function () {
diff --git a/frontend-js/src/test/js/plugin/ProxyAccessPlugin.js b/frontend-js/src/test/js/plugin/ProxyAccessPlugin.js
index a546e8725a88fbef76d957e0ae481c2b5a97f5d9..2190559d069912debb6ce8f1edf7e35c6dec3d7f 100644
--- a/frontend-js/src/test/js/plugin/ProxyAccessPlugin.js
+++ b/frontend-js/src/test/js/plugin/ProxyAccessPlugin.js
@@ -7,13 +7,29 @@ var Promise = require('bluebird');
 
 var logger = require('../logger');
 
-function ProxyAccessPlugin(options) {
+/**
+ *
+ * @constructor
+ * @extends Plugin
+ */
+function ProxyAccessPlugin() {
   Plugin.call(this);
 }
 
 ProxyAccessPlugin.prototype = Object.create(Plugin.prototype);
 ProxyAccessPlugin.prototype.constructor = ProxyAccessPlugin;
 
+/**
+ *
+ * @param {Object} [options]
+ * @param {CustomMap} options.map
+ * @param {Plugin} options.plugin
+ * @param {string} options.pluginId
+ * @param {string} options.hash
+ * @param {HTMLElement} options.element
+ * @param {Configuration} options.configuration
+ * @param {ServerConnector} options.ServerConnector
+ */
 ProxyAccessPlugin.prototype.setOptions = function (options) {
   if (options !== undefined) {
     options.plugin = this;
@@ -21,6 +37,10 @@ ProxyAccessPlugin.prototype.setOptions = function (options) {
   }
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 ProxyAccessPlugin.prototype.load = function () {
   this.setLoadedPluginData({
     getName: function () {
@@ -38,7 +58,13 @@ ProxyAccessPlugin.prototype.load = function () {
   });
   return Promise.resolve();
 };
+
+/**
+ *
+ * @returns {Promise}
+ */
 ProxyAccessPlugin.prototype.unload = function () {
   return Promise.resolve();
 };
+
 module.exports = ProxyAccessPlugin;