diff --git a/frontend-js/src/main/js/Functions.js b/frontend-js/src/main/js/Functions.js
index bf016d2f577ff11e7b0ce9b22375d1aa5c9006b3..9fc811c193ad498b7de77357be40ad692ef259e4 100644
--- a/frontend-js/src/main/js/Functions.js
+++ b/frontend-js/src/main/js/Functions.js
@@ -264,9 +264,11 @@ Functions.getElementByName = function (element, name) {
  *
  * @param {Object} params
  * @param {string} params.type type of the {HTMLElement} to be created
+ * @param {string} [params.inputType] type of the input to be created
  * @param {string} [params.className] css class of the element
  * @param {string} [params.style] css styling
  * @param {string} [params.value]
+ * @param {string|HTMLElement} [params.content]
  *
  * @returns {HTMLElement}
  */
@@ -285,7 +287,9 @@ Functions.createElement = function (params) {
     result.type = params.inputType;
   }
   if (params.content !== null && params.content !== undefined) {
-    if (params.xss !== false) {
+    if (Functions.isDomElement(params.content)) {
+      result.appendChild(params.content);
+    } else if (params.xss !== false) {
       var content = xss(params.content);
       if (content !== params.content) {
         logger.warn("XSS changed content: " + params.content);
diff --git a/frontend-js/src/main/js/ObjectWithListeners.js b/frontend-js/src/main/js/ObjectWithListeners.js
index df0dfa815cbd5683ab8b935cf46dd8456cb99ba4..5b54f6f37f2900ab379ec623995364b282f2339d 100644
--- a/frontend-js/src/main/js/ObjectWithListeners.js
+++ b/frontend-js/src/main/js/ObjectWithListeners.js
@@ -143,7 +143,7 @@ ObjectWithListeners.prototype.removePropertyListener = function (name, fun) {
  * @param arg
  *          argument data passed to the handler
  *
- * @returns {Promise}
+ * @returns {PromiseLike}
  */
 ObjectWithListeners.prototype.callListeners = function (type, arg) {
   if (this._validListeners[type] === undefined) {
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 422f046f7c72e745c6f9fc2632b94c905991fb78..58058cf16cfcd17dbb36bccd5c0851fbffeaad7d 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -150,6 +150,11 @@ function isSessionExpiredError(error) {
   return false;
 }
 
+/**
+ *
+ * @param params
+ * @returns {PromiseLike}
+ */
 ServerConnector.sendRequest = function (params) {
   var self = this;
   if (arguments.length > 1) {
@@ -236,6 +241,12 @@ ServerConnector.sendDeleteRequest = function (url, json) {
   });
 };
 
+/**
+ *
+ * @param url
+ * @param json
+ * @returns {PromiseLike}
+ */
 ServerConnector.sendPatchRequest = function (url, json) {
   return this.sendRequest({
     method: "PATCH",
@@ -279,7 +290,7 @@ ServerConnector.createGetParams = function (params, prefix) {
     if (prefix !== undefined) {
       key = prefix + "." + key;
     }
-    if (value instanceof Point ) {
+    if (value instanceof Point) {
       value = this.pointToString(value);
     } else if (Object.prototype.toString.call(value) === '[object Array]') {
       value = this.idsToString(value);
@@ -829,6 +840,11 @@ ServerConnector.getProject = function (projectId) {
   });
 };
 
+/**
+ *
+ * @param {Project} project
+ * @returns {PromiseLike|Promise}
+ */
 ServerConnector.updateProject = function (project) {
   var self = this;
   var queryParams = {
@@ -840,14 +856,16 @@ ServerConnector.updateProject = function (project) {
       version: project.getVersion(),
       notifyEmail: project.getNotifyEmail(),
       organism: self.serialize(project.getOrganism()),
-      disease: self.serialize(project.getDisease())
+      disease: self.serialize(project.getDisease()),
+      mapCanvasType: project.getMapCanvasType()
     }
   };
   return self.sendPatchRequest(self.getProjectUrl(queryParams), filterParams).then(function (content) {
     var downloadedProject = new Project(content);
-    project.update(downloadedProject);
+    return project.update(downloadedProject);
+  }).then(function () {
     return project;
-  }).then(null, function (error) {
+  }).catch(function (error) {
     if ((error instanceof NetworkError)) {
       switch (error.statusCode) {
         case HttpStatus.FORBIDDEN:
diff --git a/frontend-js/src/main/js/gui/AbstractGuiElement.js b/frontend-js/src/main/js/gui/AbstractGuiElement.js
index 59af4fa59929b15570ddaf0b93214e1e805d1252..f2817d3a395badbdaf3103c8d5c39cbeb3974f00 100644
--- a/frontend-js/src/main/js/gui/AbstractGuiElement.js
+++ b/frontend-js/src/main/js/gui/AbstractGuiElement.js
@@ -54,6 +54,10 @@ AbstractGuiElement.prototype.setProject = function (project) {
   this._project = project;
 };
 
+/**
+ *
+ * @returns {Project}
+ */
 AbstractGuiElement.prototype.getProject = function () {
   if (this._project === undefined || this._project === null) {
     return this.getMap().getProject();
@@ -97,6 +101,10 @@ AbstractGuiElement.prototype.setConfiguration = function (configuration) {
   this._configuration = configuration;
 };
 
+/**
+ *
+ * @returns {Configuration}
+ */
 AbstractGuiElement.prototype.getConfiguration = function () {
   return this._configuration;
 };
diff --git a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
index 963c02464c218224b94a584a01ab9825f29865ec..99f09eba27e999cc0923825799decaee9f05b29f 100644
--- a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
@@ -323,7 +323,7 @@ AddProjectDialog.prototype.createGeneralTabContent = function () {
     onclick: function () {
       return self.onSaveClicked().then(function () {
         return self.close();
-      }, GuiConnector.alert);
+      }).catch(GuiConnector.alert);
     },
     xss: false
   });
@@ -429,8 +429,8 @@ AddProjectDialog.prototype.createRow = function (elements) {
     result.appendChild(element);
   }
   return result;
-
 };
+
 AddProjectDialog.prototype.createOverlaysTab = function (tabMenuDiv, tabContentDiv) {
   var self = this;
   self.addTab({
@@ -792,7 +792,7 @@ AddProjectDialog.prototype._fillMapCanvasTypeSelectOptions = function (select, c
       }
       $(licenceCheckbox).prop('checked', false);
     });
-  })
+  });
 };
 
 
diff --git a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
index b65a1d542b9a1646f678488c5a9d5f7930a03f54..e43b1160d326762bf05246cd50fcffffd93b029b 100644
--- a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
@@ -9,6 +9,7 @@ var Annotation = require('../../map/data/Annotation');
 var CommentsTab = require('./CommentsAdminPanel');
 var GuiConnector = require('../../GuiConnector');
 var PrivilegeType = require('../../map/data/PrivilegeType');
+var ValidationError = require("../../ValidationError");
 
 var Functions = require('../../Functions');
 // noinspection JSUnusedLocalSymbols
@@ -157,12 +158,52 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
     style: "display:table-cell",
     content: "ProjectId"
   }));
-  projectIdRow.appendChild(new Functions.createElement({
+  projectIdRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: project.getProjectId()
   }));
 
+  var mapCanvasTypeRow = Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(mapCanvasTypeRow);
+  mapCanvasTypeRow.appendChild(Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Map canvas type: "
+  }));
+  mapCanvasTypeRow.appendChild(Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: Functions.createElement({
+      type: "select",
+      name: "project-map-canvas-type"
+    })
+  }));
+
+  var googleLicenseRow = Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(googleLicenseRow);
+  googleLicenseRow.appendChild(Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "I agree to <a href='https://developers.google.com/maps/terms'>Google Maps APIs Terms of Service</a>: ",
+    xss: false
+  }));
+  googleLicenseRow.appendChild(Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: Functions.createElement({
+      type: "input",
+      inputType: "checkbox",
+      name: "project-google-maps-license"
+    })
+  }));
+
   var nameRow = new Functions.createElement({
     type: "div",
     style: "display:table-row"
@@ -548,6 +589,42 @@ EditProjectDialog.prototype.init = function () {
   }).then(function () {
     return self.refreshComments();
   }).then(function () {
+    var configuration = self.getConfiguration();
+    var mapCanvasTypes = configuration.getMapCanvasTypes();
+    var select = $("[name='project-map-canvas-type']", self.getElement())[0];
+    var licenceCheckbox = $("[name='project-google-maps-license']", self.getElement())[0];
+    var licenceDiv = licenceCheckbox.parentElement.parentElement;
+
+    for (var i = 0; i < mapCanvasTypes.length; i++) {
+      var mapCanvasType = mapCanvasTypes[i];
+      var option = Functions.createElement({
+        type: "option",
+        content: mapCanvasType.name,
+        value: mapCanvasType.id
+      });
+      if (mapCanvasType.id === self.getProject().getMapCanvasType()) {
+        option.selected = true;
+        if (mapCanvasType.id === "GOOGLE_MAPS_API") {
+          $(licenceDiv).css("display", "table-row");
+          self.setLicenseAccepted(true);
+        } else {
+          $(licenceDiv).css("display", "none");
+          self.setLicenseAccepted(false);
+        }
+      }
+      select.appendChild(option);
+    }
+    $(select).change(function () {
+      $("option:selected", select).each(function () {
+        if ($(this).val() === "GOOGLE_MAPS_API") {
+          $(licenceDiv).css("display", "table-row");
+        } else {
+          $(licenceDiv).css("display", "none");
+        }
+        self.setLicenseAccepted(false);
+      });
+    });
+
     $(window).trigger('resize');
   });
 };
@@ -784,18 +861,45 @@ var prepareMiriamData = function (type, resource) {
   }
 };
 
+/**
+ *
+ * @returns {PromiseLike}
+ */
 EditProjectDialog.prototype.onSaveClicked = function () {
   var self = this;
   var project = self.getProject();
   var element = self.getElement();
-  project.setName($("[name='projectName']", element)[0].value);
-  project.setVersion($("[name='projectVersion']", element)[0].value);
-  project.setNotifyEmail($("[name='projectNotifyEmail']", element)[0].value);
-  var organism = prepareMiriamData("TAXONOMY", $("[name='projectOrganism']", element)[0].value);
-  project.setOrganism(organism);
-  var disease = prepareMiriamData("MESH_2012", $("[name='projectDisease']", element)[0].value);
-  project.setDisease(disease);
-  return ServerConnector.updateProject(project);
+  return self.checkValidity().then(function () {
+    project.setName($("[name='projectName']", element)[0].value);
+    project.setVersion($("[name='projectVersion']", element)[0].value);
+    project.setNotifyEmail($("[name='projectNotifyEmail']", element)[0].value);
+    var organism = prepareMiriamData("TAXONOMY", $("[name='projectOrganism']", element)[0].value);
+    project.setOrganism(organism);
+    var disease = prepareMiriamData("MESH_2012", $("[name='projectDisease']", element)[0].value);
+    project.setDisease(disease);
+    project.setMapCanvasType(self.getMapCanvasTypeId());
+    return ServerConnector.updateProject(project);
+  });
+};
+
+EditProjectDialog.prototype.checkValidity = function () {
+  var self = this;
+  var isValid = true;
+  var error = "<b>Some data is missing.</b><ul>";
+
+  var mapCanvasTypeId = self.getMapCanvasTypeId();
+  if (mapCanvasTypeId === "GOOGLE_MAPS_API") {
+    if (!self.isLicenseAccepted()) {
+      isValid = false;
+      error += "<li>Please accept Google Maps License when choosing Google Maps API engine</li>";
+    }
+  }
+
+  if (isValid) {
+    return Promise.resolve(true);
+  } else {
+    return Promise.reject(new ValidationError(error));
+  }
 };
 EditProjectDialog.prototype.close = function () {
   var self = this;
@@ -905,5 +1009,35 @@ EditProjectDialog.prototype.destroy = function () {
   }
 };
 
+/**
+ *
+ * @param {string} mapCanvasTypeId
+ */
+EditProjectDialog.prototype.setMapCanvasTypeId = function (mapCanvasTypeId) {
+  var select = $("[name='project-map-canvas-type']", this.getElement());
+  select.val(mapCanvasTypeId);
+  select.change();
+};
+
+/**
+ *
+ * @returns {string}
+ */
+EditProjectDialog.prototype.getMapCanvasTypeId = function () {
+  return $("[name='project-map-canvas-type']", this.getElement()).val();
+};
+
+
+EditProjectDialog.prototype.setLicenseAccepted = function (isLicenseAccepted) {
+  $("[name='project-google-maps-license']", this.getElement()).prop("checked", isLicenseAccepted);
+};
+
+/**
+ *
+ * @returns {boolean}
+ */
+EditProjectDialog.prototype.isLicenseAccepted = function () {
+  return $("[name='project-google-maps-license']", this.getElement()).is(":checked");
+};
 
 module.exports = EditProjectDialog;
diff --git a/frontend-js/src/main/js/map/data/Project.js b/frontend-js/src/main/js/map/data/Project.js
index da5e7eff2cd479ccc02b1ba58ab7d9b8a5ebb043..43dbd5051a0f9f81186931f70ff8a84369b2eb2c 100644
--- a/frontend-js/src/main/js/map/data/Project.js
+++ b/frontend-js/src/main/js/map/data/Project.js
@@ -72,7 +72,7 @@ Project.prototype.loadFromData = function (data) {
 /**
  *
  * @param {Project} data
- * @returns {Promise}
+ * @returns {PromiseLike}
  */
 Project.prototype.update = function (data) {
   this._update(data);
diff --git a/frontend-js/src/test/js/gui/admin/EditProjectDialog-test.js b/frontend-js/src/test/js/gui/admin/EditProjectDialog-test.js
index 0d808a00081fa7f1f4eb5c3f5215e0f6dbc08654..63d4373df80bd07df6c12f83d71b2db608de3eb7 100644
--- a/frontend-js/src/test/js/gui/admin/EditProjectDialog-test.js
+++ b/frontend-js/src/test/js/gui/admin/EditProjectDialog-test.js
@@ -96,6 +96,8 @@ describe('EditProjectDialog', function () {
         customMap: null,
         configuration: helper.getConfiguration()
       });
+      return dialog.init();
+    }).then(function () {
       return dialog.onSaveClicked();
     }).then(function (result) {
       assert.ok(project === result);
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.name=UNKNOWN DISEASE MAP&project.organism.resource=9606&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.mapCanvasType=OPEN_LAYERS&project.name=UNKNOWN DISEASE MAP&project.organism.resource=9606&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.name=UNKNOWN DISEASE MAP&project.organism.resource=9606&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.mapCanvasType=OPEN_LAYERS&project.name=UNKNOWN DISEASE MAP&project.organism.resource=9606&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID&