From 90113e4af84a27528b2b13c15d87bb67c56a00d4 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Mon, 21 Aug 2017 15:08:24 +0200
Subject: [PATCH] AddOverlayDialog extracted into separate class

---
 frontend-js/src/main/js/GuiConnector.js       |  10 +-
 frontend-js/src/main/js/ServerConnector.js    |  13 +-
 .../src/main/js/gui/AddOverlayDialog.js       | 240 +++++++++++++++++
 .../src/main/js/gui/leftPanel/GuiUtils.js     |   5 -
 .../src/main/js/gui/leftPanel/OverlayPanel.js | 251 +++++-------------
 .../src/main/js/map/data/LayoutData.js        |  18 ++
 .../src/test/js/ServerConnector-test.js       |   6 +-
 .../src/test/js/gui/AddOverlayDialog-test.js  |  63 +++++
 .../js/gui/leftPanel/OverlayPanel-test.js     |  15 --
 .../src/test/js/map/data/LayoutData-test.js   |  81 +++---
 frontend-js/src/test/js/mocha-config.js       |   1 +
 .../POST_content=s1%0A&token=MOCK_TOKEN_ID&   |   4 +
 12 files changed, 457 insertions(+), 250 deletions(-)
 create mode 100644 frontend-js/src/main/js/gui/AddOverlayDialog.js
 create mode 100644 frontend-js/src/test/js/gui/AddOverlayDialog-test.js
 create mode 100644 frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_content=s1%0A&token=MOCK_TOKEN_ID&

diff --git a/frontend-js/src/main/js/GuiConnector.js b/frontend-js/src/main/js/GuiConnector.js
index 1d44c47f8d..e5dea644c4 100644
--- a/frontend-js/src/main/js/GuiConnector.js
+++ b/frontend-js/src/main/js/GuiConnector.js
@@ -126,8 +126,8 @@ GuiConnector.showProcessing = function(messageText) {
   var self = GuiConnector;
   if (self._processingDialog === undefined) {
     self._processingDialog = document.createElement("div");
-    self._errorDialogContent = document.createElement("div");
-    self._processingDialog.appendChild(self._errorDialogContent);
+    self._processingDialogContent = document.createElement("div");
+    self._processingDialog.appendChild(self._processingDialogContent);
     document.body.appendChild(self._processingDialog);
     $(self._processingDialog).dialog({
       modal : true,
@@ -144,9 +144,9 @@ GuiConnector.showProcessing = function(messageText) {
     type : "img",
     src : 'resources/images/icons/ajax-loader.gif',
   });
-  self._errorDialogContent.innerHTML = "";
-  self._errorDialogContent.style.textAlign = "center";
-  self._errorDialogContent.appendChild(messageImg);
+  self._processingDialogContent.innerHTML = "";
+  self._processingDialogContent.style.textAlign = "center";
+  self._processingDialogContent.appendChild(messageImg);
 
   $(self._processingDialog).dialog("option", "title", messageText);
 
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index f595a5987f..0ce3909e05 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -1316,11 +1316,22 @@ ServerConnector.addComment = function(params) {
 };
 
 ServerConnector.addOverlay = function(params) {
+  if (!(params instanceof LayoutData)) {
+    throw new Error("Invalid overlay: " + params);
+  }
   var self = this;
   var queryParams = {};
+  var data = {
+    name : params.getName(),
+    description : params.getDescription(),
+    content : params.getContent(),
+    filename : params.getFilename(),
+  };
+  logger.info(data);
+  logger.info(params);
   return self.getProjectId(params.projectId).then(function(result) {
     queryParams.projectId = result;
-    return self.sendPostRequest(self.addOverlayUrl(queryParams), params);
+    return self.sendPostRequest(self.addOverlayUrl(queryParams), data);
   }).then(function(content) {
     return new LayoutData(JSON.parse(content));
   });
diff --git a/frontend-js/src/main/js/gui/AddOverlayDialog.js b/frontend-js/src/main/js/gui/AddOverlayDialog.js
new file mode 100644
index 0000000000..3dd4dcc4c9
--- /dev/null
+++ b/frontend-js/src/main/js/gui/AddOverlayDialog.js
@@ -0,0 +1,240 @@
+"use strict";
+
+/* exported logger */
+
+var AbstractGuiElement = require('./AbstractGuiElement');
+var Annotation = require('../map/data/Annotation');
+var GuiConnector = require('../GuiConnector');
+var GuiUtils = require('./leftPanel/GuiUtils');
+var LayoutData = require('../map/data/LayoutData');
+var NetworkError = require('../NetworkError');
+
+var Functions = require('../Functions');
+var logger = require('../logger');
+var HttpStatus = require('http-status-codes');
+
+var guiUtils = new (require('./leftPanel/GuiUtils'))();
+
+function AddOverlayDialog(params) {
+  AbstractGuiElement.call(this, params);
+  var self = this;
+  self.registerListenerType("onAddOverlay");
+  self.createGui();
+}
+
+AddOverlayDialog.prototype = Object.create(AbstractGuiElement.prototype);
+AddOverlayDialog.prototype.constructor = AddOverlayDialog;
+
+AddOverlayDialog.prototype.createGui = function() {
+  var self = this;
+  var guiUtils = new GuiUtils();
+  var fileContent = null;
+  var content = document.createElement("div");
+  content.style.width = "100%";
+  content.style.height = "100%";
+  content.appendChild(guiUtils.createLabel("Name: "));
+  var nameInput = Functions.createElement({
+    type : "input",
+    inputType : "text",
+    name : "overlay-name",
+  });
+  content.appendChild(nameInput);
+  content.appendChild(guiUtils.createNewLine());
+
+  content.appendChild(guiUtils.createLabel("Description: "));
+  content.appendChild(guiUtils.createNewLine());
+  var descriptionInput = Functions.createElement({
+    type : "textarea",
+    name : "overlay-description",
+  });
+  content.appendChild(descriptionInput);
+  content.appendChild(guiUtils.createNewLine());
+
+  content.appendChild(guiUtils.createLabel("Upload file: "));
+  var fileInput = Functions.createElement({
+    type : "input",
+    inputType : "file",
+    name : "overlay-file",
+  });
+  fileInput.addEventListener("change", function() {
+    return self.processFile(fileInput.files[0]);
+  }, false);
+  content.appendChild(fileInput);
+  content.appendChild(guiUtils.createNewLine());
+
+  content.appendChild(guiUtils.createLabel("Or provide list of elements here (one per line): "));
+  content.appendChild(guiUtils.createNewLine());
+  var contentInput = Functions.createElement({
+    type : "textarea",
+    name : "overlay-content",
+  });
+  content.appendChild(contentInput);
+  content.appendChild(guiUtils.createNewLine());
+
+  self.getElement().appendChild(content);
+};
+
+AddOverlayDialog.prototype.processFile = function(file) {
+  var self = this;
+  self.setFileContent(null);
+  if (file) {
+    return new Promise(function(resolve, reject) {
+      var reader = new FileReader();
+      reader.readAsText(file, "UTF-8");
+      reader.onload = function(evt) {
+        try {
+          self.setFileContent(evt.target.result);
+          var data = self.parseFile(evt.target.result);
+          var nameInput = $("[name='overlay-name']", self.getElement())[0];
+          var descriptionInput = $("[name='overlay-description']", self.getElement())[0];
+          if (data.name !== undefined) {
+            nameInput.value = data.name;
+          } else {
+            var filename = $("[name='overlay-file']", self.getElement())[0].value;
+            if (filename.indexOf(".") > 0) {
+              filename = filename.substr(0, filename.indexOf("."));
+            }
+            if (filename.lastIndexOf("\\") >= 0) {
+              filename = filename.substr(filename.lastIndexOf("\\") + 1);
+            }
+
+            nameInput.value = filename;
+          }
+          if (data.description !== undefined) {
+            descriptionInput.value = data.description;
+          }
+          resolve(self.getFileContent());
+        } catch (error) {
+          reject(error);
+        }
+      };
+      reader.onerror = function() {
+        reject(new Error("Problem reading file"));
+      };
+    });
+  } else {
+    return Promise.resolve(null);
+  }
+};
+
+AddOverlayDialog.prototype.setFileContent = function(fileContent) {
+  this._fileContent = fileContent;
+};
+
+AddOverlayDialog.prototype.getFileContent = function() {
+  var self = this;
+  var contentInput = $("[name='overlay-content']", self.getElement())[0];
+
+  if (contentInput.value !== undefined && contentInput.value !== null) {
+    contentInput.value = contentInput.value.trim();
+    if (contentInput.value !== "") {
+      self._fileContent = contentInput.value;
+    }
+  }
+  if (self._fileContent === undefined) {
+    return null;
+  } else {
+    return self._fileContent;
+  }
+};
+
+AddOverlayDialog.prototype.init = function() {
+  return Promise.resolve();
+};
+
+AddOverlayDialog.prototype.addOverlay = function() {
+  var self = this;
+  var nameInput = $("[name='overlay-name']", self.getElement())[0];
+  var descriptionInput = $("[name='overlay-description']", self.getElement())[0];
+  var filename = $("[name='overlay-file']", self.getElement())[0].value;
+  var overlay = new LayoutData({
+    name : nameInput.value,
+    description : descriptionInput.value,
+    content : self.getFileContent(),
+    filename : filename,
+  });
+  GuiConnector.showProcessing();
+  return ServerConnector.addOverlay(overlay).then(function(result) {
+    overlay = result;
+    GuiConnector.hideProcessing();
+    return self.callListeners("onAddOverlay", overlay);
+  });
+};
+
+AddOverlayDialog.prototype.destroy = function() {
+  $(this.getElement()).dialog("destroy");
+};
+
+AddOverlayDialog.prototype.open = function() {
+  var self = this;
+  var div = self.getElement();
+  if (!$(div).hasClass("ui-dialog-content")) {
+    var buttons = [ {
+      text : "UPLOAD",
+      click : function() {
+        var dialog = this;
+        var fileContent = self.getFileContent();
+        logger.info(fileContent);
+        if (fileContent === null) {
+          GuiConnector.alert("Neither file was selected nor data was entered");
+        } else if (fileContent.length > 1024 * 256) {
+          GuiConnector.alert("File to big.<br>Please reduce file size or contact administrators.");
+        } else {
+          return self.addOverlay().then(function(result) {
+            $(dialog).dialog("close");
+            return result;
+          }, function(error) {
+            GuiConnector.hideProcessing();
+            if (error instanceof NetworkError && error.statusCode === HttpStatus.BAD_REQUEST) {
+              var errorMessage = JSON.parse(error.content);
+              GuiConnector.alert("Problematic input: <br/>" + errorMessage.reason);
+            } else {
+              GuiConnector.alert(error);
+            }
+          });
+        }
+      }
+    }, {
+      text : "CANCEL",
+      click : function() {
+        $(this).dialog("close");
+      }
+    } ];
+
+    $(div).dialog({
+      title : "Add overlay",
+      buttons : buttons,
+      modal : true,
+    });
+  }
+
+  $(div).dialog("open");
+};
+
+AddOverlayDialog.prototype.parseFile = function(fileContent) {
+  var result = {};
+  var lines = fileContent.split("\n");
+  for (var i = 0; i < lines.length; i++) {
+    var line = lines[i];
+    if (line.startsWith("#")) {
+      if (line.indexOf("=") > 0) {
+        var name = line.substring(1, line.indexOf("=")).trim();
+        var value = line.substring(line.indexOf("=") + 1).trim();
+        if (name === "NAME") {
+          result.name = value;
+        } else if (name === "DESCRIPTION") {
+          result.description = value;
+        } else if (name === "TYPE") {
+          result.type = value;
+        }
+      } else {
+        logger.warn("Invalid overlay header line: " + line);
+      }
+    } else {
+      break;
+    }
+  }
+  return result;
+};
+
+module.exports = AddOverlayDialog;
diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
index ecaa7d025f..17bd7acaae 100644
--- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
+++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
@@ -232,11 +232,6 @@ GuiUtils.prototype.createTextArea = function(value) {
   }
   return result;
 };
-GuiUtils.prototype.createFileButton = function() {
-  var result = document.createElement("input");
-  result.setAttribute('type', 'file');
-  return result;
-};
 
 GuiUtils.prototype.createParamLine = function(label, value) {
   var result = document.createElement("div");
diff --git a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
index cbc48b60a3..3283d0d847 100644
--- a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
@@ -2,6 +2,7 @@
 
 /* exported logger */
 
+var AddOverlayDialog = require('../AddOverlayDialog');
 var Panel = require('../Panel');
 var PanelControlElementType = require('../PanelControlElementType');
 
@@ -16,8 +17,8 @@ function OverlayPanel(params) {
   params.panelName = "overlays";
   params.scrollable = true;
   params.helpTip = "<p>Overlays tab allows to display or generate custom coloring of elements and interactions in the map.</p>"
-    + "<p>General overlays are overlays accessible for every user viewing the content.</p>"
-    + "<p>Custom overlays are user-provided overlays, this menu becomes available upon login (see below).</p>";
+      + "<p>General overlays are overlays accessible for every user viewing the content.</p>"
+      + "<p>Custom overlays are user-provided overlays, this menu becomes available upon login (see below).</p>";
   Panel.call(this, params);
 
   var self = this;
@@ -88,20 +89,20 @@ OverlayPanel.prototype._createOverlayPanelGui = function() {
   this.setControlElement(PanelControlElementType.OVERLAY_CUSTOM_OVERLAY_TABLE, customOverlaysTableDiv);
 
   var centerTag = Functions.createElement({
-    type: "center"
+    type : "center"
   });
   customOverlaysDiv.appendChild(centerTag);
 
   var addOverlayButton = Functions.createElement({
-    type: "button",
-    name: "addOverlay",
-    content: "Add overlay"
+    type : "button",
+    name : "addOverlay",
+    content : "Add overlay"
   });
   centerTag.appendChild(addOverlayButton);
   this.setControlElement(PanelControlElementType.OVERLAY_ADD_OVERLAY_BUTTON, addOverlayButton);
 };
 
-OverlayPanel.prototype.clear = function () {
+OverlayPanel.prototype.clear = function() {
   var table = this.getControlElement(PanelControlElementType.OVERLAY_GENERAL_OVERLAY_TABLE);
   while (table.firstChild) {
     table.removeChild(table.firstChild);
@@ -114,7 +115,7 @@ OverlayPanel.prototype.clear = function () {
 
 };
 
-OverlayPanel.prototype.createTableHeader = function (edit) {
+OverlayPanel.prototype.createTableHeader = function(edit) {
   var result = document.createElement("thead");
 
   var row = document.createElement("tr");
@@ -141,7 +142,7 @@ OverlayPanel.prototype.createTableHeader = function (edit) {
   return result;
 };
 
-OverlayPanel.prototype.createOverlayRow = function (overlay, checked) {
+OverlayPanel.prototype.createOverlayRow = function(overlay, checked) {
   var self = this;
   var guiUtils = self.getGuiUtils();
   var result = document.createElement("tr");
@@ -159,7 +160,7 @@ OverlayPanel.prototype.createOverlayRow = function (overlay, checked) {
     var checkbox = document.createElement("input");
     checkbox.type = "checkbox";
     checkbox.checked = checked;
-    checkbox.onclick = function () {
+    checkbox.onclick = function() {
       if (this.checked) {
         return self.getMap().openDataOverlay(overlay.getId()).then(null, GuiConnector.alert);
       } else {
@@ -171,7 +172,7 @@ OverlayPanel.prototype.createOverlayRow = function (overlay, checked) {
     var img = guiUtils.createIcon("icons/search.png");
     var link = document.createElement("a");
     link.href = "#";
-    link.onclick = function () {
+    link.onclick = function() {
       self.getMap().openDataOverlay(overlay.getId());
       $(result).addClass('active').siblings().removeClass('active');
     };
@@ -184,10 +185,10 @@ OverlayPanel.prototype.createOverlayRow = function (overlay, checked) {
   if (overlay.getInputDataAvailable()) {
     var button = document.createElement("button");
     button.setAttribute("name", "download-overlay-" + overlay.getId());
-    button.onclick = function () {
+    button.onclick = function() {
       return ServerConnector.getOverlaySourceDownloadUrl({
-        overlayId: overlay.getId()
-      }).then(function (url) {
+        overlayId : overlay.getId()
+      }).then(function(url) {
         return self.downloadFile(url);
       }).then(null, GuiConnector.alert);
     };
@@ -201,7 +202,7 @@ OverlayPanel.prototype.createOverlayRow = function (overlay, checked) {
     var editTd = document.createElement("td");
     var editButton = document.createElement("button");
     editButton.setAttribute("name", "editButton");
-    editButton.onclick = function () {
+    editButton.onclick = function() {
       self.openEditOverlayDialog(overlay);
     };
     editButton.innerHTML = "<span class='ui-icon ui-icon-document'></span>";
@@ -264,20 +265,20 @@ OverlayPanel.prototype.openEditOverlayDialog = function(overlay) {
   });
 };
 
-OverlayPanel.prototype.refresh = function () {
+OverlayPanel.prototype.refresh = function() {
   var self = this;
   var user = null;
 
   var overlayTypes = [];
   var selectedOverlay = [];
 
-  return ServerConnector.getOverlayTypes().then(function (types) {
+  return ServerConnector.getOverlayTypes().then(function(types) {
     overlayTypes = types;
     return ServerConnector.getLoggedUser();
-  }).then(function (loggedUser) {
+  }).then(function(loggedUser) {
     user = loggedUser;
     return self.getMap().getVisibleDataOverlays();
-  }).then(function (visibleDataOverlays) {
+  }).then(function(visibleDataOverlays) {
     for (var j = 0; j < visibleDataOverlays.length; j++) {
       selectedOverlay[visibleDataOverlays[j].getId()] = true;
     }
@@ -308,190 +309,70 @@ OverlayPanel.prototype.refresh = function () {
         var table = self.getControlElement(PanelControlElementType.OVERLAY_GENERAL_OVERLAY_TABLE);
         table.appendChild(self.createTableHeader());
 
-      var body = document.createElement("tbody");
-      table.appendChild(body);
-      for (i = 0; i < generalOverlays.length; i++) {
-        overlay = generalOverlays[i];
-        body.appendChild(self.createOverlayRow(overlay, selectedOverlay[overlay.getId()]));
-      }
+        var body = document.createElement("tbody");
+        table.appendChild(body);
+        for (i = 0; i < generalOverlays.length; i++) {
+          overlay = generalOverlays[i];
+          body.appendChild(self.createOverlayRow(overlay, selectedOverlay[overlay.getId()]));
+        }
 
-      var title = self.getControlElement(PanelControlElementType.OVERLAY_CUSTOM_OVERLAY_TITLE);
-      var addButton = self.getControlElement(PanelControlElementType.OVERLAY_ADD_OVERLAY_BUTTON);
-      if (user.getLogin() === "anonymous") {
-        title.innerHTML = 'YOU ARE NOT LOGGED IN. PLEASE, <a href="#">LOG IN</a>'
-          + 'TO UPLOAD AND VIEW CUSTOM OVERLAYS<br/><center><button>LOGIN</button></center>';
-        var openLoginDialog = function () {
-          return self.getParent().getLoginDialog().open();
-        };
-        $(title).find("a")[0].onclick = openLoginDialog;
-        $(title).find("button")[0].onclick = openLoginDialog;
-        addButton.style.display = "none";
-      } else {
-        title.innerHTML = self.getCustomOverlaysMessage();
-        addButton.style.display = "block";
+        var title = self.getControlElement(PanelControlElementType.OVERLAY_CUSTOM_OVERLAY_TITLE);
+        var addButton = self.getControlElement(PanelControlElementType.OVERLAY_ADD_OVERLAY_BUTTON);
+        if (user.getLogin() === "anonymous") {
+          title.innerHTML = 'YOU ARE NOT LOGGED IN. PLEASE, <a href="#">LOG IN</a>'
+              + 'TO UPLOAD AND VIEW CUSTOM OVERLAYS<br/><center><button>LOGIN</button></center>';
+          var openLoginDialog = function() {
+            return self.getParent().getLoginDialog().open();
+          };
+          $(title).find("a")[0].onclick = openLoginDialog;
+          $(title).find("button")[0].onclick = openLoginDialog;
+          addButton.style.display = "none";
+        } else {
+          title.innerHTML = self.getCustomOverlaysMessage();
+          addButton.style.display = "block";
 
-        table = self.getControlElement(PanelControlElementType.OVERLAY_CUSTOM_OVERLAY_TABLE);
-        table.appendChild(self.createTableHeader(true));
+          table = self.getControlElement(PanelControlElementType.OVERLAY_CUSTOM_OVERLAY_TABLE);
+          table.appendChild(self.createTableHeader(true));
 
-        body = document.createElement("tbody");
-        table.appendChild(body);
-        for (i = 0; i < customOverlays.length; i++) {
-          overlay = customOverlays[i];
-          body.appendChild(self.createOverlayRow(overlay, selectedOverlay[overlay.getId()]));
+          body = document.createElement("tbody");
+          table.appendChild(body);
+          for (i = 0; i < customOverlays.length; i++) {
+            overlay = customOverlays[i];
+            body.appendChild(self.createOverlayRow(overlay, selectedOverlay[overlay.getId()]));
+          }
         }
-      }
 
-      self.onresize();
-    });
+        self.onresize();
+      });
 };
 
-OverlayPanel.prototype.setCustomOverlaysMessage = function (customOverlaysMessage) {
+OverlayPanel.prototype.setCustomOverlaysMessage = function(customOverlaysMessage) {
   this._customOverlaysMessage = customOverlaysMessage;
 };
 
-OverlayPanel.prototype.getCustomOverlaysMessage = function () {
+OverlayPanel.prototype.getCustomOverlaysMessage = function() {
   return this._customOverlaysMessage;
 };
 
-OverlayPanel.prototype.parseFile = function (fileContent) {
-  var result = {};
-  var lines = fileContent.split("\n");
-  for (var i = 0; i < lines.length; i++) {
-    var line = lines[i];
-    if (line.startsWith("#")) {
-      if (line.indexOf("=") > 0) {
-        var name = line.substring(1, line.indexOf("=")).trim();
-        var value = line.substring(line.indexOf("=") + 1).trim();
-        if (name === "NAME") {
-          result.name = value;
-        } else if (name === "DESCRIPTION") {
-          result.description = value;
-        } else if (name === "TYPE") {
-          result.type = value;
-        }
-      } else {
-        logger.warn("Invalid overlay header line: " + line);
-      }
-    } else {
-      break;
-    }
-  }
-  return result;
-};
 
-OverlayPanel.prototype.openAddOverlayDialog = function () {
+OverlayPanel.prototype.openAddOverlayDialog = function() {
   var self = this;
-  var guiUtils = self.getGuiUtils();
-  var fileContent = null;
-  var contentInput = null;
-  var content = document.createElement("div");
-  content.style.width = "100%";
-  content.style.height = "100%";
-  content.appendChild(guiUtils.createLabel("Name: "));
-  var nameInput = guiUtils.createInputText();
-  content.appendChild(nameInput);
-  content.appendChild(guiUtils.createNewLine());
-
-  content.appendChild(guiUtils.createLabel("Description: "));
-  content.appendChild(guiUtils.createNewLine());
-  var descriptionInput = guiUtils.createTextArea();
-  content.appendChild(descriptionInput);
-  content.appendChild(guiUtils.createNewLine());
-
-  content.appendChild(guiUtils.createLabel("Upload file: "));
-  var fileInput = guiUtils.createFileButton();
-  fileInput.addEventListener("change", function () {
-    fileContent = null;
-    var file = fileInput.files[0];
-    if (file) {
-      var reader = new FileReader();
-      reader.readAsText(file, "UTF-8");
-      reader.onload = function (evt) {
-        fileContent = evt.target.result;
-        var data = self.parseFile(fileContent);
-        if (data.name !== undefined) {
-          nameInput.value = data.name;
-        } else {
-          var filename = fileInput.value;
-          if (filename.indexOf(".") > 0) {
-            filename = filename.substr(0, filename.indexOf("."));
-          }
-          if (filename.lastIndexOf("\\") >= 0) {
-            filename = filename.substr(filename.lastIndexOf("\\") + 1);
-          }
-          nameInput.value = filename;
-        }
-        if (data.description !== undefined) {
-          descriptionInput.value = data.description;
-        }
-      };
-      reader.onerror = function () {
-        GuiConnector.alert("Problem reading file");
-      };
-    }
-  }, false);
-  content.appendChild(fileInput);
-  content.appendChild(guiUtils.createNewLine());
-
-  content.appendChild(guiUtils.createLabel("Or provide list of elements here (one per line): "));
-  content.appendChild(guiUtils.createNewLine());
-  contentInput = guiUtils.createTextArea();
-  content.appendChild(contentInput);
-  content.appendChild(guiUtils.createNewLine());
-
-  var buttons = [{
-    text: "UPLOAD",
-    click: function () {
-      var dialog = this;
-      if (contentInput.value !== undefined && contentInput.value !== null) {
-        contentInput.value = contentInput.value.trim();
-        if (contentInput.value !== "") {
-          fileContent = contentInput.value;
-        }
-      }
-      if (fileContent === null) {
-        GuiConnector.alert("Neither file was selected nor data was entered");
-      } else if (fileContent.length > 1024 * 256) {
-        GuiConnector.alert("File to big.<br>Please reduce file size or contact administrators.");
-      } else {
-        var data = {
-          name: nameInput.value,
-          description: descriptionInput.value,
-          content: fileContent,
-          filename: fileInput.value
-        };
-        GuiConnector.showProcessing();
-        return ServerConnector.addOverlay(data).then(function (overlay) {
-          self.getMap().getModel().addLayout(overlay);
-          return self.refresh();
-        }).then(function () {
-          GuiConnector.hideProcessing();
-          $(dialog).dialog("close");
-        }, function (error) {
-          GuiConnector.hideProcessing();
-          if (error instanceof NetworkError && error.statusCode === HttpStatus.BAD_REQUEST) {
-            var errorMessage = JSON.parse(error.content);
-            GuiConnector.alert("Problematic input: <br/>" + errorMessage.reason);
-          } else {
-            GuiConnector.alert(error);
-          }
-        });
-      }
-    }
-  }, {
-    text: "CANCEL",
-    click: function () {
-      $(this).dialog("close");
-    }
-  }];
-  self.openDialog(content, {
-    id: "addOverlay",
-    modal: true,
-    buttons: buttons,
+  var addOverlayDialog = new AddOverlayDialog({
+    project : self.getProject(),
+    customMap : self.getMap(),
+    element : document.createElement("div"),
+  });
+  addOverlayDialog.addListener("onAddOverlay", function(e) {
+    logger.info(e.arg);
+    self.getMap().getModel().addLayout(e.arg);
+    return self.refresh();
+  })
+  return addOverlayDialog.init().then(function() {
+    return addOverlayDialog.open();
   });
 };
 
-OverlayPanel.prototype.init = function () {
+OverlayPanel.prototype.init = function() {
   return this.refresh();
 };
 module.exports = OverlayPanel;
diff --git a/frontend-js/src/main/js/map/data/LayoutData.js b/frontend-js/src/main/js/map/data/LayoutData.js
index 57d50f087c..e502f6d1b5 100644
--- a/frontend-js/src/main/js/map/data/LayoutData.js
+++ b/frontend-js/src/main/js/map/data/LayoutData.js
@@ -23,6 +23,8 @@ function LayoutData(layoutId, name) {
     this.setDirectory(object.directory);
     this.setDescription(object.description);
     this.setCreator(object.creator);
+    this.setContent(object.content);
+    this.setFilename(object.filename);
     this.setPublicOverlay(object.publicOverlay);
     this.setInputDataAvailable(object.inputDataAvailable);
     if (!this.getInputDataAvailable()) {
@@ -193,4 +195,20 @@ LayoutData.prototype.setPublicOverlay = function(publicOverlay) {
   this._publicOverlay = publicOverlay;
 };
 
+LayoutData.prototype.getContent = function() {
+  return this._content;
+};
+
+LayoutData.prototype.setContent = function(content) {
+  this._content = content;
+};
+
+LayoutData.prototype.getFilename = function() {
+  return this._filename;
+};
+
+LayoutData.prototype.setFilename= function(filename) {
+  this._filename = filename;
+};
+
 module.exports = LayoutData;
diff --git a/frontend-js/src/test/js/ServerConnector-test.js b/frontend-js/src/test/js/ServerConnector-test.js
index 25afdddd62..60ba0d7c46 100644
--- a/frontend-js/src/test/js/ServerConnector-test.js
+++ b/frontend-js/src/test/js/ServerConnector-test.js
@@ -170,13 +170,13 @@ describe('ServerConnector', function() {
   });
 
   it('addOverlay', function() {
-    return ServerConnector.addOverlay({
+    return ServerConnector.addOverlay(new LayoutData({
       name : "test nam",
       description : "test desc",
       content : "name color\nCAPN1 #00FF00\nPARK7 #AC0000",
       filename : "test.txt"
-    }).then(function(overlayId) {
-      assert.ok(overlayId);
+    })).then(function(overlay) {
+      assert.ok(overlay);
     });
   });
 
diff --git a/frontend-js/src/test/js/gui/AddOverlayDialog-test.js b/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
new file mode 100644
index 0000000000..dd4759e577
--- /dev/null
+++ b/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
@@ -0,0 +1,63 @@
+"use strict";
+
+/* exported logger */
+
+require("../mocha-config.js");
+
+var AddOverlayDialog = require('../../../main/js/gui/AddOverlayDialog');
+
+var chai = require('chai');
+var assert = chai.assert;
+var logger = require('../logger');
+
+describe('AddOverlayDialog', function() {
+
+  describe('processFile', function() {
+    it('default', function() {
+      return ServerConnector.getProject().then(function(project) {
+        var dialog = new AddOverlayDialog({
+          element : testDiv,
+          project : project,
+          customMap : null
+        });
+
+        var file = new Blob([ "#DESCRIPTION=xxx\nname\tvalue\ns1\t1" ]);
+        return dialog.processFile(file).then(function(content) {
+          assert.ok(content !== null);
+        });
+      })
+    });
+  });
+
+  it('addOverlay', function() {
+    return ServerConnector.getProject().then(function(project) {
+      var dialog = new AddOverlayDialog({
+        element : testDiv,
+        project : project,
+        customMap : null
+      });
+
+      dialog.setFileContent("s1\n");
+      return dialog.addOverlay();
+    })
+  });
+
+  
+  it('parse overlay file', function() {
+    return ServerConnector.getProject().then(function(project) {
+      var dialog = new AddOverlayDialog({
+        element : testDiv,
+        project : project,
+        customMap : null
+      });
+
+      return ServerConnector.sendGetRequest("testFiles/overlay/good.txt").then(function(fileContent) {
+        var obj = dialog.parseFile(fileContent);
+        assert.equal(obj.name, "example name");
+        assert.equal(obj.description, "layout description");
+        assert.equal(obj.type, "GENERIC");
+      });
+    });
+  });
+
+});
diff --git a/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js b/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
index 388d4e32c2..0620bc0ac0 100644
--- a/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
+++ b/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
@@ -101,20 +101,5 @@ describe('OverlayPanel', function() {
     return panel.openAddOverlayDialog();
   });
 
-  it('parse overlay file', function() {
-    var map = helper.createCustomMap();
-
-    var panel = new OverlayPanel({
-      element : testDiv,
-      customMap : map
-    });
-
-    return ServerConnector.sendGetRequest("testFiles/overlay/good.txt").then(function(fileContent) {
-      var obj = panel.parseFile(fileContent);
-      assert.equal(obj.name, "example name");
-      assert.equal(obj.description, "layout description");
-      assert.equal(obj.type, "GENERIC");
-    });
-  });
 
 });
diff --git a/frontend-js/src/test/js/map/data/LayoutData-test.js b/frontend-js/src/test/js/map/data/LayoutData-test.js
index 7939f504cd..ed1af0ba80 100644
--- a/frontend-js/src/test/js/map/data/LayoutData-test.js
+++ b/frontend-js/src/test/js/map/data/LayoutData-test.js
@@ -9,42 +9,51 @@ var assert = chai.assert;
 var logger = require('../../logger');
 
 describe('LayoutData', function() {
-  it("contructor", function() {
-    var layoutId = 3;
-    var name = "nm";
-    var overlay = new LayoutData(layoutId, name);
-    assert.equal(overlay.getId(), layoutId);
-    assert.equal(overlay.getName(), name);
-  });
+  describe("contructor", function() {
+    it("default", function() {
+      var layoutId = 3;
+      var name = "nm";
+      var overlay = new LayoutData(layoutId, name);
+      assert.equal(overlay.getId(), layoutId);
+      assert.equal(overlay.getName(), name);
+    });
 
-  it("contructor from json obj", function() {
-    var obj = {
-      modelId : 15781,
-      name : "test",
-      description : "test",
-      status : "OK",
-      progress : "0.00",
-      directory : "dir/subDir",
-      creator : "admin ",
-      inputDataAvailable : "true",
-      idObject : 14852
-    };
-    var data = new LayoutData(obj);
-    assert.ok(data);
-    assert.equal(data.getInputDataAvailable(), true);
-    assert.equal(data.getDirectory(), "dir/subDir");
-  });
+    it("with content", function() {
+      var overlay = new LayoutData({
+        content : "test"
+      });
+      assert.ok(overlay.getContent());
+    });
 
-  it("contructor from prolematic json", function() {
-    var obj = {
-      modelId : 15781,
-      name : "test",
-      inputDataAvailable : "wtf",
-      idObject : 14852
-    };
-    var data = new LayoutData(obj);
-    assert.ok(data);
-    assert.equal(logger.getWarnings().length, 1);
+    it("from json obj", function() {
+      var obj = {
+        modelId : 15781,
+        name : "test",
+        description : "test",
+        status : "OK",
+        progress : "0.00",
+        directory : "dir/subDir",
+        creator : "admin ",
+        inputDataAvailable : "true",
+        idObject : 14852
+      };
+      var data = new LayoutData(obj);
+      assert.ok(data);
+      assert.equal(data.getInputDataAvailable(), true);
+      assert.equal(data.getDirectory(), "dir/subDir");
+    });
+
+    it("from prolematic json", function() {
+      var obj = {
+        modelId : 15781,
+        name : "test",
+        inputDataAvailable : "wtf",
+        idObject : 14852
+      };
+      var data = new LayoutData(obj);
+      assert.ok(data);
+      assert.equal(logger.getWarnings().length, 1);
+    });
   });
 
   it("updateAlias", function() {
@@ -81,12 +90,12 @@ describe('LayoutData', function() {
     var aliasId = 329163;
     var alias = new LayoutAlias({
       idObject : aliasId,
-      modelId: 15781,
+      modelId : 15781,
     });
 
     overlay.addAlias(alias);
 
-    return overlay.getFullAliasById(aliasId).then(function(data){
+    return overlay.getFullAliasById(aliasId).then(function(data) {
       assert.equal(data.getType(), LayoutAlias.GENERIC);
     });
   });
diff --git a/frontend-js/src/test/js/mocha-config.js b/frontend-js/src/test/js/mocha-config.js
index fa68c112a6..2386f2d30d 100644
--- a/frontend-js/src/test/js/mocha-config.js
+++ b/frontend-js/src/test/js/mocha-config.js
@@ -26,6 +26,7 @@ global.window.$ = $;
 global.Option = window.Option;
 global.Blob = window.Blob;
 global.MouseEvent = window.MouseEvent;
+global.FileReader = window.FileReader;
 
 var originalCreateElement = document.createElement;
 document.createElement = function(arg) {
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_content=s1%0A&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_content=s1%0A&token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000..8d8dfbd5e9
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_content=s1%0A&token=MOCK_TOKEN_ID&
@@ -0,0 +1,4 @@
+{
+  "status": "OK",
+  "overlayId": 17296
+}
\ No newline at end of file
-- 
GitLab