Launcher: Separate iFrame for each app, toggle invisibility between clicks

Change-Id: I540c04ea9f67c27624d69664a3b5a3057734268f
diff --git a/core/installer/welcome/launcher-tmpl/launcher.html b/core/installer/welcome/launcher-tmpl/launcher.html
index f4fed7f..9d7eb17 100644
--- a/core/installer/welcome/launcher-tmpl/launcher.html
+++ b/core/installer/welcome/launcher-tmpl/launcher.html
@@ -5,7 +5,7 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>dodo: Launcher</title>
     <link rel="stylesheet" type="text/css" href="/static/pico.2.0.6.min.css">
-    <link rel="stylesheet" type="text/css" href="/static/launcher.css">
+    <link rel="stylesheet" type="text/css" href="/static/launcher.css?v=0.0.2">
 </head>
 <body class="container-fluid">
     <div id="left-panel">
@@ -21,7 +21,7 @@
         <hr class="separator">
         <div class="app-list">
             {{range .AllAppsInfo}}
-                <div class="app-icon-tooltip" data-app-url="{{ .URL }}">
+                <div class="app-icon-tooltip" data-app-id="{{ .Id }}" data-app-url="{{ .URL }}">
                     <div class="icon">
                         {{.Icon}}
                     </div>
@@ -48,11 +48,11 @@
                                 {{ template "help-menu-template" (dict "Help" .Help "First" true) }}
                             </div>
                             <div class="modal-right" id="modal-right-help-content-{{ CleanAppName .Id }}">
-								<aside>
-									<nav>
-										{{ template "help-content-template" (dict "Help" .Help "First" true) }}
-									</nav>
-								</aside>
+                                <aside>
+                                    <nav>
+                                        {{ template "help-content-template" (dict "Help" .Help "First" true) }}
+                                    </nav>
+                                </aside>
                             </div>
                         </div>
                     </article>
@@ -61,7 +61,7 @@
         </div>
     </div>
     <div id="right-panel">
-        <iframe id="appFrame" width="100%" height="100%" frameborder="0"></iframe>
+        <iframe id="appFrame-default" class="appFrame" style="display: block;"></iframe>
     </div>
     {{ define "help-menu-template" }}
 		{{ $first := .First }}
@@ -81,6 +81,6 @@
             {{ template "help-content-template" (dict "Help" $h.Children "First" false) }}
         {{ end }}
     {{ end }}
-    <script src="/static/launcher.js"></script>
+    <script src="/static/launcher.js?v=0.0.2"></script>
 </body>
 </html>
diff --git a/core/installer/welcome/static/launcher.css b/core/installer/welcome/static/launcher.css
index aab58c6..bc716c8 100644
--- a/core/installer/welcome/static/launcher.css
+++ b/core/installer/welcome/static/launcher.css
@@ -42,8 +42,11 @@
   border-color: black;
 }
 
-#appFrame {
+.appFrame {
   border-radius: 10px;
+  width: 100%;
+  height: 100%;
+  border: 0;
 }
 
 .app-icon-tooltip {
@@ -275,7 +278,7 @@
   cursor: auto;
 }
 
-.tooltip-user button {
+#logout-button {
   margin-top: 5px !important;
   padding: 0 !important;
   border: 0 !important;
@@ -291,14 +294,4 @@
   margin: 0;
   cursor: auto;
   font-size: 19px;
-  /* align-self: flex-start; */
-}
-
-#logout-button {
-  padding: 2px !important;
-  border: 0 !important;
-  width: 100% !important;
-  color: white !important;
-  cursor: pointer !important;
-  margin-bottom: 5px !important;
 }
diff --git a/core/installer/welcome/static/launcher.js b/core/installer/welcome/static/launcher.js
index 8dd4b81..58ab6af 100644
--- a/core/installer/welcome/static/launcher.js
+++ b/core/installer/welcome/static/launcher.js
@@ -1,114 +1,136 @@
 document.addEventListener("DOMContentLoaded", function () {
-  document.querySelector('iframe').contentDocument.write("Welcome to the dodo: application launcher, think of it as your desktop environment. You can launch applications from left-hand side dock. You should setup VPN clients on your devices, so you can install applications from Application Manager and access your private network. Instructions on how to do that can be viewed by clicking <b>Help</b> button after hovering over <b>Headscale</b> icon in the dock.");
+  document.getElementById('appFrame-default').contentDocument.write("Welcome to the dodo: application launcher, think of it as your desktop environment. You can launch applications from left-hand side dock. You should setup VPN clients on your devices, so you can install applications from Application Manager and access your private network. Instructions on how to do that can be viewed by clicking <b>Help</b> button after hovering over <b>Headscale</b> icon in the dock.");
 
-    function showTooltip(obj) {
-        // obj.style.display = 'flex';
-        obj.style.visibility = 'visible';
-        obj.style.opacity = '1';
-    }
-    function hideTooltip(obj) {
-        obj.style.visibility = 'hidden';
-        obj.style.opacity = '0';
-        // obj.style.display = '';
-    }
-    const circle = document.querySelector(".user-circle");
-    const tooltipUser = document.querySelector("#tooltip-user");
+  function showTooltip(obj) {
+    obj.style.visibility = 'visible';
+    obj.style.opacity = '1';
+  }
+  function hideTooltip(obj) {
+    obj.style.visibility = 'hidden';
+    obj.style.opacity = '0';
+  }
+
+  const circle = document.querySelector(".user-circle");
+  const tooltipUser = document.querySelector("#tooltip-user");
+  [
+    ['mouseenter', () => showTooltip(tooltipUser)],
+    ['mouseleave', () => hideTooltip(tooltipUser)],
+  ].forEach(([event, listener]) => {
+    circle.addEventListener(event, listener);
+  });
+
+  const iframes = {};
+  const rightPanel = document.getElementById('right-panel');
+
+  function showIframe(appId) {
+    document.querySelectorAll('.appFrame').forEach(iframe => {
+      iframe.style.display = iframe.id === `appFrame-${appId}` ? 'block' : 'none';
+    });
+  }
+
+  function createIframe(appId, appUrl) {
+    const iframe = document.createElement('iframe');
+    iframe.id = `appFrame-${appId}`;
+    iframe.className = 'appFrame';
+    iframe.src = appUrl;
+    iframe.style.display = 'none';
+    rightPanel.appendChild(iframe);
+    iframes[appId] = iframe;
+  }
+
+  const icons = document.querySelectorAll(".app-icon-tooltip");
+  icons.forEach(function (icon) {
+    icon.addEventListener("click", function (event) {
+      event.stopPropagation();
+      const appUrl = this.getAttribute("data-app-url");
+      const appId = this.getAttribute("data-app-id");
+      if (!appUrl) {
+        const modalId = `modal-${this.querySelector('.help-button').id.replace('help-button-', '')}`;
+        openModal(document.getElementById(modalId));
+      } else {
+        if (!iframes[appId]) createIframe(appId, appUrl);
+        showIframe(appId);
+      }
+      document.querySelectorAll(".app-icon-tooltip .background-glow").forEach((e) => e.remove());
+      const glow = document.createElement('div');
+      glow.classList.add("background-glow");
+      glow.setAttribute("style", "transform: none; transform-origin: 50% 50% 0px;")
+      this.appendChild(glow);
+    });
+    const tooltip = icon.querySelector('.tooltip');
+    tooltip.addEventListener("click", function (event) {
+      event.stopPropagation();
+    });
     [
-        ['mouseenter', () => showTooltip(tooltipUser)],
-        ['mouseleave', () => hideTooltip(tooltipUser)],
+      ['mouseenter', () => showTooltip(tooltip)],
+      ['mouseleave', () => hideTooltip(tooltip)],
+      ['focus', () => showTooltip(tooltip)],
+      ['blur', () => hideTooltip(tooltip)],
     ].forEach(([event, listener]) => {
-        circle.addEventListener(event, listener);
+      icon.addEventListener(event, listener);
     });
-    const icons = document.querySelectorAll(".app-icon-tooltip");
-    icons.forEach(function (icon) {
-        icon.addEventListener("click", function (event) {
-            event.stopPropagation();
-            const appUrl = this.getAttribute("data-app-url");
- 		    if (!appUrl) {
-			  const button = this.querySelector('.help-button');
-			  const buttonId = button.getAttribute('id');
-              const modalId = 'modal-' + buttonId.substring("help-button-".length);
-              const modal = document.getElementById(modalId);
-  		      openModal(modal);
-			  return;
-			}
-            document.getElementById('appFrame').src = 'about:blank';
-            document.getElementById('appFrame').src = appUrl;
-            document.querySelectorAll(".app-icon-tooltip .background-glow").forEach((e) => e.remove());
-            const glow = document.createElement('div');
-            glow.classList.add("background-glow");
-            glow.setAttribute("style", "transform: none; transform-origin: 50% 50% 0px;")
-            this.appendChild(glow);
-        });
-        const tooltip = icon.querySelector('.tooltip');
-        tooltip.addEventListener("click", function (event) {
-            event.stopPropagation();
-        });
-        [
-            ['mouseenter', () => showTooltip(tooltip)],
-            ['mouseleave', () => hideTooltip(tooltip)],
-            ['focus', () => showTooltip(tooltip)],
-            ['blur', () => hideTooltip(tooltip)],
-        ].forEach(([event, listener]) => {
-            icon.addEventListener(event, listener);
-        });
-    });
+  });
+
   let visibleModal = undefined;
-  const openModal = function(modal) {
+  const openModal = function (modal) {
     modal.removeAttribute("close");
     modal.setAttribute("open", true);
-	visibleModal = modal;
+    visibleModal = modal;
   };
-  const closeModal = function(modal) {
+  const closeModal = function (modal) {
     modal.removeAttribute("open");
     modal.setAttribute("close", true);
-	visibleModal = undefined;
+    visibleModal = undefined;
   };
-    const helpButtons = document.querySelectorAll('.help-button');
-    helpButtons.forEach(function (button) {
-        button.addEventListener('click', function (event) {
-            event.stopPropagation();
-            const buttonId = button.getAttribute('id');
-            const modalId = 'modal-' + buttonId.substring("help-button-".length);
-            const closeHelpId = "close-help-" + buttonId.substring("help-button-".length);
-            const modal = document.getElementById(modalId);
-  		    openModal(modal);
-            const closeHelpButton = document.getElementById(closeHelpId);
-            closeHelpButton.addEventListener('click', function (event) {
-              event.stopPropagation();
-			  closeModal(modal);
-            });
-        });
+
+  const helpButtons = document.querySelectorAll('.help-button');
+  helpButtons.forEach(function (button) {
+    button.addEventListener('click', function (event) {
+      event.stopPropagation();
+      const buttonId = button.getAttribute('id');
+      const modalId = 'modal-' + buttonId.substring("help-button-".length);
+      const closeHelpId = "close-help-" + buttonId.substring("help-button-".length);
+      const modal = document.getElementById(modalId);
+      openModal(modal);
+      const closeHelpButton = document.getElementById(closeHelpId);
+      closeHelpButton.addEventListener('click', function (event) {
+        event.stopPropagation();
+        closeModal(modal);
+      });
     });
-    const modalHelpButtons = document.querySelectorAll('.title-menu');
-    modalHelpButtons.forEach(function (button) {
-        button.addEventListener('click', function (event) {
-            event.stopPropagation();
-            const helpTitle = button.getAttribute('id');
-            const helpTitleId = helpTitle.substring('title-'.length);
-            const helpContentId = 'help-content-' + helpTitleId;
-            const allContentElements = document.querySelectorAll('.help-content');
-            allContentElements.forEach(function (contentElement) {
-			    contentElement.style.display = "none";
-            });
-			modalHelpButtons.forEach(function (button) {
-			    button.removeAttribute("aria-current");
-			});
-			document.getElementById(helpContentId).style.display = 'block';
-			button.setAttribute("aria-current", "page");
-        });
-    });
-  document.addEventListener("keydown", (event) => {
-	if (event.key === "Escape" && visibleModal) {
-      closeModal(visibleModal);
-	}
   });
+
+  const modalHelpButtons = document.querySelectorAll('.title-menu');
+  modalHelpButtons.forEach(function (button) {
+    button.addEventListener('click', function (event) {
+      event.stopPropagation();
+      const helpTitle = button.getAttribute('id');
+      const helpTitleId = helpTitle.substring('title-'.length);
+      const helpContentId = 'help-content-' + helpTitleId;
+      const allContentElements = document.querySelectorAll('.help-content');
+      allContentElements.forEach(function (contentElement) {
+        contentElement.style.display = "none";
+      });
+      modalHelpButtons.forEach(function (button) {
+        button.removeAttribute("aria-current");
+      });
+      document.getElementById(helpContentId).style.display = 'block';
+      button.setAttribute("aria-current", "page");
+    });
+  });
+
+  document.addEventListener("keydown", (event) => {
+    if (event.key === "Escape" && visibleModal) {
+      closeModal(visibleModal);
+    }
+  });
+
   document.addEventListener("click", (event) => {
-	if (visibleModal === null) return;
-	const modalContent = visibleModal.querySelector("article");
-	const closeButton = visibleModal.querySelector(".close-button");
-	if (!modalContent.contains(event.target) || closeButton.contains(event.target)) {
-	  closeModal(visibleModal);
-	}
+    if (visibleModal === null) return;
+    const modalContent = visibleModal.querySelector("article");
+    const closeButton = visibleModal.querySelector(".close-button");
+    if (!modalContent.contains(event.target) || closeButton.contains(event.target)) {
+      closeModal(visibleModal);
+    }
   });
 });