diff --git a/gemeinsamforschen/src/main/java/unipotsdam/gf/modules/annotation/controller/AnnotationController.java b/gemeinsamforschen/src/main/java/unipotsdam/gf/modules/annotation/controller/AnnotationController.java index 4e6bb8e9e71c4f85ec6d31c1a18591f20a09fa30..27abdc4bcc7f9abed957e39b46369e80ed5f3ba9 100644 --- a/gemeinsamforschen/src/main/java/unipotsdam/gf/modules/annotation/controller/AnnotationController.java +++ b/gemeinsamforschen/src/main/java/unipotsdam/gf/modules/annotation/controller/AnnotationController.java @@ -21,27 +21,21 @@ public class AnnotationController implements IAnnotation { uuid = UUID.randomUUID().toString(); } - // build the annotation - Annotation annotation = new Annotation(uuid, - ZonedDateTime.now().toEpochSecond(), - annotationPostRequest.getUserId(), - annotationPostRequest.getTargetId(), - annotationPostRequest.getBody(), - annotationPostRequest.getStartCharacter(), - annotationPostRequest.getEndCharacter()); - // establish connection MysqlConnect connection = new MysqlConnect(); connection.connect(); // build and execute request String request = "INSERT INTO annotations (`id`, `userId`, `targetId`, `body`, `startCharacter`, `endCharacter`) VALUES (?,?,?,?,?,?);"; - connection.issueInsertOrDeleteStatement(request, annotation.getId(), annotation.getUserId(), annotation.getTargetId(), annotation.getBody(), annotation.getStartCharacter(), annotation.getEndCharacter()); + connection.issueInsertOrDeleteStatement(request, uuid, annotationPostRequest.getUserId(), annotationPostRequest.getTargetId(), annotationPostRequest.getBody(), annotationPostRequest.getStartCharacter(), annotationPostRequest.getEndCharacter()); // close connection connection.close(); - return annotation; + // build response annotation + Annotation annotationResponse = getAnnotation(uuid); + + return annotationResponse; } diff --git a/gemeinsamforschen/src/main/webapp/assets/css/annotationStyle.css b/gemeinsamforschen/src/main/webapp/assets/css/annotationStyle.css new file mode 100644 index 0000000000000000000000000000000000000000..74ac1c7a1a6fa585af3de0ca37f55496f13f22e9 --- /dev/null +++ b/gemeinsamforschen/src/main/webapp/assets/css/annotationStyle.css @@ -0,0 +1,151 @@ +body, html { + height: 100vh; + width: 100vw; +} +ol { + padding: 0px; + margin: 0px; + list-style-type: none; +} +.content-mainpage { + display: flex; + box-sizing: border-box; + font-family: Arial; + height: 100%; + overflow-y: hidden; +} +.rightcolumn { + float: right; + width: 25%; + display: inline-block; + overflow: scroll; + /* background-color: blue; */ +} +.leftcolumn { + padding: 10px; + float: left; + width: 75%; + display: inline-block; + /* background-color: yellow; */ +} +.rightcontent { + margin: 10px; +} +.leftcontent { + max-height: 100%; + display: flex; + flex-flow: column; + /* background-color: white; */ +} +.spacing { + height: 10px; + /* background-color: orange; */ +} + +.annotation-card { + width: 100%; + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; + border-radius: 5px; + display: inline-block; + background-color: white; +} +.annotation-card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); +} +.annotation-header { + padding: 5px; + display: flex; + flex-wrap: wrap; + align-items: center; + border-top-right-radius: 5px; + border-top-left-radius: 5px; + color: white; } +.annotation-header i { + font-size: 11px; +} +.annotation-header span { + font-size: 11px; + margin-left: 5px; + margin-right: 5px; +} +.annotation-header a:link { + color: white; + text-decoration: none; +} +.annotation-header a:visited { + color: white; + text-decoration: none; +} +.annotation-header a:active { + color: white; + text-decoration: none; +} +.annotation-header a:hover { + color: #e6e6e6; + text-decoration: none; +} +.annotation-header-title { + display: flex; + flex-flow: column; + width: calc(100% - 40px); +} +.annotation-header-toggle { + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} +.annotation-body { + padding: 8px; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; +} +.annotation-body p { + margin: 0px; + font-size: 13px; +} +.overflow-hidden { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.annotation-footer { + padding: 5px; + padding-top: 0px; + text-align: right; + font-size: 9px; + color: lightgrey; + display: flex; +} +.annotation-footer span { + margin-left: 5px; +} +.annotation-footer-delete { + margin-right: 5px; + cursor: pointer; +} +.annotation-footer-date { + flex: 1 +} +.container-fluid-content { + display: flex; + flex-flow: column; + height: 100%; +} +.content-header { + display: flex; +} +.full-height { + height: 100%; +} +.leftcontent-buttons-next { + float: right; + margin: 20px; +} +.leftcontent-text { + overflow: scroll; +} + diff --git a/gemeinsamforschen/src/main/webapp/assets/js/annotationScript.js b/gemeinsamforschen/src/main/webapp/assets/js/annotationScript.js new file mode 100644 index 0000000000000000000000000000000000000000..beba2528b6e0ece7ca6ba9a2c4ea65d89d9693c1 --- /dev/null +++ b/gemeinsamforschen/src/main/webapp/assets/js/annotationScript.js @@ -0,0 +1,456 @@ +// initialize userId, userColors and targetId +var userId = randomUserId(); +var userColors = new Map(); +var userColorsDark = new Map(); +var targetId = 200; + +// declare document text +var documentText; + +/** + * This function will fire when the DOM is ready + */ +$(document).ready(function() { + + /** + * Context menu handler + */ + $.contextMenu({ + selector: '.context-menu-one', + callback: function(key, options) { + + // close context menu + window.close; + + // initialize selected body + var body = getSelectedText(); + + // if user selected something + if (body.length > 0) { + // annotationPostRequest + var request = { + userId: userId, + targetId: targetId, + body: body, + startCharacter: window.getSelection().getRangeAt(0).startOffset, + endCharacter: window.getSelection().getRangeAt(0).endOffset + }; + + console.log(request); + + createAnnotation(request, function(response) { + // display the new annotation + displayAnnotation(response); + + }); + } + + }, + items: { + "annotation": {name: "Annotation", icon: "edit"} + } + }); + + /** + * continue button + */ + $('#btnContinue').click(function () { + location.href="givefeedback.jsp?token=" + getUserTokenFromUrl(); + }); + + documentText = $('#documentText').html(); + + // fetch annotations from server on page start + getAnnotations(targetId, function (response) { + // iterate over annotations and display each + $.each(response, function (i, annotation) { + displayAnnotation(annotation); + }) + }); + +}); + +/** + * POST: Save an annotation in the database + * + * @param annotationPostRequest The post request + * @param responseHandler The response handler + */ +function createAnnotation(annotationPostRequest, responseHandler) { + var url = "http://localhost:8080/rest/annotations/"; + var json = JSON.stringify(annotationPostRequest); + $.ajax({ + url: url, + type: "POST", + data: json, + contentType: "application/json", + dataType: "json", + success: function (response) { + responseHandler(response); + } + }); +} + +/** + * PATCH: Alter an annotation in database + * + * @param id The annotation id + * @param annotationPatchRequest The patch request + * @param responseHandler The response handler + */ +function alterAnnotation(id, annotationPatchRequest, responseHandler) { + var url = "http://localhost:8080/rest/annotations/" + id; + var json = JSON.stringify(annotationPatchRequest); + $.ajax({ + url: url, + type: "PATCH", + data: json, + contentType: "application/json", + dataType: "json", + success: function (response) { + responseHandler(response); + } + }); +} + +/** + * DELETE: Delete an annotation from database + * + * @param id The annotation id + */ +function deleteAnnotation(id) { + var url = "http://localhost:8080/rest/annotations/" + id; + $.ajax({ + url: url, + type: "DELETE", + dataType: "json", + success: function (response) { + // Nothing to do + } + }); +} + +/** + * GET: Get all annotations from database for a specific target + * + * + * @param targetId The target id + * @param responseHandler The response handler + */ +function getAnnotations(targetId, responseHandler) { + var url = "http://localhost:8080/rest/annotations/target/" + targetId; + $.ajax({ + url: url, + type: "GET", + dataType: "json", + success: function (response) { + // sort the responding annotations by timestamp (DESC) + response.sort(function (a, b) { + return a.timestamp - b.timestamp; + }); + // handle the response + responseHandler(response); + } + }); +} + +/** + * Delete annotation from list + * + * @param elem The parent li element + * @param id The id of the annotation + */ +function deleteAnnotationHandler(elem, id) { + // remove annotation from list + elem.remove() + // remove highlighted text + deleteHighlightedText(); + // remove annotation from database + deleteAnnotation(id) +} + +/** + * Display annotation in the list + * + * @param annotation The annotation to be displayed + */ +function displayAnnotation(annotation) { + // fetch list of annotations + var list = $('#annotations') + + var deleteIcon = "fas fa-trash"; + var dateIcon = "fas fa-calendar"; + if (isTimestampToday(annotation.timestamp)) { + dateIcon = "fas fa-clock"; + } + + // insert annotation card + list.prepend( + $('<li>') + .attr('class', 'listelement') + .append( + $('<div>').attr('class', 'annotation-card') + .mouseenter(function () { + $(this).children('.annotation-header').css('background-color', getDarkUserColor(annotation.userId)); + }) + .mouseleave(function () { + $(this).children('.annotation-header').css('background-color', getUserColor(annotation.userId)); + }) + .append( + $('<div>').attr('class', 'annotation-header') + .css('background-color', getUserColor(annotation.userId)) + .append( + $('<div>').attr('class', 'annotation-header-title') + .append( + $('<div>').attr('class', 'overflow-hidden') + .append( + $('<i>').attr('class', 'fas fa-user') + ) + .append( + $('<span>').append(annotation.userId) + ) + ) + .append( + $('<div>').attr('class', 'overflow-hidden') + .append( + $('<i>').attr('class', 'fas fa-bookmark') + ) + .append( + $('<span>').append('title' + annotation.userId) + ) + ) + ) + .append( + $('<div>').attr('class', 'annotation-header-toggle') + .click(function () { + toggleButtonHandler($(this)); + }) + .append( + $('<i>').attr('class', 'fas fa-chevron-down') + ) + ) + ) + .append( + $('<div>').attr('class', 'annotation-body') + .append( + $('<p>').attr('class', 'overflow-hidden').append(annotation.body) + ) + ) + .append( + $('<div>').attr('class', 'annotation-footer') + .append( + function () { + if (userId == annotation.userId) { + return $('<div>').attr('class', 'annotation-footer-delete') + .append( + $('<i>').attr('class', deleteIcon) + ) + .click(function () { + deleteAnnotationHandler($(this).closest('li'), annotation.id) + }) + } + } + ) + .append( + $('<div>').attr('class', 'annotation-footer-date overflow-hidden') + .append( + $('<i>').attr('class', dateIcon) + ) + .append( + $('<span>').append(timestampToReadableTime(annotation.timestamp)) + ) + ) + + + ) + ) + .data('annotation', annotation) + .mouseenter(function () { + addHighlightedText(annotation.startCharacter, annotation.endCharacter, annotation.userId); + }) + .mouseleave(function () { + deleteHighlightedText(); + }) + .append(function () { + if ($('#annotations li').filter( ".listelement" ).length > 0) { + return $('<div>').attr('class', 'spacing') + } + }) + ); +} + +/** + * Add a highlighted text at specific position + * + * @param startCharacter The offset of the start character + * @param endCharacter The offset of the end character + * @param userId The user id + */ +function addHighlightedText(startCharacter, endCharacter, userId) { + // create <span> tag with the annotated text + var replacement = $('<span></span>').css('background-color', getUserColor(userId)).html(documentText.slice(startCharacter, endCharacter)); + + // wrap an <p> tag around the replacement, get its parent (the <p>) and ask for the html + var replacementHtml = replacement.wrap('<p/>').parent().html(); + + // insert the replacementHtml + var newDocument = documentText.slice(0, startCharacter) + replacementHtml + documentText.slice(endCharacter); + + // set new document text + $('#documentText').html(newDocument); +} + +/** + * Restore the base text + */ +function deleteHighlightedText() { + $('#documentText').html(documentText); +} + +/** + * Get the text value of the selected text + * + * @returns {string} The text + */ +function getSelectedText() { + if(window.getSelection){ + return window.getSelection().toString(); + } + else if(document.getSelection){ + return document.getSelection(); + } + else if(document.selection){ + return document.selection.createRange().text; + } +} + +/** + * Get color based on user id + * + * @param userId The id of the user + * @returns {string} The user color + */ +function getUserColor(userId) { + // insert new color if there is no userId key + if (userColors.get(userId) == null) { + generateRandomColor(userId); + } + // return the color + return userColors.get(userId); +} + +/** + * Get dark color based on user id + * + * @param userId The id of the user + * @returns {string} The dark user color + */ +function getDarkUserColor(userId) { + // insert new color if there is no userId key + if (userColorsDark.get(userId) == null) { + generateRandomColor(userId); + } + // return the color + return userColorsDark.get(userId); +} + +/** + * Generate a random color of the format 'rgb(r, g, b)' + * + * @param userId The given user id + */ +function generateRandomColor(userId) { + var r = Math.floor(Math.random()*56)+170; + var g = Math.floor(Math.random()*56)+170; + var b = Math.floor(Math.random()*56)+170; + var r_d = r - 50; + var g_d = g - 50; + var b_d = b - 50; + + var color = 'rgb(' + r + ',' + g + ',' + b + ')'; + var colorDark = 'rgb(' + r_d + ',' + g_d + ',' + b_d + ')'; + + userColors.set(userId, color); + userColorsDark.set(userId, colorDark); +} + +/** + * Calculate and build a readable timestamp from an unix timestamp + * + * @param timestamp A unix timestamp + * @returns {string} A readable timestamp + */ +function timestampToReadableTime(timestamp) { + // build Date object from timestamp + var annotationDate = new Date(timestamp); + // declare response + var responseTimestamp; + + // if annotation is from today + if (isTimestampToday(timestamp)) { + // get hours from date + var hours = annotationDate.getHours(); + // get minutes from date + var minutes = "0" + annotationDate.getMinutes(); + // get seconds from date + // var seconds = "0" + annotationDate.getSeconds(); + + // build readable timestamp + responseTimestamp = hours + ":" + minutes.substr(-2); + } + // else annotation is not from today + else { + // get date + var date = annotationDate.getDate(); + // get month + var month = annotationDate.getMonth(); + // get year + var year = annotationDate.getFullYear(); + + // build readable timestamp + responseTimestamp = date + "." + month + "." + year; + } + + return responseTimestamp; +} + +/** + * Check if given timestamp is from today + * + * @param timestamp The given timestamp in milliseconds + * @returns {boolean} Returns true if the timestamp is from today + */ +function isTimestampToday(timestamp) { + // now + var now = new Date(); + // build Date object from timestamp + var date = new Date(timestamp); + + // return true if timestamp is today + if (now.getDate() == date.getDate() && now.getMonth() == date.getMonth() && now.getFullYear() == date.getFullYear()) { + return true; + } + else { + return false; + } +} + +/** + * Toggle between the toggle button status + * + * @param element The given toggle button + */ +function toggleButtonHandler(element) { + // open and close annotation text + element.parent().siblings(".annotation-body").children("p").toggleClass("overflow-hidden"); + // toggle between up and down button + element.children("i").toggleClass("fa-chevron-down fa-chevron-up") +} + +/* + MOCKUP FUNCTIONS + */ +function randomUserId() { + return Math.floor((Math.random() * 12) + 1);; +} + diff --git a/gemeinsamforschen/src/main/webapp/assets/js/project-student.js b/gemeinsamforschen/src/main/webapp/assets/js/project-student.js new file mode 100644 index 0000000000000000000000000000000000000000..2a714319632270bda633f5c91cc11b6959a18083 --- /dev/null +++ b/gemeinsamforschen/src/main/webapp/assets/js/project-student.js @@ -0,0 +1,23 @@ +$(document).ready(function(){ + + $('.projectId').click(function () { + location.href="project-student.jsp?token="+getUserTokenFromUrl(); + }); + + $('.givefeedback').click(function () { + location.href="givefeedback.jsp?token="+getUserTokenFromUrl(); + }) + + $('.viewfeedback').click(function () { + location.href="viewfeedback.jsp?token="+getUserTokenFromUrl(); + }) + + $('.annotationview').click(function () { + location.href="annotation-document.jsp?token="+getUserTokenFromUrl(); + }) + + $('. overviewstudent').click(function () { + location.href="project-student.jsp?token="+getUserTokenFromUrl(); + }) + +}); \ No newline at end of file diff --git a/gemeinsamforschen/src/main/webapp/assets/js/utility.js b/gemeinsamforschen/src/main/webapp/assets/js/utility.js index dac28eb2de49b29e1df606bb4f4cbe2abd9f4627..bbbf0394ae1ca308e21b690477ddb39619fd9161 100644 --- a/gemeinsamforschen/src/main/webapp/assets/js/utility.js +++ b/gemeinsamforschen/src/main/webapp/assets/js/utility.js @@ -6,5 +6,6 @@ function getUserTokenFromUrl() { $_GET[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]); } return $_GET['token']; + } diff --git a/gemeinsamforschen/src/main/webapp/pages/annotation-document.jsp b/gemeinsamforschen/src/main/webapp/pages/annotation-document.jsp new file mode 100644 index 0000000000000000000000000000000000000000..3e2175d850ccb0404263c14bf6970b3eb5ca17d3 --- /dev/null +++ b/gemeinsamforschen/src/main/webapp/pages/annotation-document.jsp @@ -0,0 +1,83 @@ +<%@ taglib uri="../core/pages/gemeinsamForschen.tld" prefix="menu"%> + +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>muster-gemeinsam-forschen</title> + + <!-- css - annotationStyle --> + <link rel="stylesheet" type="text/css" href="../assets/css/annotationStyle.css"> + <!-- css - contextMenu --> + <link href="https://swisnl.github.io/jQuery-contextMenu/dist/jquery.contextMenu.css" rel="stylesheet" type="text/css" /> + <!-- css - bootstrap --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> + <!-- css - styles --> + <link rel="stylesheet" href="../assets/css/styles.css"> + <!-- css - font awesome --> + <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> + <!-- css - sidebar --> + <link rel="stylesheet" href="../assets/css/Sidebar-Menu.css"> + + <!-- js - jQuery --> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> + <!-- js - bootstrap --> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> + <!-- js - jQuery ui position --> + <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" type="text/javascript"></script> + <!-- js - contextMenu script --> + <script src="https://swisnl.github.io/jQuery-contextMenu/dist/jquery.contextMenu.js" type="text/javascript"></script> + <!-- js - utility script --> + <script src="../assets/js/utility.js"></script> + <!-- js - annotationScript --> + <script src="../assets/js/annotationScript.js"></script> + +</head> + +<body> + <div id="wrapper" class="full-height"> + <menu:menu></menu:menu> + <div class="page-content-wrapper full-height"> + <div class="container-fluid full-height"> + <div class="container-fluid-content"> + <div class="content-header"> + <h1>gemeinsam Forschen + <a href="#"> + <span class="glyphicon glyphicon-envelope" + style="font-size:27px;margin-top:-17px;margin-left:600px;"></span> + </a> + <a href="#"> + <span class="glyphicon glyphicon-cog" style="font-size:29px;margin-left:5px;margin-top:-25px;"></span> + </a> + </h1> + </div> + <div class="content-mainpage"> + <div class="leftcolumn"> + <div class="leftcontent"> + <div class="leftcontent-text context-menu-one" id="documentText"> + Style never met and those among great. At no or september sportsmen he perfectly happiness attending. Depending listening delivered off new she procuring satisfied sex existence. Person plenty answer to exeter it if. Law use assistance especially resolution cultivated did out sentiments unsatiable. Way necessary had intention happiness but september delighted his curiosity. Furniture furnished or on strangers neglected remainder engrossed. Shot what able cold new the see hold. Friendly as an betrayed formerly he. Morning because as to society behaved moments. Put ladies design mrs sister was. Play on hill felt john no gate. Am passed figure to marked in. Prosperous middletons is ye inhabiting as assistance me especially. For looking two cousins regular amongst. + Style never met and those among great. At no or september sportsmen he perfectly happiness attending. Depending listening delivered off new she procuring satisfied sex existence. Person plenty answer to exeter it if. Law use assistance especially resolution cultivated did out sentiments unsatiable. Way necessary had intention happiness but september delighted his curiosity. Furniture furnished or on strangers neglected remainder engrossed. Shot what able cold new the see hold. Friendly as an betrayed formerly he. Morning because as to society behaved moments. Put ladies design mrs sister was. Play on hill felt john no gate. Am passed figure to marked in. Prosperous middletons is ye inhabiting as assistance me especially. For looking two cousins regular amongst. + </div> + <div class="leftcontent-buttons"> + <div class="leftcontent-buttons-next"> + <button id="btnContinue" type="button" class="btn btn-secondary">Weiter</button> + </div> + </div> + </div> + </div> + <div class="rightcolumn"> + <div class="rightcontent"> + <ol id="annotations"> + </ol> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</body> + +</html> \ No newline at end of file diff --git a/gemeinsamforschen/src/main/webapp/pages/givefeedback.jsp b/gemeinsamforschen/src/main/webapp/pages/givefeedback.jsp new file mode 100644 index 0000000000000000000000000000000000000000..33d96121350b4a003d2382a9f4dc4052091e59b3 --- /dev/null +++ b/gemeinsamforschen/src/main/webapp/pages/givefeedback.jsp @@ -0,0 +1,203 @@ + +<%@ taglib uri="../core/pages/gemeinsamForschen.tld" prefix="menu"%> + +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>muster-gemeinsam-forschen</title> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> + <link rel="stylesheet" href="../assets/css/styles.css"> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> + <link rel="stylesheet" href="../assets/fonts/font-awesome.min.css"> + <link rel="stylesheet" href="../assets/css/Community-ChatComments.css"> + <link rel="stylesheet" href="../assets/css/Sidebar-Menu-1.css"> + <link rel="stylesheet" href="../assets/css/Sidebar-Menu.css"> + <script src="https://cdn.jsdelivr.net/npm/inscrybmde@1.11.3/dist/inscrybmde.min.js"></script> + <script src="https://cdn.rawgit.com/showdownjs/showdown/1.8.5/dist/showdown.min.js"></script> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/inscrybmde@1.11.3/dist/inscrybmde.min.css"> + <script src="../assets/js/utility.js"></script> + <script src="../assets/js/project-student.js"></script> +</head> + +<body> +<div id="wrapper"> + <menu:menu></menu:menu> + + <div class="page-content-wrapper"> + <div class="container-fluid"> + <h1 id="projectId"> PeerFeedback</h1> + </div> + <div align="right" class="dropdown" > + <button style= "position: absolute; right: 50px;" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"> + + <i class="glyphicon glyphicon-envelope"></i> + </button> + + <ul class="dropdown-menu"> + <li><a class="viewfeedback" role="button">Feedback A</a></li> + <li><a class="viewfeedback" role="button">Feedback B</a></li> + <li><a class="viewfeedback" role="button">Feedback C</a></li> + </ul> + + <a href="#"> + <span class="glyphicon glyphicon-cog" style="font-size:29px;margin-right:30px;margin-top:3px;"></span> + </a> + + </div> + + <div> + + </div> + <div> + <table> + <tr> + <h2> Gib dein Feedback ein!</h2> + <div class="line-spacer"></div> + <p><span> Datei zum Feedback: SelectedFile.pdf </span></p> + <p class="text-primary"><span> Kategorie: Untersuchungskonzept </span></p> + <hr /> + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="" id="defaultCheck1"> + <label class="form-check-label" for="defaultCheck1"> + Das fand ich gut + </label> + </div> + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="" id="defaultCheck2"> + <label class="form-check-label" for="defaultCheck1"> + Ich habe noch eine Frage + </label> + </div> + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="" id="defaultCheck3"> + <label class="form-check-label" for="defaultCheck1"> + Das wuerde ich anders machen + </label> + </div> + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="" id="defaultCheck4"> + <label class="form-check-label" for="defaultCheck1"> + Ich habe eine Idee + </label> + </div> + <hr /> + <div class="line-spacer"></div> + <td id="Peerfeedback" valign="top"> + + + <div style="height:100px;padding-bottom:100px;"> + <textarea id="demo1"> + Das ist ein Test! + </textarea> + </div> + + <button onclick="save()">Speichern</button> + + <p id = "output"> Output... </p> + <script> + var editor = new InscrybMDE({ + element: document.getElementById("demo1"), + spellChecker: false, + //toolbar: ["bold", "italic", "heading", "|", "quote", "table", "code", "|" , "side-by-side", "fullscreen"], + minHeight: "80px", + }); + + + editor.style = "min-height: 100px"; + + function save() { + console.log("save"); + console.log(editor.value()); + + var converter = new showdown.Converter(), + text = editor.value(), + html = converter.makeHtml(text); + + document.getElementById('output').innerHTML = html;11 + } + + </script> + + <button class="btn btn-secondary" onclick="goBack()">Zurück</button> + + <script> + function goBack() { + window.history.back(); + } + </script> + </td> + + <td id="chat"> + <div class="card"> + <div class="card-header"> + <h6 class="mb-0">Gruppen+Projekt Chat</h6> + </div> + <div class="card-body"> + <ul class="list-group"> + <li class="list-group-item"> + <div class="media"> + <div></div> + <div class="media-body"> + <div class="media" style="overflow:visible;"> + <div><img src="../assets/img/1.jpg" class="mr-3" + style="width: 25px; height:25px;"></div> + <div class="media-body" style="overflow:visible;"> + <div class="row"> + <div class="col-md-12"> + <p><a href="#">Sara Doe:</a> This guy has been going + 100+ MPH on side streets. <br> + <small class="text-muted">August 6, 2016 @ 10:35am + </small> + </p> + </div> + </div> + </div> + </div> + </div> + </div> + </li> + <li class="list-group-item"> + <div class="media"> + <div></div> + <div class="media-body"> + <div class="media" style="overflow:visible;"> + <div><img src="../assets/img/2.jpg" class="mr-3" + style="width: 25px; height:25px;"></div> + <div class="media-body" style="overflow:visible;"> + <div class="row"> + <div class="col-md-12"> + <p><a href="#">Brennan Prill:</a> This guy has been + going 100+ MPH on side streets. <br> + <small class="text-muted">August 6, 2016 @ 10:35am + </small> + </p> + </div> + </div> + </div> + </div> + </div> + </div> + </li> + </ul> + <button class="btn btn-light"> + Add Comment + </button> + </div> + </div> + </td> +</tr> +</table> +</div> +</div> +</div> + +<script src="../assets/js/jquery.min.js"></script> +<script src="../assets/bootstrap/js/bootstrap.min.js"></script> +<script src="../assets/js/Sidebar-Menu.js"></script> +</body> + +</html> \ No newline at end of file diff --git a/gemeinsamforschen/src/main/webapp/pages/project-student.jsp b/gemeinsamforschen/src/main/webapp/pages/project-student.jsp index 56d203004a59c56540948d5011d9f3089cd8908b..3d3ebf69c1b6e9658076fc7330994dccb49e05fb 100644 --- a/gemeinsamforschen/src/main/webapp/pages/project-student.jsp +++ b/gemeinsamforschen/src/main/webapp/pages/project-student.jsp @@ -1,3 +1,4 @@ +<%--suppress XmlDuplicatedId --%> <%@ taglib uri="../core/pages/gemeinsamForschen.tld" prefix="menu"%> <!DOCTYPE html> @@ -15,6 +16,9 @@ <link rel="stylesheet" href="../assets/css/Community-ChatComments.css"> <link rel="stylesheet" href="../assets/css/Sidebar-Menu-1.css"> <link rel="stylesheet" href="../assets/css/Sidebar-Menu.css"> + <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> + <script src="../assets/js/utility.js"></script> + <script src="../assets/js/project-student.js"></script> </head> <body> @@ -23,57 +27,103 @@ <div class="page-content-wrapper"> <div class="container-fluid"> - <h1 id="projectId">project1 + <h1 id="projectId">Project 1</h1> + </div> + <div align="right" class="dropdown"> + <button style= "position: absolute; right: 50px;" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"> + + <i class="glyphicon glyphicon-envelope"></i> + </button> + + <ul class="dropdown-menu"> + <li><a class="viewfeedback" role="button">Feedback A</a></li> + <li><a class="viewfeedback" role="button">Feedback B</a></li> + <li><a class="viewfeedback" role="button">Feedback C</a></li> + </ul> + <a href="#"> - <span class="glyphicon glyphicon-envelope" - style="font-size:27px;margin-top:-17px;margin-left:600px;"></span> + <span class="glyphicon glyphicon-cog" style="font-size:29px;margin-right:30px;margin-top:3px;"></span> </a> - <a href="#"> - <span class="glyphicon glyphicon-cog" style="font-size:29px;margin-left:5px;margin-top:-25px;"></span> - </a></h1> + </div> <div> <table> <tr> <td id="yourContent"> - <h1>your content guys and girls!</h1> + <h1>Feedbackable Students</h1> <!-- here will be all the content --> <table> <tr> - <td> + + <td width="100px" valign="top"> <h3>student1</h3> <img src="../assets/img/1.jpg"> <a href="#">student1@uni.de</a> <hr> <ul> - <li>Projektübersicht hochgeladen</li> - <li>Blumen ins Hausaufgabenheft geklebt</li> + + <li><a class="annotationview" role="button"> + Projektuebersicht hochgeladen + <i class="far fa-comments"></i> + </a> + </li> + <li><a class="annotationview" role="button"> + Blumen ins Hausaufgabenheft geklebt + <i class="far fa-comments"></i> + </a> + </li> + </a> </ul> </td> - <td> </td> - <td> + <td></td> + + <td width="100px" valign="top"> <h3>student2</h3> <img src="../assets/img/2.jpg"> <a href="#">student2@uni.de</a> <hr> <ul> - <li>feedback zu Herbarium im Hausaufgabenheft gegeben</li> - <li>Blumen an Vegetarier verfüttert</li> - <li>Die armen Vegetarier</li> + <li><a class="annotationview" role="button"> + Blumen an Vegetarier verfuettert + <i class="far fa-comments"></i> + </a></li> + <li><a class="annotationview" role="button"> + Literaturverzeichnis hochgeladen + <i class="far fa-comments"></i> + </a></li> + <li><a class="annotationview" role="button"> + Die armen Vegetarier + <i class="far fa-comments"></i> + </a></li> </ul> </td> - <td> </td> - <td> + <td></td> + + <td width="100px" valign="top"> <h3>student3</h3> <img src="../assets/img/3.jpg"> <a href="#">student3@uni.de</a> <hr> <ul> - <li>Viva la Floristika</li> + <li><a class="annotationview" role="button"> + "Viva la Floristika" - Titel hochgeladen + <i class="far fa-comments"></i> + </a> + </li> </ul> </td> + </tr> </table> + + <button onclick="goBack()" class="btn btn-secondary">Zurueck</button> + + <script> + function goBack() { + window.history.back(); + } + </script> + </td> <td id="chat"> <div class="card"> diff --git a/gemeinsamforschen/src/main/webapp/pages/viewfeedback.jsp b/gemeinsamforschen/src/main/webapp/pages/viewfeedback.jsp new file mode 100644 index 0000000000000000000000000000000000000000..a6314029f73d42ff095ae48d99f435b67b0acb82 --- /dev/null +++ b/gemeinsamforschen/src/main/webapp/pages/viewfeedback.jsp @@ -0,0 +1,136 @@ + +<%@ taglib uri="../core/pages/gemeinsamForschen.tld" prefix="menu"%> + +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>muster-gemeinsam-forschen</title> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> + <link rel="stylesheet" href="../assets/css/styles.css"> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> + <link rel="stylesheet" href="../assets/fonts/font-awesome.min.css"> + <link rel="stylesheet" href="../assets/css/Community-ChatComments.css"> + <link rel="stylesheet" href="../assets/css/Sidebar-Menu-1.css"> + <link rel="stylesheet" href="../assets/css/Sidebar-Menu.css"> + <script src="../assets/js/utility.js"></script> + <script src="../assets/js/project-student.js"></script> +</head> + +<body> +<div id="wrapper"> + <menu:menu></menu:menu> + + <div class="page-content-wrapper"> + <div class="container-fluid"> + <h1 id="projectId"> PeerFeedback</h1> + </div> + <div align="right" class="dropdown"> + <button style= "position: absolute; right: 50px;" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"> + + <i class="glyphicon glyphicon-envelope"></i> + </button> + + <ul class="dropdown-menu"> + <li><a class="viewfeedback" role="button">Feedback A</a></li> + <li><a class="viewfeedback" role="button">Feedback B</a></li> + <li><a class="viewfeedback" role="button">Feedback C</a></li> + </ul> + + <a href="#"> + <span class="glyphicon glyphicon-cog" style="font-size:29px;margin-right:30px;margin-top:3px;"></span> + </a> + + </div> + <div> + <table> + <tr> + <td id="Peerfeedback"> + <h2>Feedback Nachrichten von Student X</h2> + + <iframe width="90%" height="200%" src="http://rocketchat.westeurope.cloudapp.azure.com/channel/general?layout=embedded"></iframe> + + <button class="btn btn-secondary" onclick="goBack()">Zurück</button> + + <script> + function goBack() { + window.history.back(); + } + </script> + + + </td> + + <td id="chat"> + <div class="card"> + <div class="card-header"> + <h6 class="mb-0">Gruppen+Projekt Chat</h6> + </div> + <div class="card-body"> + <ul class="list-group"> + <li class="list-group-item"> + <div class="media"> + <div></div> + <div class="media-body"> + <div class="media" style="overflow:visible;"> + <div><img src="../assets/img/1.jpg" class="mr-3" + style="width: 25px; height:25px;"></div> + <div class="media-body" style="overflow:visible;"> + <div class="row"> + <div class="col-md-12"> + <p><a href="#">Sara Doe:</a> This guy has been going + 100+ MPH on side streets. <br> + <small class="text-muted">August 6, 2016 @ 10:35am + </small> + </p> + </div> + </div> + </div> + </div> + </div> + </div> + </li> + <li class="list-group-item"> + <div class="media"> + <div></div> + <div class="media-body"> + <div class="media" style="overflow:visible;"> + <div><img src="../assets/img/2.jpg" class="mr-3" + style="width: 25px; height:25px;"></div> + <div class="media-body" style="overflow:visible;"> + <div class="row"> + <div class="col-md-12"> + <p><a href="#">Brennan Prill:</a> This guy has been + going 100+ MPH on side streets. <br> + <small class="text-muted">August 6, 2016 @ 10:35am + </small> + </p> + </div> + </div> + </div> + </div> + </div> + </div> + </li> + </ul> + <button class="btn btn-light"> + Add Comment + </button> + </div> + </div> + </td> + </tr> + </table> + </div> + </div> +</div> + +<script src="../assets/js/jquery.min.js"></script> +<script src="../assets/bootstrap/js/bootstrap.min.js"></script> +<script src="../assets/js/Sidebar-Menu.js"></script> +</body> + +</html> diff --git a/gemeinsamforschen/src/scripts/dbschema/fltrail.sql b/gemeinsamforschen/src/scripts/dbschema/fltrail.sql index c92c03da44cc2448ac7b5e9d09cb274997e2459d..a930e3f00837538d9e256dc9e008add7e1c3de8d 100644 --- a/gemeinsamforschen/src/scripts/dbschema/fltrail.sql +++ b/gemeinsamforschen/src/scripts/dbschema/fltrail.sql @@ -61,6 +61,17 @@ CREATE TABLE if not exists projectuser ENGINE = InnoDB DEFAULT CHARSET = utf8; +CREATE TABLE `annotations` ( + `id` varchar(120) NOT NULL, + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `userId` int(11) DEFAULT NULL, + `targetId` int(11) DEFAULT NULL, + `body` varchar(280) DEFAULT NULL, + `startCharacter` int(11) DEFAULT NULL, + `endCharacter` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + alter table users add isStudent tinyint(1) default '1' null;