commit 35ab10b265fc8629cdb2eaa3b2bb1ffe692b02d4
Author: Pavel Fidranský <fidransky@outlook.com>
Date:   Sat Feb 9 17:40:23 2019 +0100

    fix #20: diagram can be downloaded as raw JSON

diff --git a/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetDBDiagramData.java b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetDBDiagramData.java
new file mode 100644
index 0000000..5d7eea5
--- /dev/null
+++ b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetDBDiagramData.java
@@ -0,0 +1,50 @@
+package cz.zcu.kiv.offscreen.servlets.api;
+
+import cz.zcu.kiv.offscreen.servlets.BaseServlet;
+import cz.zcu.kiv.offscreen.user.DB;
+import cz.zcu.kiv.offscreen.user.Diagram;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * This class is used for loading diagram's graph JSON from database.
+ */
+public class GetDBDiagramData extends BaseServlet {
+
+    private static final Logger logger = LogManager.getLogger();
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        logger.debug("Processing request");
+        String diagramId = request.getParameter("id");
+
+        if (StringUtils.isBlank(diagramId)) {
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+            logger.debug("Diagram id is empty");
+            return;
+        }
+
+        DB db = new DB(getServletContext());
+        Diagram diagram = new Diagram(db, Integer.parseInt(diagramId));
+
+        if (!diagram.isPublic() && (!isLoggedIn(request) || (isLoggedIn(request) && diagram.getUserId() != getUserId(request)))) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            logger.debug("User is unauthorized");
+            return;
+        }
+
+        String json = diagram.getDiagram().get("graph_json");
+
+        response.setContentType("application/json");
+        response.setCharacterEncoding("UTF-8");
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.getWriter().write(json);
+        response.getWriter().flush();
+        logger.debug("Response OK");
+    }
+}
diff --git a/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetPrivateDiagrams.java b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetPrivateDiagrams.java
index 2add421..8ac296d 100644
--- a/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetPrivateDiagrams.java
+++ b/sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetPrivateDiagrams.java
@@ -36,11 +36,11 @@ public class GetPrivateDiagrams extends BaseServlet {
 
         JsonArray jsonArray = new JsonArray();
         for (Map<String, String> userDiagram : userDiagramList) {
-
             JsonObject jsonObject = new JsonObject();
             jsonObject.addProperty("id", userDiagram.get("id"));
             jsonObject.addProperty("name", userDiagram.get("name"));
-
+            jsonObject.addProperty("created", userDiagram.get("created"));
+            jsonObject.addProperty("last_update", userDiagram.get("last_update"));
             jsonArray.add(jsonObject);
         }
 
diff --git a/sources/imiger-core/src/main/webapp/css/common.css b/sources/imiger-core/src/main/webapp/css/common.css
index 1f99ce9..5bd8007 100644
--- a/sources/imiger-core/src/main/webapp/css/common.css
+++ b/sources/imiger-core/src/main/webapp/css/common.css
@@ -1,9 +1,8 @@
 body {
 	font-family: 'Arial', sans-serif;
-    font-size: 0.8em;
+	font-size: 0.8em;
 	margin: 0;
-    background-color: #e8f4ff;
-    overflow: hidden;
+	background-color: #e8f4ff;
 }
 
 ul {
diff --git a/sources/imiger-core/src/main/webapp/css/show-graph.css b/sources/imiger-core/src/main/webapp/css/show-graph.css
index 1b4a0db..1e58e3a 100644
--- a/sources/imiger-core/src/main/webapp/css/show-graph.css
+++ b/sources/imiger-core/src/main/webapp/css/show-graph.css
@@ -1,7 +1,11 @@
+body {
+	overflow: hidden;
+}
+
 .graph-content {
 	display: flex;
 	height: calc(100vh - 60px - 43px);
-    background-color: #fff;
+	background-color: #fff;
 }
 
 .archetype-icon {
diff --git a/sources/imiger-core/src/main/webapp/css/upload-files.css b/sources/imiger-core/src/main/webapp/css/upload-files.css
index 2e635c9..440a42e 100644
--- a/sources/imiger-core/src/main/webapp/css/upload-files.css
+++ b/sources/imiger-core/src/main/webapp/css/upload-files.css
@@ -1,35 +1,91 @@
-.upload-form {
-    width: 200px;
-    margin: 20px auto;
-    padding: 10px;
-    background-color: #CFEAFE;
-    box-shadow: 3px 3px 10px #888;
+.content {
+	max-width: 480px;
+	margin-top: 45px;
+	margin-left: auto;
+	margin-right: auto;
+	line-height: 1.8;
 }
 
-.upload-form button[type="submit"] {
+.section {
+	margin-bottom: 45px;
+	padding-left: 30px;
+	padding-right: 30px;
+}
+
+.section h2 {
+	font-size: 1.4em;
+	font-weight: normal;
+	color: #0b548a;
+	margin-top: 15px;
+	margin-bottom: 30px;
+	border-bottom: 1px solid;
+}
+
+.diagram-form button[type="submit"] {
 	display: block;
 	width: 100%;
 }
+.diagram-list-item {
+	position: relative;
+}
+
+.diagram-list-item:not(:last-child) {
+	margin-bottom: 15px;
+}
+
+.diagram-list-item a {
+	display: block;
+	color: #000;
+	text-decoration: none;
+}
+
+.diagram-details {
+	color: gray;
+	font-size: 0.8em;
+	margin-top: 0;
+	margin-bottom: 0;
+}
+
+.diagram-details dt,
+.diagram-details dd {
+	display: inline;
+}
+
+.diagram-details dd {
+	margin-left: 0;
+	margin-right: 15px;
+}
+
+.diagram-button-group {
+	display: none;
+	position: absolute;
+	top: 5px;
+	right: 0;
+}
+
+.diagram-list-item:focus .diagram-button-group,
+.diagram-list-item:hover .diagram-button-group {
+	display: block;
+}
 
-.diagrams-menu {
-	width: 200px;
-    margin: 20px auto;
-	padding: 10px;
-	background-color: #CFEAFE;
-	box-shadow: 3px 3px 10px #888;
+.diagram-button-group li {
+	display: inline-block;
 }
 
-.diagrams-menu li {
+.diagram-button-group .button {
+	width: 20px;
 	height: 20px;
+	padding: 0;
+	background: transparent;
+	border: 0;
+	cursor: pointer;
 }
 
-.diagrams-menu li button {
-	float: right;
-    width: 20px;
-    height: 20px;
-    padding: 0;
+.diagram-button-group .delete-diagram-button {
+	padding: 1px;
+	vertical-align: 1px;
 }
 
-.diagrams-menu li img {
+.diagram-button-group .button img {
 	max-width: 100%;
 }
diff --git a/sources/imiger-core/src/main/webapp/js/uploadFilesApp.js b/sources/imiger-core/src/main/webapp/js/uploadFilesApp.js
index a70fede..f005a05 100644
--- a/sources/imiger-core/src/main/webapp/js/uploadFilesApp.js
+++ b/sources/imiger-core/src/main/webapp/js/uploadFilesApp.js
@@ -36,7 +36,7 @@ class UploadFilesApp extends App {
 
 		// private diagrams list
 		const privateDiagramList = document.getElementById('privateDiagramList');
-		privateDiagramList.querySelectorAll('.remove-diagram-button').forEach(button => {
+		privateDiagramList.querySelectorAll('.delete-diagram-button').forEach(button => {
 			button.addEventListener('click', this._removeDiagram);
 		});
 
@@ -79,31 +79,64 @@ class UploadFilesApp extends App {
 			const data = await AJAX.getJSON(Constants.API.getPrivateDiagrams);
 
 			data.forEach(diagram => {
-				privateDiagramList.appendChild(DOM.h('li', {}, [
+				privateDiagramList.appendChild(DOM.h('li', {
+					class: 'diagram-list-item',
+				}, [
 					DOM.h('a', {
 						href: app.homeUrl + 'graph?diagramId=' + diagram.id,
 						innerText: diagram.name,
 					}),
-					DOM.h('a', {
-						href: app.homeUrl + 'api/get-diagram-data?id=' + diagram.id,
-						download: diagram.name + '.json',
-						class: 'button download-diagram-button',
+					DOM.h('dl', {
+						class: 'diagram-details',
 					}, [
-						DOM.h('img', {
-							src: 'images/button_cancel.png',
-							alt: 'stáhnout',
+						DOM.h('dt', {
+							innerText: 'created:',
+						}),
+						DOM.h('dd', {}, [
+							DOM.h('time', {
+								innerText: diagram.created,
+							}),
+						]),
+						DOM.h('dt', {
+							innerText: 'updated:',
 						}),
+						DOM.h('dd', {}, [
+							DOM.h('time', {
+								innerText: diagram.last_update,
+							}),
+						]),
 					]),
-					DOM.h('button', {
-						class: 'button remove-diagram-button',
-						'data-id': diagram.id,
-						'data-name': diagram.name,
-						onClick: this._removeDiagram,
+					DOM.h('ul', {
+						class: 'diagram-button-group',
 					}, [
-						DOM.h('img', {
-							src: 'images/button_cancel.png',
-							alt: 'odstranit',
-						}),
+						DOM.h('li', {}, [
+							DOM.h('a', {
+								href: app.homeUrl + 'api/get-diagram-data?id=' + diagram.id,
+								download: diagram.name + '.json',
+								title: 'download diagram as raw JSON',
+								class: 'button download-diagram-button',
+							}, [
+								DOM.h('img', {
+									src: 'images/icomoon/download3.svg',
+									alt: 'download diagram icon',
+								}),
+							]),
+						]),
+						DOM.t(' '),
+						DOM.h('li', {}, [
+							DOM.h('button', {
+								class: 'button delete-diagram-button',
+								title: 'delete diagram',
+								'data-id': diagram.id,
+								'data-name': diagram.name,
+								onClick: this._removeDiagram,
+							}, [
+								DOM.h('img', {
+									src: 'images/icomoon/cross.svg',
+									alt: 'delete diagram icon',
+								}),
+							]),
+						]),
 					]),
 				]));
 			});
diff --git a/sources/imiger-core/src/main/webapp/uploadFiles.jsp b/sources/imiger-core/src/main/webapp/uploadFiles.jsp
index eb64944..08e8524 100644
--- a/sources/imiger-core/src/main/webapp/uploadFiles.jsp
+++ b/sources/imiger-core/src/main/webapp/uploadFiles.jsp
@@ -43,7 +43,7 @@
 		<header class="header" id="header">
 			<img src="images/logo_cs.svg" class="header-logo" alt="logo of University of West Bohemia" title="University of West Bohemia">
 
-			<h2 class="header-title">Interactive Multimodal Graph Explorer</h2>
+			<h1 class="header-title">Interactive Multimodal Graph Explorer</h1>
 
 			<div class="user-menu loggedInOnly">
 				<span class="username" id="usernameLabel">${user.username}</span>
@@ -56,15 +56,15 @@
 			</div>
 		</header>
 
-		<main>
-			<div class="upload-form">
-				<h3>New diagram</h3>
+		<main class="content">
+			<section class="section">
+				<h2>New diagram</h2>
 
 				<c:if test="${not empty errorMessage}">
 					<p class="alert">${errorMessage}</p>
 				</c:if>
 
-				<form method="post" enctype="multipart/form-data">
+				<form method="post" enctype="multipart/form-data" class="diagram-form">
 					<div class="form-field">
 						<label for="file">Select JSON data file:</label><br>
 						<input type="file" name="file" id="file">
@@ -80,38 +80,68 @@
 
 					<button id="btnLoad" type="submit">Start visualization</button>
 				</form>
-			</div>
+			</section>
 
-			<div class="diagrams-menu loggedInOnly">
-				<h3>My diagrams</h3>
+			<section class="section loggedInOnly">
+				<h2>My diagrams</h2>
 
-				<ul id="privateDiagramList">
+				<ul class="diagram-list" id="privateDiagramList">
 					<c:forEach items="${diagramsPrivate}" var="diagram">
-						<li>
+						<li class="diagram-list-item">
 							<a href="${APP_HOME_URL}graph?diagramId=${diagram.id}">${diagram.name}</a>
 
-							<a href="${APP_HOME_URL}api/get-diagram-data?id=${diagram.id}" download="${diagram.name}.json" class="button download-diagram-button">
-								<img src="images/button_cancel.png" alt="stáhnout">
-							</a>
-							<button class="button remove-diagram-button" data-id="${diagram.id}" data-name="${diagram.name}">
-								<img src="images/button_cancel.png" alt="odstranit">
-							</button>
+							<dl class="diagram-details">
+								<dt>created:</dt>
+								<dd><time>${diagram.created}</time></dd>
+
+								<dt>updated:</dt>
+								<dd><time>${diagram.last_update}</time></dd>
+							</dl>
+
+							<ul class="diagram-button-group">
+								<li>
+									<a href="${APP_HOME_URL}api/get-diagram-data?id=${diagram.id}" download="${diagram.name}.json" title="download diagram as raw JSON" class="button download-diagram-button">
+										<img src="images/icomoon/download3.svg" alt="download diagram icon">
+									</a>
+								</li>
+								<li>
+									<button class="button delete-diagram-button" title="delete diagram" data-id="${diagram.id}" data-name="${diagram.name}">
+										<img src="images/icomoon/cross.svg" alt="delete diagram icon">
+									</button>
+								</li>
+							</ul>
 						</li>
 					</c:forEach>
 				</ul>
-			</div>
+			</section>
 
-			<div class="diagrams-menu">
-				<h3>Public diagrams</h3>
+			<section class="section">
+				<h2>Public diagrams</h2>
 
-				<ul id="publicDiagramList">
+				<ul class="diagram-list" id="publicDiagramList">
 					<c:forEach items="${diagramsPublic}" var="diagram">
-						<li>
+						<li class="diagram-list-item">
 							<a href="${APP_HOME_URL}graph?diagramId=${diagram.id}">${diagram.name}</a>
+
+							<dl class="diagram-details">
+								<dt>created:</dt>
+								<dd><time>${diagram.created}</time></dd>
+
+								<dt>updated:</dt>
+								<dd><time>${diagram.last_update}</time></dd>
+							</dl>
+
+							<ul class="diagram-button-group">
+								<li>
+									<a href="${APP_HOME_URL}api/get-diagram-data?id=${diagram.id}" download="${diagram.name}.json" title="download diagram as raw JSON" class="button download-diagram-button">
+										<img src="images/icomoon/download3.svg" alt="download diagram icon">
+									</a>
+								</li>
+							</ul>
 						</li>
 					</c:forEach>
 				</ul>
-			</div>
+			</section>
 		</main>
 
 		<script type="module">
diff --git a/sources/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetDBDiagramData.java b/sources/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetDBDiagramData.java
deleted file mode 100644
index 5d7eea5..0000000
--- a/sources/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetDBDiagramData.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package cz.zcu.kiv.offscreen.servlets.api;
-
-import cz.zcu.kiv.offscreen.servlets.BaseServlet;
-import cz.zcu.kiv.offscreen.user.DB;
-import cz.zcu.kiv.offscreen.user.Diagram;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * This class is used for loading diagram's graph JSON from database.
- */
-public class GetDBDiagramData extends BaseServlet {
-
-    private static final Logger logger = LogManager.getLogger();
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
-        logger.debug("Processing request");
-        String diagramId = request.getParameter("id");
-
-        if (StringUtils.isBlank(diagramId)) {
-            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
-            logger.debug("Diagram id is empty");
-            return;
-        }
-
-        DB db = new DB(getServletContext());
-        Diagram diagram = new Diagram(db, Integer.parseInt(diagramId));
-
-        if (!diagram.isPublic() && (!isLoggedIn(request) || (isLoggedIn(request) && diagram.getUserId() != getUserId(request)))) {
-            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-            logger.debug("User is unauthorized");
-            return;
-        }
-
-        String json = diagram.getDiagram().get("graph_json");
-
-        response.setContentType("application/json");
-        response.setCharacterEncoding("UTF-8");
-        response.setStatus(HttpServletResponse.SC_OK);
-        response.getWriter().write(json);
-        response.getWriter().flush();
-        logger.debug("Response OK");
-    }
-}
