commit c044ee460339e5f53d8882b766b1245ed1b1b14e
Author: Pavel Fidranský <fidransky@outlook.com>
Date:   Fri Oct 26 10:16:29 2018 +0200

    modified ShowGraphApp to use newly created Header and Navbar JS classes

diff --git a/sources/src/main/webapp/css/main.css b/sources/src/main/webapp/css/main.css
index af97c79..0bc9972 100644
--- a/sources/src/main/webapp/css/main.css
+++ b/sources/src/main/webapp/css/main.css
@@ -120,6 +120,10 @@ form input[type="checkbox"] {
 	cursor: pointer;
 }
 
+.header .username {
+	margin-right: 5px;
+}
+
 /* login popup */
 
 .header .login_popup {
diff --git a/sources/src/main/webapp/js/components/floatingPoint.js b/sources/src/main/webapp/js/components/floatingPoint.js
index befc6d3..c426af3 100644
--- a/sources/src/main/webapp/js/components/floatingPoint.js
+++ b/sources/src/main/webapp/js/components/floatingPoint.js
@@ -87,7 +87,7 @@ function FloatingPoint() {
 		var viewportPosition = app.viewportComponent.getPosition();
 
 		position.x = (bbox.left - viewportPosition.x);
-		position.y = (bbox.top - viewportPosition.y - app.headerHeight);
+		position.y = (bbox.top - viewportPosition.y - app.headerComponent.height - app.navbarComponent.height);
 
 		if (node instanceof Vertex) {
 			var edgeOffsetY = 10;
diff --git a/sources/src/main/webapp/js/components/group.js b/sources/src/main/webapp/js/components/group.js
index ef4e308..b515143 100644
--- a/sources/src/main/webapp/js/components/group.js
+++ b/sources/src/main/webapp/js/components/group.js
@@ -715,7 +715,7 @@ function Group(props) {
 			return;
 		}
 
-		switch (document.actionForm.actionMove.value) {
+		switch (document.modeForm.mode.value) {
 			case 'move':
 				this.setHighlightedWithNeighbours(!highlighted);
 				break;
diff --git a/sources/src/main/webapp/js/components/vertex.js b/sources/src/main/webapp/js/components/vertex.js
index e7fc17e..5ff4f84 100644
--- a/sources/src/main/webapp/js/components/vertex.js
+++ b/sources/src/main/webapp/js/components/vertex.js
@@ -696,7 +696,7 @@ function Vertex(props) {
 			return;
 		}
 
-		switch (document.actionForm.actionMove.value) {
+		switch (document.modeForm.mode.value) {
 			case 'move':
 				this.setHighlightedWithNeighbours(!highlighted);
 				break;
diff --git a/sources/src/main/webapp/js/showGraphApp.js b/sources/src/main/webapp/js/showGraphApp.js
index e0a3000..088d4db 100644
--- a/sources/src/main/webapp/js/showGraphApp.js
+++ b/sources/src/main/webapp/js/showGraphApp.js
@@ -21,9 +21,6 @@ function ShowGraphApp(appName, appHomeUrl) {
 	/** @prop {string} HOME_URL Application home URL. */
 	this.HOME_URL = appHomeUrl;
 
-	/** @prop {float} headerHeight Current height of the application header. */
-	this.headerHeight = getHeaderHeight();
-
 	/** @prop {Sidebar} sidebarComponent */
 	this.sidebarComponent = null;
 	/** @prop {Viewport} viewportComponent */
@@ -116,187 +113,49 @@ function ShowGraphApp(appName, appHomeUrl) {
 	 * Binds user interactions to local handler functions.
 	 */
 	function bootstrap() {
-		var self = this;
-
-		self.loader.enable();
-
-		var content = document.getElementById('content');
-
-		self.viewportComponent = new Viewport;
-		content.appendChild(self.viewportComponent.render());
-
-		self.sidebarComponent = new Sidebar;
-		content.appendChild(self.sidebarComponent.render());
-		self.sidebarComponent.minimapComponent.setViewportSize(self.viewportComponent.getSize());
-
-		self.modalWindowComponent = new SaveDiagramModalWindow;
-		content.appendChild(self.modalWindowComponent.render());
-
-		// auth events
-		const usernameLabel = document.getElementById('usernameLabel');
+		this.loader.enable();
 
-		document.addEventListener('imiger.userLoggedIn', e => {
-			usernameLabel.innerText = e.detail.user.username;
-		});
-		document.addEventListener('imiger.userLoggedOut', () => {
-			usernameLabel.innerText = '';
-		});
+		this.headerComponent = new Header;
+		this.navbarComponent = new Navbar;
+		this.viewportComponent = new Viewport;
+		this.sidebarComponent = new Sidebar;
+		this.modalWindowComponent = new SaveDiagramModalWindow;
+
+		const appElement = document.getElementById('app');
+		appElement.appendChild(this.headerComponent.render());
+		appElement.appendChild(this.navbarComponent.render());
+		appElement.appendChild(DOM.h('main', {
+			class: 'graph-content',
+			id: 'content',
+		}, [
+			this.viewportComponent.render(),
+			this.sidebarComponent.render(),
+		]));
+		appElement.appendChild(this.modalWindowComponent.render());
+
+		this.sidebarComponent.minimapComponent.setViewportSize(this.viewportComponent.getSize());
 
 		// diagram
 		document.addEventListener('imiger.diagramUpdated', e => {
 			this.diagram = new Diagram(e.detail);
 
-			document.title = this.name + ' - ' + this.diagram.name;
-			history.replaceState({} , document.title, this.homeUrl + 'graph?diagramId=' + this.diagram.id);
+			document.title = this.NAME + ' - ' + this.diagram.name;
+			history.replaceState({} , document.title, this.HOME_URL + 'graph?diagramId=' + this.diagram.id);
 		});
 
 		// context menu
-		document.body.addEventListener('mousedown', function() {
-			self.closeFloatingComponents();
+		document.body.addEventListener('mousedown', () => {
+			this.closeFloatingComponents();
 		});
 
 		// zoom
-		document.getElementById('zoomIn').addEventListener('click', function(e) {
-			self.zoom.zoomIn();
-		});
-		
-		document.getElementById('zoomOut').addEventListener('click', function(e) {
-			self.zoom.zoomOut();
-		});
-
-		document.getElementById('zoomValue').innerText = Math.round(self.zoom.scale * 100) + '%';
-		document.getElementById('graph').setAttribute('transform', 'scale(' + self.zoom.scale + ')');
-
-		// search
-		document.getElementById('searchText').addEventListener('keyup', function(e) {
-			// enter key
-			if (e.keyCode === 13) {
-				search(this.value);
-				return;
-			}
-
-			// escape key
-			if (e.keyCode === 27) {
-				resetSearch();
-				return;
-			}
-		});
-		
-		document.getElementById('search').addEventListener('click', function(e) {
-			search(document.getElementById('searchText').value);
-		});
-		
-		document.getElementById('countOfFound').addEventListener('click', resetSearch);
-		
-		function search(term) {
-			if (term.length < 2) return;
-
-			var found = 0;
-			
-			var nodeList = self.viewportComponent.getNodeList();
-			nodeList.forEach(function(node) {
-				if (!node.name.toLowerCase().includes(term.toLowerCase())) {
-					node.setFound(false);
-
-				} else {
-					node.setFound(true);
-
-					found++;
-				}
-			});
-			
-			document.getElementById('countOfFound').innerText = found;
-		}
-
-		function resetSearch(e) {
-			var nodeList = self.viewportComponent.getNodeList();
-			nodeList.forEach(function(node) {
-				node.setFound(false);
-			});
-
-			document.getElementById('searchText').value = '';
-			document.getElementById('countOfFound').innerText = 0;
-		}
-		
-		// exclude vertices with most edges button
-		document.getElementById('mostEdge').addEventListener('click', function(e) {
-			var vertexList = self.viewportComponent.getVertexList();
-			if (vertexList.length === 0) return;
-
-			var vertexWithMostEdges = vertexList.reduce(function(prev, vertex) {
-				return vertex.countEdges() > prev.countEdges() ? vertex : prev;
-			});
-			
-			if (vertexWithMostEdges !== null) {
-				vertexWithMostEdges.exclude();
-				self.sidebarComponent.excludedNodeListComponent.add(vertexWithMostEdges);
-			}
-		});
-		
-		// exclude vertices with most edges to group button
-		document.getElementById('vertexToGroup').addEventListener('click', function(e) {
-			var vertexList = self.viewportComponent.getVertexList();
-			if (vertexList.length === 0) return;
-
-			var vertexWithMostEdges = vertexList.reduce(function(prev, vertex) {
-				return vertex.countEdges() > prev.countEdges() ? vertex : prev;
-			});
-
-			var verticesWithMostEdges = vertexList.filter(function(vertex) {
-				return vertex.countEdges() === vertexWithMostEdges.countEdges();
-			});
-
-			if (verticesWithMostEdges.length > 0) {
-				var group = new Group({});
-
-				verticesWithMostEdges.forEach(function(vertex) {
-					group.addVertex(vertex);
-				});
-
-				self.nodeList.push(group);
-				self.groupList.push(group);
-
-				self.viewportComponent.addGroup(group);
-			}
-		});
-
-		// apply force-directed layout
-		var layouting = false;
-		var layoutingInterval;
-
-		document.getElementById('applyLayout').addEventListener('click', function() {
-			if (layouting) {
-				document.getElementById('applyLayoutImg').setAttribute('src', 'images/layout_off.png');
-
-				layouting = false;
-				clearInterval(layoutingInterval);
-
-			} else {
-				document.getElementById('applyLayoutImg').setAttribute('src', 'images/layout_on.png');
-
-				layouting = true;
-				layoutingInterval = window.setInterval(self.viewportComponent.forceDirected.run, 10);
-			}
-		});
-		
-		// save as PNG button
-		document.getElementById('btnSaveDiagram').addEventListener('click', function(e) {
-			saveSvgAsPng(document.getElementById('svg1'), 'diagram.png', {
-				scale: 1,
-			});
-		});
-
-		// save to database button
-		document.getElementById('btnSaveDiagramToDatabase').addEventListener('click', function(e) {
-			self.modalWindowComponent.open();
-		});
+		document.getElementById('zoomValue').innerText = Math.round(this.zoom.scale * 100) + '%';
+		document.getElementById('graph').setAttribute('transform', 'scale(' + this.zoom.scale + ')');
 
 		// window resize
-		window.addEventListener('resize', function(e) {
-			self.headerHeight = getHeaderHeight();
-			self.redrawEdges();
-
-			self.sidebarComponent.minimapComponent.setViewportSize(self.viewportComponent.getSize());
+		window.addEventListener('resize', e => {
+			this.redrawEdges();
+			this.sidebarComponent.minimapComponent.setViewportSize(this.viewportComponent.getSize());
 		});
 	}
 
@@ -349,11 +208,4 @@ function ShowGraphApp(appName, appHomeUrl) {
 			window.location.replace('./');
 		}
 	}
-
-	/**
-	 * @returns {integer} Height of the header.
-	 */
-	function getHeaderHeight() {
-		return document.getElementById('header').offsetHeight;
-	}
 }
diff --git a/sources/src/main/webapp/showGraph.jsp b/sources/src/main/webapp/showGraph.jsp
index 8e530a4..6e16110 100644
--- a/sources/src/main/webapp/showGraph.jsp
+++ b/sources/src/main/webapp/showGraph.jsp
@@ -1,7 +1,8 @@
 <%@page contentType="text/html" pageEncoding="UTF-8"%>
 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 
-<c:set var="HOME_URL" value="${initParam.HOME_URL}"/>
+<c:set var="APP_NAME" value="IMiGEr"/>
+<c:set var="APP_HOME_URL" value="${initParam.HOME_URL}"/>
 <c:set var="isLoggedIn" value="${sessionScope.isLoggedIn}"/>
 <c:set var="user" value="${sessionScope.user}"/>
 
@@ -30,8 +31,10 @@
 		<script src="js/components/floatingPoint.js"></script>
 		<script src="js/components/group.js"></script>
 		<script src="js/components/groupVertexList.js"></script>
+		<script src="js/components/header.js"></script>
 		<script src="js/components/loginPopup.js"></script>
 		<script src="js/components/minimap.js"></script>
+		<script src="js/components/navbar.js"></script>
 		<script src="js/components/registerPopup.js"></script>
 		<script src="js/components/saveDiagramModalWindow.js"></script>
 		<script src="js/components/sidebar.js"></script>
@@ -62,7 +65,6 @@
 		<script src="js/valueObjects/diagram.js"></script>
 		<script src="js/valueObjects/dimensions.js"></script>
 
-		<script src="js/userMenu.js"></script>
 		<script src="js/markSymbol.js"></script>
 		<script src="js/constants.js"></script>
 		<script src="js/showGraphApp.js"></script>
@@ -71,110 +73,7 @@
 	</head>
 
 	<body class="${isLoggedIn ? 'loggedIn' : 'loggedOut'}">
-		<div class="wrapper">
-			<header class="header" id="header">
-				<img src="images/logo.png" class="header-logo" alt="logo of University of West Bohemia" title="University of West Bohemia">
-
-				<h2 class="header-title">Interactive Multimodal Graph Explorer</h2>
-
-				<%@ include file="userMenu.jsp" %>
-
-				<nav class="navbar" id="navigation">
-					<ul>
-						<li>
-							<button class="btn zoom" id="zoomOut" title="zoom-"><img src="images/zoom_out.png" alt="zoom-"></button>
-							<span class="zoom-value" id="zoomValue"></span>
-							<button class="btn zoom" id="zoomIn" title="zoom+"><img src="images/zoom_in.png" alt="zoom+"></button>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<input class="search-text" id="searchText" type="text" placeholder="Search components...">
-							<button class="btn search" id="search"><img src="images/search.png" title="search" alt="search"></button>
-							<span class="search-count" id="countOfFound" title="Count of components found">0</span>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<form name="actionForm">
-								<label for="move">
-									<input type="radio" name="actionMove" value="move" id="move" checked>
-									move
-									<img class="navbar-image" src="images/move.png" alt="move">
-								</label>
-								<label for="remove">
-									<input type="radio" name="actionMove" value="exclude" id="remove">
-									exclude
-									<img class="navbar-image" src="images/remove2.png" alt="remove">
-								</label>
-							</form>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<button id="mostEdge" class="btn exclude-separately" title="Exclude components with the most count of edges separately.">
-								<img src="images/excludeSeparately.png" alt="excludeSeparately">
-							</button>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<button id="vertexToGroup" class="btn exclude-to-group" title="Exclude components with the most count of edges to group.">
-								<img src="images/package.png" alt="Exclude components to group">
-							</button>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<a href="${HOME_URL}" class="btn btn-block back-to-upload" id="view_back_to_upload" title="Back to upload"></a>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<button class="btn" id="applyLayout" title="Apply layout to current graph">
-								<img src="images/layout_off.png" id="applyLayoutImg" alt="Apply layout to current graph.">
-							</button>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<button class="btn save-diagram" id="btnSaveDiagram" title="Save diagram as PNG">
-								<img src="images/png_save.png" id="applyLayoutImg" alt="Save diagram as PNG.">
-							</button>
-						</li>
-						<li class="loggedInOnly">
-							<hr class="navbar-separator">
-						</li>
-						<li class="loggedInOnly">
-							<button class="btn save-diagram" id="btnSaveDiagramToDatabase" title="Save diagram">
-								<img src="images/icon_save.png" id="applyLayoutImg" alt="Save diagram">
-							</button>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<a href="${HOME_URL}graph?diagramId=${param.diagramId}" class="btn btn-block view-refresh-diagram" id="view_refresh_diagram" title="Refresh diagram"></a>
-						</li>
-						<li>
-							<hr class="navbar-separator">
-						</li>
-						<li>
-							<button class="btn btn-block view-refresh-reset-diagram" id="view_refresh_reset_diagram" title="Refresh diagram - reset position"></button>
-						</li>
-					</ul>
-				</nav>
-			</header>
-
-			<main class="graph-content" id="content"></main>
-		</div>
+		<div id="app"></div>
 
 		<div class="loader" id="loader">
 			<div class="loader-content" id="spinLoader">
@@ -183,13 +82,21 @@
 		</div>
 
 		<script>
-		const app = new ShowGraphApp('${APP_NAME}', '${APP_HOME_URL}');
+			const app = new ShowGraphApp('${APP_NAME}', '${APP_HOME_URL}');
+
+			document.addEventListener('DOMContentLoaded', () => {
+				let loaderFn = app.diagramLoader('${param.diagramId}');
 
-		document.addEventListener('DOMContentLoaded', () => {
-			var loaderFn = app.diagramLoader('${param.diagramId}');
+				app.run(loaderFn);
 
-			app.run(loaderFn);
-		});
+				// user is logged in
+				if ('${user}' !== '') {
+					document.dispatchEvent(new LoggedInEvent({
+						id: '${user.id}',
+						username: '${user.username}',
+					}));
+				}
+			});
 		</script>
 	</body>
 </html>
diff --git a/sources/src/main/webapp/uploadFiles.jsp b/sources/src/main/webapp/uploadFiles.jsp
index c83c327..8962653 100644
--- a/sources/src/main/webapp/uploadFiles.jsp
+++ b/sources/src/main/webapp/uploadFiles.jsp
@@ -41,7 +41,7 @@
 			<h2 class="header-title">Interactive Multimodal Graph Explorer</h2>
 
 			<div class="user-menu loggedInOnly">
-				<span id="usernameLabel">${user.username}</span>
+				<span class="username" id="usernameLabel">${user.username}</span>
 				<button class="button" id="logoutButton">Log out</button>
 			</div>
 
