From 23441dab2e4c4005c1a1a9eddc0d064a598848e7 Mon Sep 17 00:00:00 2001 From: Patrick Jentsch Date: Fri, 23 Oct 2020 08:51:46 +0200 Subject: [PATCH 01/31] intermediate --- .../css/materialize.fix.sidenav-fixed.css | 12 + .../css/materialize.fix.sticky-footer.css | 13 + web/app/static/css/nopaque.css | 16 - web/app/static/js/nopaque.js | 185 +++---- web/app/templates/_variables.html.j2 | 19 + web/app/templates/auth/login.html.j2 | 70 +-- web/app/templates/auth/register.html.j2 | 60 ++- web/app/templates/auth/reset_password.html.j2 | 38 +- .../auth/reset_password_request.html.j2 | 35 +- web/app/templates/auth/unconfirmed.html.j2 | 35 +- web/app/templates/main/about_and_faq.html.j2 | 508 +++++++++--------- web/app/templates/main/dashboard.html.j2 | 265 ++++----- web/app/templates/main/index.html.j2 | 11 +- web/app/templates/main/news.html.j2 | 23 +- web/app/templates/main/privacy_policy.html.j2 | 285 +++++----- web/app/templates/main/terms_of_use.html.j2 | 198 +++---- web/app/templates/materialize/base.html.j2 | 35 ++ web/app/templates/materialize/wtf.html.j2 | 101 ++++ web/app/templates/nopaque.html.j2 | 489 +++++++---------- 19 files changed, 1249 insertions(+), 1149 deletions(-) create mode 100644 web/app/static/css/materialize.fix.sidenav-fixed.css create mode 100644 web/app/static/css/materialize.fix.sticky-footer.css create mode 100644 web/app/templates/_variables.html.j2 create mode 100644 web/app/templates/materialize/base.html.j2 create mode 100644 web/app/templates/materialize/wtf.html.j2 diff --git a/web/app/static/css/materialize.fix.sidenav-fixed.css b/web/app/static/css/materialize.fix.sidenav-fixed.css new file mode 100644 index 00000000..7cf789da --- /dev/null +++ b/web/app/static/css/materialize.fix.sidenav-fixed.css @@ -0,0 +1,12 @@ +/* + * The sidenav-fixed class is used which causes the sidenav to be fixed and open + * on large screens and hides to the regular functionality on smaller screens. + * In order to prevent the sidenav to overlap the content, the content (in our + * case header, main and footer) gets an offset equal to the width of the + * sidenav. + */ +@media only screen and (min-width : 993px) { + header, main, footer {padding-left: 300px;} + .modal:not(.bottom-sheet) {left: 300px;} + .navbar-fixed > nav {width: calc(100% - 300px)} +} diff --git a/web/app/static/css/materialize.fix.sticky-footer.css b/web/app/static/css/materialize.fix.sticky-footer.css new file mode 100644 index 00000000..49b8f5b8 --- /dev/null +++ b/web/app/static/css/materialize.fix.sticky-footer.css @@ -0,0 +1,13 @@ +/* + * Force the footer to always stay on the bottom of the page regardless of how + * little content is on the page. + */ +body { + display: flex; + min-height: 100vh; + flex-direction: column; +} + +main { + flex: 1 0 auto; +} diff --git a/web/app/static/css/nopaque.css b/web/app/static/css/nopaque.css index 66421a7d..f97cede4 100644 --- a/web/app/static/css/nopaque.css +++ b/web/app/static/css/nopaque.css @@ -1,19 +1,3 @@ -/* - * ### Start sticky footer ### - * Force the footer to always stay on the bottom of the page regardless of how - * little content is on the page. -*/ -body { - display: flex; - min-height: 100vh; - flex-direction: column; -} - -main { - flex: 1 0 auto; -} -/* ### End sticky footer ### */ - /* add custom bold class */ .bold { font-weight: bold; diff --git a/web/app/static/js/nopaque.js b/web/app/static/js/nopaque.js index 35ceac83..b006ec25 100644 --- a/web/app/static/js/nopaque.js +++ b/web/app/static/js/nopaque.js @@ -4,12 +4,8 @@ */ var nopaque = {}; -// nopaque ressources -nopaque.socket = undefined; - // User data nopaque.user = {}; -nopaque.user.isAuthenticated = undefined; nopaque.user.settings = {}; nopaque.user.settings.darkMode = undefined; nopaque.corporaSubscribers = []; @@ -25,81 +21,76 @@ nopaque.foreignCorporaSubscribers = []; nopaque.foreignJobsSubscribers = []; nopaque.foreignQueryResultsSubscribers = []; -nopaque.flashedMessages = undefined; - // nopaque functions -nopaque.socket = {}; -nopaque.socket.init = function() { - nopaque.socket = io({transports: ['websocket']}); - // Add event handlers - nopaque.socket.on("user_data_stream_init", function(msg) { - nopaque.user = JSON.parse(msg); - for (let subscriber of nopaque.corporaSubscribers) { - subscriber._init(nopaque.user.corpora); - } - for (let subscriber of nopaque.jobsSubscribers) { - subscriber._init(nopaque.user.jobs); - } - for (let subscriber of nopaque.queryResultsSubscribers) { - subscriber._init(nopaque.user.query_results); - } - }); +nopaque.socket = io({transports: ['websocket']}); +// Add event handlers +nopaque.socket.on("user_data_stream_init", function(msg) { + nopaque.user = JSON.parse(msg); + for (let subscriber of nopaque.corporaSubscribers) { + subscriber._init(nopaque.user.corpora); + } + for (let subscriber of nopaque.jobsSubscribers) { + subscriber._init(nopaque.user.jobs); + } + for (let subscriber of nopaque.queryResultsSubscribers) { + subscriber._init(nopaque.user.query_results); + } +}); - nopaque.socket.on("user_data_stream_update", function(msg) { - var patch; +nopaque.socket.on("user_data_stream_update", function(msg) { + var patch; - patch = JSON.parse(msg); - nopaque.user = jsonpatch.apply_patch(nopaque.user, patch); - corpora_patch = patch.filter(operation => operation.path.startsWith("/corpora")); - jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs")); - query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results")); - for (let subscriber of nopaque.corporaSubscribers) { - subscriber._update(corpora_patch); - } - for (let subscriber of nopaque.jobsSubscribers) { - subscriber._update(jobs_patch); - } - for (let subscriber of nopaque.queryResultsSubscribers) { - subscriber._update(query_results_patch); - } - if (["all", "end"].includes(nopaque.user.settings.job_status_site_notifications)) { - for (operation of jobs_patch) { - /* "/jobs/{jobId}/..." -> ["{jobId}", ...] */ - pathArray = operation.path.split("/").slice(2); - if (operation.op === "replace" && pathArray[1] === "status") { - if (nopaque.user.settings.job_status_site_notifications === "end" && !["complete", "failed"].includes(operation.value)) {continue;} - nopaque.flash(`[${nopaque.user.jobs[pathArray[0]].title}] New status: ${operation.value}`, "job"); - } + patch = JSON.parse(msg); + nopaque.user = jsonpatch.apply_patch(nopaque.user, patch); + corpora_patch = patch.filter(operation => operation.path.startsWith("/corpora")); + jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs")); + query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results")); + for (let subscriber of nopaque.corporaSubscribers) { + subscriber._update(corpora_patch); + } + for (let subscriber of nopaque.jobsSubscribers) { + subscriber._update(jobs_patch); + } + for (let subscriber of nopaque.queryResultsSubscribers) { + subscriber._update(query_results_patch); + } + if (["all", "end"].includes(nopaque.user.settings.job_status_site_notifications)) { + for (operation of jobs_patch) { + /* "/jobs/{jobId}/..." -> ["{jobId}", ...] */ + pathArray = operation.path.split("/").slice(2); + if (operation.op === "replace" && pathArray[1] === "status") { + if (nopaque.user.settings.job_status_site_notifications === "end" && !["complete", "failed"].includes(operation.value)) {continue;} + nopaque.flash(`[${nopaque.user.jobs[pathArray[0]].title}] New status: ${operation.value}`, "job"); } } - }); + } +}); - nopaque.socket.on("foreign_user_data_stream_init", function(msg) { - nopaque.foreignUser = JSON.parse(msg); - for (let subscriber of nopaque.foreignCorporaSubscribers) { - subscriber._init(nopaque.foreignUser.corpora); - } - for (let subscriber of nopaque.foreignJobsSubscribers) { - subscriber._init(nopaque.foreignUser.jobs); - } - for (let subscriber of nopaque.foreignQueryResultsSubscribers) { - subscriber._init(nopaque.foreignUser.query_results); - } - }); +nopaque.socket.on("foreign_user_data_stream_init", function(msg) { + nopaque.foreignUser = JSON.parse(msg); + for (let subscriber of nopaque.foreignCorporaSubscribers) { + subscriber._init(nopaque.foreignUser.corpora); + } + for (let subscriber of nopaque.foreignJobsSubscribers) { + subscriber._init(nopaque.foreignUser.jobs); + } + for (let subscriber of nopaque.foreignQueryResultsSubscribers) { + subscriber._init(nopaque.foreignUser.query_results); + } +}); - nopaque.socket.on("foreign_user_data_stream_update", function(msg) { - var patch; +nopaque.socket.on("foreign_user_data_stream_update", function(msg) { + var patch; - patch = JSON.parse(msg); - nopaque.foreignUser = jsonpatch.apply_patch(nopaque.foreignUser, patch); - corpora_patch = patch.filter(operation => operation.path.startsWith("/corpora")); - jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs")); - query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results")); - for (let subscriber of nopaque.foreignCorporaSubscribers) {subscriber._update(corpora_patch);} - for (let subscriber of nopaque.foreignJobsSubscribers) {subscriber._update(jobs_patch);} - for (let subscriber of nopaque.foreignQueryResultsSubscribers) {subscriber._update(query_results_patch);} - }); -} + patch = JSON.parse(msg); + nopaque.foreignUser = jsonpatch.apply_patch(nopaque.foreignUser, patch); + corpora_patch = patch.filter(operation => operation.path.startsWith("/corpora")); + jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs")); + query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results")); + for (let subscriber of nopaque.foreignCorporaSubscribers) {subscriber._update(corpora_patch);} + for (let subscriber of nopaque.foreignJobsSubscribers) {subscriber._update(jobs_patch);} + for (let subscriber of nopaque.foreignQueryResultsSubscribers) {subscriber._update(query_results_patch);} +}); nopaque.Forms = {}; nopaque.Forms.init = function() { @@ -173,32 +164,10 @@ nopaque.Forms.init = function() { } } -nopaque.Navigation = {}; -nopaque.Navigation.init = function() { - /* ### Initialize sidenav-main ### */ - for (let entry of document.querySelectorAll("#sidenav-main a")) { - if (entry.href === window.location.href) { - entry.parentNode.classList.add("active"); - } - } -} - -nopaque.flash = function() { - var classes, toast, toastActionElement; - - switch (arguments.length) { - case 1: - category = "message"; - message = arguments[0]; - break; - case 2: - message = arguments[0]; - category = arguments[1]; - break; - default: - console.error("Usage: nopaque.flash(message) or nopaque.flash(message, category)") - } +nopaque.flash = function(message, category) { + let toast; + let toastActionElement; switch (category) { case "corpus": @@ -219,27 +188,5 @@ nopaque.flash = function() { close `}); toastActionElement = toast.el.querySelector('.toast-action[data-action="close"]'); - if (toastActionElement) { - toastActionElement.addEventListener('click', function() { - toast.dismiss(); - }); - } + toastActionElement.addEventListener('click', () => {toast.dismiss();}); } - - -document.addEventListener('DOMContentLoaded', () => { - // Disable all option elements with no value - for (let optionElement of document.querySelectorAll('option[value=""]')) { - optionElement.disabled = true; - } - M.AutoInit(); - M.CharacterCounter.init(document.querySelectorAll('input[data-length][type="text"]')); - M.Dropdown.init(document.querySelectorAll('#nav-notifications, #nav-account'), - {alignment: 'right', constrainWidth: false, coverTrigger: false}); - nopaque.Forms.init(); - nopaque.Navigation.init(); - while (nopaque.flashedMessages.length) { - flashedMessage = nopaque.flashedMessages.shift(); - nopaque.flash(flashedMessage[1], flashedMessage[0]); - } -}); diff --git a/web/app/templates/_variables.html.j2 b/web/app/templates/_variables.html.j2 new file mode 100644 index 00000000..95bf1953 --- /dev/null +++ b/web/app/templates/_variables.html.j2 @@ -0,0 +1,19 @@ +{% set colors = {'primary': '#00426f', + 'secondary': '#b1b3b4', + 'corpus_analysis': '#aa9cc9', + 'corpus_analysis_darken': '#6b3f89', + 'corpus_analysis_lighten': '#ebe8f6', + 'file_setup': '#d5dc95', + 'file_setup_darken': '#a1b300', + 'file_setup_lighten': '#f2f3e1', + 'nlp': '#98acd2', + 'nlp_darken': '#0064a3', + 'nlp_lighten': '#e5e8f5', + 'ocr': '#a9d8c8', + 'ocr_darken': '#00a58b', + 'ocr_lighten': '#e7f4f1'} %} + + +{% if main_class is not defined %} +{% set main_class = 'grey lighten-5' %} +{% endif %} diff --git a/web/app/templates/auth/login.html.j2 b/web/app/templates/auth/login.html.j2 index 69ccbe57..a477da4f 100644 --- a/web/app/templates/auth/login.html.j2 +++ b/web/app/templates/auth/login.html.j2 @@ -1,8 +1,8 @@ {% extends "nopaque.html.j2" %} +{% import 'materialize/wtf.html.j2' as wtf %} -{% set headline = ' ' %} - -{% block page_content %} +{% block styles %} +{{ super() }} +{% endblock styles %} -
-
-
-

Log in

-

Want to boost your research and get going? nopaque is free and no download is needed. Register now!

-
- -
-
- -
-
-
-
- {{ login_form.hidden_tag() }} - {{ M.render_field(login_form.user, material_icon='person') }} - {{ M.render_field(login_form.password, material_icon='vpn_key') }} -
- -
- {{ M.render_field(login_form.remember_me) }} -
+{% block page_content %} +
+
+
+
+
+

{{ title }}

+

Want to boost your research and get going? nopaque is free and no download is needed. Register now!

+
+
-
- {{ M.render_field(login_form.submit, material_icon='send') }} +
+ +
+
+ +
+ {{ login_form.hidden_tag() }} + {{ wtf.render_field(login_form.user, material_icon='person') }} + {{ wtf.render_field(login_form.password, material_icon='vpn_key') }} +
+ +
+ {{ wtf.render_field(login_form.remember_me) }} +
+
+
+
+ {{ wtf.render_field(login_form.submit, material_icon='send') }} +
+
- +
{% endblock %} diff --git a/web/app/templates/auth/register.html.j2 b/web/app/templates/auth/register.html.j2 index af8a0b95..db4ef2c0 100644 --- a/web/app/templates/auth/register.html.j2 +++ b/web/app/templates/auth/register.html.j2 @@ -1,8 +1,8 @@ {% extends "nopaque.html.j2" %} +{% import 'materialize/wtf.html.j2' as wtf %} -{% set headline = ' ' %} - -{% block page_content %} +{% block styles %} +{{ super() }} +{% endblock styles %} -
-
-
-

Register

-

Simply enter a username and password to receive your registration email. After that you can start right away.

-

It goes without saying that the General Data Protection Regulation applies, only necessary data is stored.

-

Please also read our terms of use before signing up for nopaque!

+{% block page_content %} +
+
+
+
+
+

Register

+

Simply enter a username and password to receive your registration email. After that you can start right away.

+

It goes without saying that the General Data Protection Regulation applies, only necessary data is stored.

+

Please also read our terms of use before signing up for nopaque!

+
+
+
+ +
+
+
+
+ {{ registration_form.hidden_tag() }} + {{ wtf.render_field(registration_form.username, data_length='64', material_icon='person') }} + {{ wtf.render_field(registration_form.password, data_length='128', material_icon='vpn_key') }} + {{ wtf.render_field(registration_form.password_confirmation, data_length='128', material_icon='vpn_key') }} + {{ wtf.render_field(registration_form.email, class_='validate', material_icon='email', type='email') }} +
+
+ {{ wtf.render_field(registration_form.submit, material_icon='send') }} +
+
+
- -
-
-
-
- {{ registration_form.hidden_tag() }} - {{ M.render_field(registration_form.username, data_length='64', material_icon='person') }} - {{ M.render_field(registration_form.password, data_length='128', material_icon='vpn_key') }} - {{ M.render_field(registration_form.password_confirmation, data_length='128', material_icon='vpn_key') }} - {{ M.render_field(registration_form.email, class_='validate', material_icon='email', type='email') }} -
-
- {{ M.render_field(registration_form.submit, material_icon='send') }} -
-
-
-
{% endblock %} diff --git a/web/app/templates/auth/reset_password.html.j2 b/web/app/templates/auth/reset_password.html.j2 index 6bd93f56..414a2d10 100644 --- a/web/app/templates/auth/reset_password.html.j2 +++ b/web/app/templates/auth/reset_password.html.j2 @@ -1,23 +1,31 @@ {% extends "nopaque.html.j2" %} +{% import 'materialize/wtf.html.j2' as wtf %} {% block page_content %} -
-

Lorem ipsum

-

dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,

-
+
+
+
+

{{ title }}

+
-
-
-
-
- {{ reset_password_form.hidden_tag() }} - {{ M.render_field(reset_password_form.password, data_length='128') }} - {{ M.render_field(reset_password_form.password_confirmation, data_length='128') }} +
+

dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,

+
+ +
+
+ +
+ {{ reset_password_form.hidden_tag() }} + {{ wtf.render_field(reset_password_form.password, data_length='128') }} + {{ wtf.render_field(reset_password_form.password_confirmation, data_length='128') }} +
+
+ {{ wtf.render_field(reset_password_form.submit, material_icon='send') }} +
+
-
- {{ M.render_field(reset_password_form.submit, material_icon='send') }} -
- +
{% endblock %} diff --git a/web/app/templates/auth/reset_password_request.html.j2 b/web/app/templates/auth/reset_password_request.html.j2 index cb8f23c8..549af6cd 100644 --- a/web/app/templates/auth/reset_password_request.html.j2 +++ b/web/app/templates/auth/reset_password_request.html.j2 @@ -1,21 +1,30 @@ {% extends "nopaque.html.j2" %} +{% import 'materialize/wtf.html.j2' as wtf %} {% block page_content %} -
-

After entering your email address you will receive instructions on how to reset your password.

-
+
+
+
+

{{ title }}

+
-
-
-
-
- {{ reset_password_request_form.hidden_tag() }} - {{ M.render_field(reset_password_request_form.email, class_='validate', material_icon='email', type='email') }} +
+

After entering your email address you will receive instructions on how to reset your password.

+
+ +
+
+ +
+ {{ reset_password_request_form.hidden_tag() }} + {{ wtf.render_field(reset_password_request_form.email, class_='validate', material_icon='email', type='email') }} +
+
+ {{ wtf.render_field(reset_password_request_form.submit, material_icon='send') }} +
+
-
- {{ M.render_field(reset_password_request_form.submit, material_icon='send') }} -
- +
{% endblock %} diff --git a/web/app/templates/auth/unconfirmed.html.j2 b/web/app/templates/auth/unconfirmed.html.j2 index f3d26dc9..98ce4de4 100644 --- a/web/app/templates/auth/unconfirmed.html.j2 +++ b/web/app/templates/auth/unconfirmed.html.j2 @@ -1,20 +1,25 @@ {% extends "nopaque.html.j2" %} -{% block title %}Opaque - Confirm your account{% endblock %} - {% block page_content %} -