integrate nopaque repo

This commit is contained in:
Patrick Jentsch
2020-06-05 14:42:04 +02:00
parent 450ddf69fc
commit cb2b64fa9d
164 changed files with 1212 additions and 168 deletions

View File

@ -1,7 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12">
<p>This site is forbidden for you.</p>
</div>
{% endblock %}

View File

@ -1,7 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12">
<p>Site has not been found.</p>
</div>
{% endblock %}

View File

@ -1,7 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12">
<p>Internal Server Error. We are Sorry!</p>
</div>
{% endblock %}

View File

@ -1,27 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<h3 id="title">{{ user.username }}</h3>
<p id="description">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,</p>
<a class="waves-effect waves-light btn" href="{{ url_for('admin.user', user_id=user.id) }}"><i class="material-icons left">arrow_back</i>Back to user administration</a>
</div>
<div class="col s12 m8">
<div class="card">
<form method="POST">
<div class="card-content">
{{ edit_user_form.hidden_tag() }}
{{ M.render_field(edit_user_form.username, data_length='64', material_icon='account_circle') }}
{{ M.render_field(edit_user_form.email, class_='validate', material_icon='email', type='email') }}
{{ M.render_field(edit_user_form.role, material_icon='swap_vert') }}
{{ M.render_field(edit_user_form.confirmed, material_icon='check') }}
</div>
<div class="card-action right-align">
{{ M.render_field(edit_user_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,30 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set full_width = True %}
{% block page_content %}
<div class="col s12">
<div class="card">
<div class="card-content" id="users">
<span class="card-title">User list</span>
<div class="input-field">
<i class="material-icons prefix">search</i>
<input id="search-user" class="search" type="search"></input>
<label for="search-user">Search user</label>
</div>
<ul class="pagination paginationTop"></ul>
{{ table }}
<ul class="pagination paginationBottom"></ul>
</div>
</div>
</div>
<script>
var options = {page: 10,
pagination: [{name: "paginationTop",
paginationClass: "paginationTop",},
{paginationClass: "paginationBottom"}],
valueNames: ['username', 'email', 'role', 'confirmed', 'id']};
var userList = new List('users', options);
</script>
{% endblock %}

View File

@ -1,110 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<h3 id="title">{{ user.username }}</h3>
<p id="description">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,</p>
<a class="waves-effect waves-light btn" href="{{ url_for('admin.index') }}"><i class="material-icons left">arrow_back</i>Back to admin board</a>
</div>
<div class="col s12 m8">
<div class="card">
<div class="card-content">
<span class="card-title">User information</span>
<ul>
<li>Username: {{ user.username }}</li>
<li>Email: {{ user.email }}</li>
<li>ID: {{ user.id }}</li>
<li>Member since: {{ user.member_since.strftime('%m/%d/%Y, %H:%M:%S %p') }}</li>
<li>Confirmed status: {{ user.confirmed }}</li>
<li>Last seen: {{ user.last_seen.strftime('%m/%d/%Y, %H:%M:%S %p') }}</li>
<li>Role ID: {{ user.role_id }}</li>
<li>Permissions as Int: {{ user.role.permissions }}</li>
<li>Role name: {{ user.role.name }}</li>
</ul>
</div>
<div class="card-action right-align">
<a href="{{ url_for('admin.edit_user', user_id=user.id) }}" class="waves-effect waves-light btn"><i class="material-icons left">edit</i>Edit</a>
<a data-target="delete-user-modal" class="waves-effect waves-light btn red modal-trigger"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</div>
<div class="col s12 l6">
<h3>Corpora</h3>
<div class="card">
<div class="card-content" id="corpora">
<div class="input-field">
<i class="material-icons prefix">search</i>
<input id="search-corpus" class="search" type="search"></input>
<label for="search-corpus">Search corpus</label>
</div>
<table>
<thead>
<tr>
<th></th>
<th>
<span class="sort" data-sort="title">Title</span>
<span class="sort" data-sort="description">Description</span>
</th>
<th><span class="sort" data-sort="status">Status</span></th>
<th></th>
</tr>
</thead>
<tbody class="list"></tbody>
</table>
<ul class="pagination"></ul>
</div>
</div>
</div>
<div class="col s12 l6">
<h3>Jobs</h3>
<div class="card">
<div class="card-content" id="jobs">
<div class="input-field">
<i class="material-icons prefix">search</i>
<input id="search-job" class="search" type="search"></input>
<label for="search-job">Search job</label>
</div>
<table>
<thead>
<tr>
<th><span class="sort" data-sort="service">Service</span></th>
<th>
<span class="sort" data-sort="title">Title</span>
<span class="sort" data-sort="description">Description</span>
</th>
<th><span class="sort" data-sort="status">Status</span></th>
<th></th>
</tr>
</thead>
<tbody class="list"></tbody>
</table>
<ul class="pagination"></ul>
</div>
</div>
</div>
<!-- Modals -->
<div id="delete-user-modal" class="modal">
<div class="modal-content">
<h4>Confirm user deletion</h4>
<p>Do you really want to delete the user {{ user.username }}? All associated data will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light btn">Cancel</a>
<a href="{{ url_for('admin.delete_user', user_id=user.id) }}" class="modal-close waves-effect waves-light btn red"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
<script>
var corpusList = new RessourceList("corpora", nopaque.foreignCorporaSubscribers, "corpus");
var jobList = new RessourceList("jobs", nopaque.foreignJobsSubscribers, "job");
document.addEventListener("DOMContentLoaded", () => {
nopaque.socket.emit("foreign_user_data_stream_init", {{ user.id }});
});
</script>
{% endblock %}

View File

@ -1,7 +0,0 @@
<p>Dear {{ user.username }},</p>
<p>to confirm your account please <a href="{{ url_for('auth.confirm', token=token, _external=True) }}">click here</a>.</p>
<p>Alternatively, you can paste the following link in your browser's address bar:</p>
<p>{{ url_for('auth.confirm', token=token, _external=True) }}</p>
<p>Sincerely,</p>
<p>The nopaque Team</p>
<p><small>Note: replies to this email address are not monitored.</small></p>

View File

@ -1,9 +0,0 @@
Dear {{ user.username }},
to confirm your account please click on the following link:
{{ url_for('auth.confirm', token=token, _external=True) }}
Sincerely,
The nopaque Team
Note: replies to this email address are not monitored.

View File

@ -1,8 +0,0 @@
<p>Dear {{ user.username }},</p>
<p>to reset your password <a href="{{ url_for('auth.reset_password', token=token, _external=True) }}">click here</a>.</p>
<p>Alternatively, you can paste the following link in your browser's address bar:</p>
<p>{{ url_for('auth.reset_password', token=token, _external=True) }}</p>
<p>If you have not requested a password reset simply ignore this message.</p>
<p>Sincerely,</p>
<p>The nopaque Team</p>
<p><small>Note: replies to this email address are not monitored.</small></p>

View File

@ -1,13 +0,0 @@
Dear {{ user.username }},
to reset your password click on the following link:
{{ url_for('auth.reset_password', token=token, _external=True) }}
If you have not requested a password reset simply ignore this message.
Sincerely,
The nopaque Team
Note: replies to this email address are not monitored.

View File

@ -1,48 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set headline = ' ' %}
{% block page_content %}
<style>
main {
background-image: url("{{ url_for('static', filename='images/parallax_lq/04_german_text_book_paper.jpg') }}");
background-repeat: no-repeat;
background-size: cover;
}
</style>
<div class="col s12 m4">
<div class="card medium">
<div class="card-content">
<h2>Log in</h2>
<p>Want to boost your research and get going? nopaque is free and no download is needed. Register now!</p>
</div>
<div class="card-action right-align">
<a class="btn" href="{{ url_for('auth.register') }}"><i class="material-icons left">person_add</i>Register</a>
</div>
</div>
</div>
<div class="col s12 m8">
<div class="card medium">
<form method="POST">
<div class="card-content">
{{ login_form.hidden_tag() }}
{{ M.render_field(login_form.user, material_icon='person') }}
{{ M.render_field(login_form.password, material_icon='vpn_key') }}
<div class="row" style="margin-bottom: 0;">
<div class="col s6 left-align">
<a href="{{ url_for('auth.reset_password_request') }}">Forgot your password?</a>
</div>
<div class="col s6 right-align">
{{ M.render_field(login_form.remember_me) }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(login_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,40 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set headline = ' ' %}
{% block page_content %}
<style>
main {
background-image: url("{{ url_for('static', filename='images/parallax_lq/02_concept_document_focus_letter.jpg') }}");
background-repeat: no-repeat;
background-size: cover;
}
</style>
<div class="col s12 m4">
<div class="card medium">
<div class="card-content">
<h2>Register</h2>
<p>Simply enter a username and password to receive your registration email. After that you can start right away.</p>
<p>It goes without saying that the <a>General Data Protection Regulation</a> applies, only necessary data is stored.</p>
</div>
</div>
</div>
<div class="col s12 m8">
<div class="card medium">
<form method="POST">
<div class="card-content">
{{ 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') }}
</div>
<div class="card-action right-align">
{{ M.render_field(registration_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,23 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<h3>Lorem ipsum</h3>
<p>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,</p>
</div>
<div class="col s12 m8">
<div class="card">
<form method="POST">
<div class="card-content">
{{ 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') }}
</div>
<div class="card-action right-align">
{{ M.render_field(reset_password_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,21 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<p>After entering your email address you will receive instructions on how to reset your password.</p>
</div>
<div class="col s12 m8">
<div class="card">
<form method="POST">
<div class="card-content">
{{ reset_password_request_form.hidden_tag() }}
{{ M.render_field(reset_password_request_form.email, class_='validate', material_icon='email', type='email') }}
</div>
<div class="card-action right-align">
{{ M.render_field(reset_password_request_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,20 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block title %}Opaque - Confirm your account{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>
Hello, {{ current_user.username }}!
</h1>
<h3>You have not confirmed your account yet.</h3>
<p>
Before you can access this site you need to confirm your account.
Check your inbox, you should have received an email with a confirmation link.
</p>
<p>
Need another confirmation email?
<a href="{{ url_for('auth.resend_confirmation') }}">Click here</a>
</p>
</div>
{% endblock %}

View File

@ -1,29 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<p>Fill out the following form to add a corpus to your corpora.</p>
<a class="waves-effect waves-light btn" href="{{ url_for('main.dashboard') }}"><i class="material-icons left">arrow_back</i>Back to dashboard</a>
</div>
<div class="col s12 m8">
<div class="card">
<form method="POST">
<div class="card-content">
{{ add_corpus_form.hidden_tag() }}
<div class="row">
<div class="col s12 m4">
{{ M.render_field(add_corpus_form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 m8">
{{ M.render_field(add_corpus_form.description, data_length='255', material_icon='description') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(add_corpus_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,76 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<h3>{{ corpus.title }}</h3>
<p>Fill out the following form to add a corpus file in verticalized text format (.vrt).</p>
<a class="waves-effect waves-light btn" href="{{ url_for('corpora.corpus', corpus_id=corpus.id) }}"><i class="material-icons left">arrow_back</i>Back to corpus</a>
</div>
<div class="col s12 m8">
<form class="nopaque-submit-form" data-progress-modal="progress-modal">
<div class="card">
<div class="card-content">
<span class="card-title">Required metadata</span>
{{ add_corpus_file_form.hidden_tag() }}
<div class="row">
<div class="col s12 m4">
{{ M.render_field(add_corpus_file_form.author, data_length='255', material_icon='person') }}
</div>
<div class="col s12 m4">
{{ M.render_field(add_corpus_file_form.title, data_length='255', material_icon='title') }}
</div>
<div class="col s12 m4">
{{ M.render_field(add_corpus_file_form.publishing_year, material_icon='access_time') }}
</div>
<div class="col s12">
{{ M.render_field(add_corpus_file_form.file, accept='.vrt', placeholder='Choose your .vrt file') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(add_corpus_file_form.submit, material_icon='send') }}
</div>
</div>
<br>
<ul class="collapsible hoverable">
<li>
<div class="collapsible-header"><i class="material-icons">add</i>Add additional metadata</div>
<div class="collapsible-body">
{% for field in add_corpus_file_form
if field.short_name not in ['author', 'csrf_token', 'file', 'publishing_year', 'submit', 'title'] %}
{{ M.render_field(field, data_length='255', material_icon=field.label.text[0:1]) }}
{% endfor %}
</div>
</li>
</ul>
<br>
<ul class="collapsible hoverable">
<li>
<div class="collapsible-header"><i class="material-icons">add</i>Add metadata with BibTex</div>
<div class="collapsible-body">
<span>
<div class="row">
<div class="col s12">
</div>
</div>
</span>
</div>
</li>
</ul>
</form>
</div>
<div id="progress-modal" class="modal">
<div class="modal-content">
<h4><i class="material-icons prefix">file_upload</i> Uploading file...</h4>
<div class="progress">
<div class="determinate" style="width: 0%"></div>
</div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div>
</div>
{% endblock %}

View File

@ -1,477 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set full_width = True %}
{% block page_content %}
<div class="col s12">
<ul class="collapsible expandable">
<li class="active">
<!-- <div class="collapsible-header">
<i class="material-icons">search</i>CQP Query
</div> -->
<!-- Div element above is part of valid materialize collapsible.
Commented out to prevent the user from collapsing it and also to save
space -->
<div class="collapsible-body" style="padding-top: 10px;
padding-right: 2rem;
padding-bottom: 0px;
padding-left: 2rem;">
<!-- Query form -->
<form id="query-form">
<div class="row">
<div class="col s12 m10">
<div class="input-field">
<i class="material-icons prefix">search</i>
{{ query_form.query() }}
{{ query_form.query.label }}
<span class="helper-text">
<a href="http://cwb.sourceforge.net/files/CQP_Tutorial/">
<i class="material-icons" style="font-size: inherit;">help
</i>
CQP query language tutorial
</a>
</span>
</div>
</div>
<div class="col s12 m2">
<br class="hide-on-small-only">
{{ M.render_field(query_form.submit, material_icon='send') }}
</div>
</div>
</form>
</div>
</li>
<li class="hoverable">
<div class="collapsible-header">
<i class="material-icons">settings</i>Display Options
</div>
<div class="collapsible-body">
<!-- Display options form -->
<form id="display-options-form">
<div class="row">
<div class="col s12 m6">
{{ M.render_field(display_options_form.results_per_page,
material_icon='format_list_numbered') }}
</div>
<div class="col s12 m6">
{{ M.render_field(display_options_form.result_context,
material_icon='short_text') }}
</div>
<div class="col s12">
{{ M.render_field(display_options_form.expert_mode) }}
</div>
</div>
</form>
</div>
</li>
</ul>
</div>
<!-- entire results div/card -->
<div class="col s12" id="query-display">
<div class="card">
<div class="card-content" id="result-list" style="overflow: hidden;">
<span class="card-title">Query Results</span>
<div class="error-container hide show-on-error"></div>
<div class="hide show-on-success">
<div class="col s12 m6 l6">
<div class="row">
<p>
<span id="received-match-count">
</span> of
<span id="match-count"></span>
matches loaded.
<br>
Matches occured in
<span id="text-lookup-count"></span>
corpus files.
</p>
<p id="query-results-user-feedback">
<i class="material-icons">help</i>
The Server is still sending your results.
Functions like "Export Results" and "Match Inspect" will be
available after all matches have been loaded.
</p>
</div>
<div class="row">
<div class="progress" id="query-results-progress">
<div class="determinate" id="query-results-determinate"></div>
</div>
</div>
</div>
<div class="col s12 m6 l6">
<div class="row">
<button id="query-results-export"
class="waves-effect
waves-light
btn-small
right disabled"
type="submit">Export Results
<i class="material-icons right">file_download</i>
</button>
</div>
</div>
<!-- Table showing the query results -->
<div class="col s12">
<ul class="pagination paginationTop"></ul>
<table class="responsive-table highlight">
<thead>
<tr>
<th style="width: 2%">Nr.</th>
<th style="width: 3%">Title</th>
<th style="width: 25%">Left context</th>
<th style="width: 45%">Match</th>
<th style="width: 25%">Right Context</th>
</tr>
</thead>
<tbody class="list" id="query-results">
</tbody>
</table>
<ul class="pagination paginationBottom"></ul>
</div>
</div>
</div>
</div>
</div>
<!-- Modals -->
<!-- Analysis init modal -->
<div class="modal no-autoinit" id="init-display">
<div class="modal-content">
<h4>Initializing your corpus analysis session...</h4>
<div class="error-container hide show-on-error"></div>
<div class="hide progress show-while-waiting">
<div class="indeterminate"></div>
</div>
</div>
</div>
<!-- Export query results modal -->
<div id="query-results-download-modal"
class="modal modal-fixed-footer no-autoinit">
<div class="modal-content">
<h4>Download current query Results</h4>
<p>The results of the current query can be downloaded as several files like
csv or json. Those files can be used in other software like Excel.
Also it is easy to publish your results as raw data like this!</p>
<table>
<tr>
<td>JSON</td>
<td>
<a class="btn waves-effect waves-light" id="download-results-json">
Download
<i class="material-icons right">file_download</i>
</a>
</td>
</tr>
<tr>
<td>CSV</td>
<td>
<a class="btn waves-effect waves-light disabled"
id="download-results-csv">
Download
<i class="material-icons right">file_download</i>
</a>
</td>
</tr>
<tr>
<td>EXCEL</td>
<td>
<a class="btn waves-effect waves-light disabled">Download
<i class="material-icons right">file_download</i>
</a>
</td>
</tr>
<tr>
<td>HTML</td>
<td>
<a class="btn waves-effect waves-light disabled">Download
<i class="material-icons right">file_download</i>
</a>
</td>
</tr>
</table>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light red btn">Close</a>
</div>
</div>
<!-- Context modal used for detailed information about one match -->
<div id="context-modal" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Match Inspect</h4>
<div id="inspect-display-options">
<form>
<ul class="collection with-header">
<li class="collection-header">
<h5>Display options</h5>
</li>
<li class="collection-item">
{{ inspect_display_options_form.expert_mode_inspect.label.text }}
<div class="secondary-content">
<div class="switch">
<label>
{{ inspect_display_options_form.expert_mode_inspect() }}
<span class="lever"></span>
</label>
</div>
</div>
</li>
<li class="collection-item">
{{ inspect_display_options_form.highlight_sentences.label.text }}
<div class="secondary-content">
<div class="switch">
<label>
{{ inspect_display_options_form.highlight_sentences() }}
<span class="lever"></span>
</label>
</div>
</div>
</li>
<li class="collection-item">
Sentences around match
<div class="secondary-content"
style="margin-top: -35px;
border-top-width: 0px;
margin-bottom: -20px;">
<div class="input-field">
<p class="range-field">
<input type="range"
id="context-sentences"
style="margin-top: 20px;
margin-bottom: 10px;"
min="1"
max="10"
value="3" />
</p>
</div>
</div>
</li>
</ul>
</form>
</div>
<div class="col s12" >
<h5>Context</h5>
<div id="context-results">
</div>
</div>
</div>
<div class="modal-footer">
<a id="inspect-download-context" class="left waves-effect waves-light btn">
Export Context
<i class="material-icons right">file_download</i>
</a>
<a href="#!" class="modal-close waves-effect waves-light red btn">Close</a>
</div>
</div>
<script src="{{ url_for('static', filename='js/nopaque.CorpusAnalysisClient.js') }}">
</script>
<script src="{{ url_for('static', filename='js/nopaque.Results.js') }}">
</script>
<script src="{{ url_for('static', filename='js/nopaque.callbacks.js') }}">
</script>
<script>
// ###### Defining global variables used in other functions ######
var client; // CorpusAnalysisClient first undefined on DOMContentLoaded defined
var collapsibleElements; // All collapsibleElements on this page
var contextModal; // Modal to open on inspect for further match context
var expertModeSwitchElement; // Expert mode switch Element
var initDisplay; // CorpusAnalysisDisplay object first undfined on DOMContentLoaded defined
var matchCountElement; // Total nr. of matches will be displayed in this element
var progress; // global progress value
var queryDisplay; // CorpusAnalysisDisplay object first undfined on DOMContentLoaded defined
var queryFormElement; // the query form
var queryResultsDeterminateElement; // The progress bar for recieved results
var queryResultsExportElement; // Download button opens download modal
var queryResultsProgressElement; // Div element holding the progress bar
var queryResultsUserFeedbackElement; // Element showing match count|total etc
var receivedMatchCountElement; // Nr. of loaded matches will be displayed in this element
var results; // results object
var data; // full JSON object holding match results
var resultsList; // resultsList object
var resultsListOptions; // specifies ResultsList options
var textLookupCountElement // Nr of texts the matches occured in will be shown in this element
// ###### Defining local scope variables ######
let contextPerItemElement; // Form Element for display option
let contextSentencesElement; // Form Element for display option in inspect
let displayOptionsData; // Getting form data from display options
let displayOptionsFormElement; // Form holding the display informations
let downloadResultsJSONElement; // button for downloading results as JSON
let downloadInspectContextElement; // button for downloading inspect context
let exportModal; // Download options modal
let firstPageElement; // first page element of resultsList pagination
let hitsPerPageInputElement;
let initDisplayElement; // Element for initialization using initDisplay
let initModal;
let paginationElements;
let queryDisplayElement; // Element for initialization using queryDisplay
let xpath; // xpath to grab first resultsList page pagination element
// ###### Initialize variables ######
client = undefined;
collapsibleElements = document.querySelector('.collapsible.expandable');
contextModal = document.getElementById("context-modal");
contextSentencesElement = document.getElementById("context-sentences");
displayOptionsFormElement = document.getElementById("display-options-form");
expertModeSwitchElement = document.getElementById("display-options-form-expert_mode");
exportModal = document.getElementById("query-results-download-modal");
initDisplay = undefined;
initDisplayElement = document.getElementById("init-display");
matchCountElement = document.getElementById("match-count");
paginationElements = document.getElementsByClassName("pagination");
queryDisplay = undefined;
queryDisplayElement = document.getElementById("query-display");
queryFormElement = document.getElementById("query-form");
queryResultsDeterminateElement = document.getElementById("query-results-determinate");
queryResultsExportElement = document.getElementById("query-results-export");
queryResultsProgressElement = document.getElementById("query-results-progress");
queryResultsUserFeedbackElement = document.getElementById("query-results-user-feedback");
receivedMatchCountElement = document.getElementById("received-match-count");
textLookupCountElement = document.getElementById("text-lookup-count");
hitsPerPageInputElement = document.getElementById("display-options-form-results_per_page");
contextPerItemElement = document.getElementById("display-options-form-result_context");
// ###### js list options and intialization ######
displayOptionsData = ResultsList.getDisplayOptions(displayOptionsFormElement);
resultsListOptions = {page: displayOptionsData["resultsPerPage"],
pagination: [{
name: "paginationTop",
paginationClass: "paginationTop",
innerWindow: 8,
outerWindow: 1
}, {
paginationClass: "paginationBottom",
innerWindow: 8,
outerWindow: 1
}],
valueNames: ["titles", "lc", "c", "rc", {data: ["index"]}],
item: `<span></span>`};
// ###### event on DOMContentLoaded ######
document.addEventListener("DOMContentLoaded", () => {
//set accordion of collapsibles to false
M.Collapsible.init(collapsibleElements, {accordion: false});
// creates some modals on DOMContentLoaded
contextModal = M.Modal.init(contextModal, {"dismissible": true});
exportModal = M.Modal.init(exportModal, {"dismissible": true});
initModal = M.Modal.init(initDisplayElement, {"dismissible": false});
// Init corpus analysis components
data = new Data();
resultsList = new ResultsList("result-list", resultsListOptions);
resultsMetaData = new MetaData();
results = new Results(data, resultsList, resultsMetaData);
initDisplay = new CorpusAnalysisDisplay(initDisplayElement);
queryDisplay = new CorpusAnalysisDisplay(queryDisplayElement);
client = new CorpusAnalysisClient({{ corpus_id }}, nopaque.socket);
initModal.open();
// set displays and callback functions
client.setDisplay("init", initDisplay);
client.setCallback("init", () => {
initModal.close();
});
client.setCallback('get_metadata', () => {
client.getMetaData();
})
client.setCallback('recv_meta_data', (response) => {
recvMetaData(response);
})
client.setDisplay("query", queryResultsUserFeedbackElement);
client.setDisplay("query", queryDisplay);
client.setCallback("query", (payload) => {
querySetup(payload);
});
client.setCallback("query_results", (payload) => {
queryRenderResults(payload);
});
client.setCallback("query_match_context", (payload) => {
results.jsList.showMatchContext(payload);
})
// Trigger corpus analysis initialization on server side
client.init();
// start a query request on submit
queryFormElement.addEventListener("submit", (event) => {
try {
// Selects first page of result list if pagination is already available
// from an query submitted before.
// This avoids confusion for the user eg: The user was on page 24
// reviewing the results and issues a new query. He would not see any
// results until the new results reach page 24 or he clicks on another
// valid result page element from the new pagination.
firstPageElement;
xpath = '//a[@class="page" and text()=1]';
firstPageElement = document.evaluate(xpath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null).singleNodeValue;
firstPageElement.click();
} catch (e) {
}
// Prevent page from reloading on submit
event.preventDefault();
// Get query string and send query to server
results.data.getQueryStr(queryFormElement);
client.query(results.data.query);
});
// live update of hits per page if hits per page value is changed
let changeHitsPerPageBind = results.jsList.changeHitsPerPage.bind(results.jsList);
hitsPerPageInputElement.onchange = changeHitsPerPageBind;
// live update of lr context per item if context value is changed
contextPerItemElement.onchange = results.jsList.changeContext;
// eventListener if pagination is used to apply new context size to new page
// and also activate inspect match if progress is 100
for (let element of paginationElements) {
element.addEventListener("click", results.jsList.changeContext);
element.addEventListener("click", results.jsList.activateInspect);
}
expertModeSwitchElement.addEventListener("change", (event) => {
if (event.target.checked) {
results.jsList.expertModeOn("query-display");
for (let element of paginationElements) {
element.onclick = (event) => {
results.jsList.eventHandlerCheck(event)
}
}
} else {
results.jsList.expertModeOff("query-display");
}
});
});
// Add onclick to open download modal when Export Results button is pressed
queryResultsExportElement.onclick = () => {
exportModal.open();
}
// add onclick to download JSON button and download the file
downloadResultsJSONElement = document.getElementById("download-results-json")
downloadResultsJSONElement.onclick = () => {
let filename = results.data.createDownloadFilename("matches");
results.data.addData(results.metaData);
results.data.downloadJSONRessource(filename, results.data,
downloadResultsJSONElement
)};
// add onclick to download JSON button and download the file
downloadInspectContextElement = document.getElementById("inspect-download-context")
downloadInspectContextElement.onclick = () => {
let filename = results.data.createDownloadFilename(`context-id-${results.jsList.contextId}`);
results.data.addData(results.metaData);
results.data.downloadJSONRessource(filename,
results.jsList.contextData,
downloadInspectContextElement);
};
</script>
{% endblock %}

View File

@ -1,220 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<h3 id="title">{{ corpus.title }}</h3>
<p id="description">{{ corpus.description }}</p>
<div class="active preloader-wrapper small hide" id="progress-indicator">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
<span class="chip status white-text hide" id="status"></span>
</div>
<div class="col s12 m8">
<div class="card">
<div class="card-content">
<span class="card-title">Chronometrics</span>
<div class="row">
<div class="col s12 m6">
<div class="input-field">
<input disabled value="{{ corpus.creation_date.strftime('%m/%d/%Y, %H:%M:%S %p') }}" id="creation-date" type="text" class="validate">
<label for="creation-date">Creation date</label>
</div>
</div>
<div class="col s12 m6">
<div class="input-field">
<input disabled value="{{ corpus.last_edited_date.strftime('%m/%d/%Y, %H:%M:%S %p') }}" id="last_edited_date" type="text" class="validate">
<label for="creation-date">Last edited</label>
</div>
</div>
<div class="col s12 m6">
<div class="input-field">
<input disabled value="{{ corpus.current_nr_of_tokens }} / {{ corpus.max_nr_of_tokens }}" id="nr_of_tokens" type="text" class="validate">
<label for="creation-date">Nr. of tokens used
<i class="material-icons tooltipped" data-position="bottom" data-tooltip="Current number of tokens in this corpus. Updates after every analyze session.">help</i>
</label>
</div>
</div>
</div>
</div>
<div class="card-action right-align">
<a href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}" class="btn disabled hide waves-effect waves-light" id="analyze"><i class="material-icons left">search</i>Analyze</a>
<a href="{{ url_for('corpora.prepare_corpus', corpus_id=corpus.id) }}" class="btn disabled hide waves-effect waves-light" id="build"><i class="material-icons left">build</i>Build</a>
<a data-target="delete-corpus-modal" class="btn modal-trigger red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</div>
<div class="col s12"></div>
<div class="col s12">
<div class="card">
<div class="card-content" style="overflow: hidden;">
<span class="card-title">Files</span>
<table class="highlight responsive-table">
<thead>
<tr>
<th>Filename</th>
<th>Author</th>
<th>Title</th>
<th>Publishing year</th>
<th></th>
</tr>
</thead>
<tbody>
<tr class="show-if-only-child">
<td colspan="5">
<span class="card-title"><i class="material-icons left">book</i>Nothing here...</span>
<p>Corpus is empty. Add texts using the option below.</p>
</td>
</tr>
{% for file in corpus.files %}
<tr>
<td style="word-break: break-word;">{{ file.filename }}</td>
<td style="word-break: break-word;">{{ file.author }}</td>
<td style="word-break: break-word;">{{ file.title }}</td>
<td>{{ file.publishing_year }}</td>
<td class="right-align">
<a class="btn-small waves-effect waves-light" href="{{ url_for('corpora.edit_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">edit</i></a>
<a class="btn-small waves-effect waves-light" href="{{ url_for('corpora.download_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">file_download</i></a>
<a data-target="delete-corpus-file-{{ file.id }}-modal" class="btn-small modal-trigger red waves-effect waves-light"><i class="material-icons">delete</i></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="card-action right-align">
<a href="{{ url_for('corpora.add_corpus_file', corpus_id=corpus.id) }}" class="btn waves-effect waves-light"><i class="material-icons left">add</i>Add corpus file</a>
</div>
</div>
</div>
<!-- Modals -->
<div id="delete-corpus-modal" class="modal">
<div class="modal-content">
<h4>Confirm corpus deletion</h4>
<p>Do you really want to delete the corpus {{corpus.title}}? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a href="{{ url_for('corpora.delete_corpus', corpus_id=corpus.id) }}" class="btn modal-close red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
{% for file in corpus.files %}
<div id="delete-corpus-file-{{ file.id }}-modal" class="modal">
<div class="modal-content">
<h4>Confirm corpus file deletion</h4>
<p>Do you really want to delete the corpus file {{ file.filename }}? The file will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('corpora.delete_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
{% endfor %}
<script>
class InformationUpdater {
constructor(corpusId, foreignCorpusFlag) {
this.corpusId = corpusId;
this.foreignCorpusFlag = foreignCorpusFlag;
if (this.foreignCorpusFlag) {
nopaque.foreignCorporaSubscribers.push(this);
} else {
nopaque.corporaSubscribers.push(this);
}
}
_init() {
let corpus;
corpus = (this.foreignCorpusFlag ? nopaque.foreignUser.corpora[this.corpusId]
: nopaque.user.corpora[this.corpusId]);
// Status
this.setStatus(corpus.status);
}
_update(patch) {
let pathArray;
for (let operation of patch) {
/* "/corpora/{corpusId}/valueName" -> ["{corpusId}", ...] */
pathArray = operation.path.split("/").slice(2);
if (pathArray[0] != this.corpusId) {continue;}
switch(operation.op) {
case "add":
location.reload();
break;
case "delete":
location.reload();
break;
case "replace":
if (pathArray[1] === "status") {
this.setStatus(operation.value);
}
break;
default:
break;
}
}
}
setStatus(status) {
let analyzeElement, buildElement, numFiles, progressIndicatorElement, statusElement;
numFiles = Object.keys((this.foreignCorpusFlag ? nopaque.foreignUser.corpora[this.corpusId] : nopaque.user.corpora[this.corpusId]).files).length;
progressIndicatorElement = document.getElementById("progress-indicator");
if (["queued", "running", "start analysis", "stop analysis"].includes(status)) {
progressIndicatorElement.classList.remove("hide");
} else {
progressIndicatorElement.classList.add("hide");
}
statusElement = document.getElementById("status");
statusElement.dataset.status = status;
statusElement.classList.remove("hide");
analyzeElement = document.getElementById("analyze");
if (["analysing", "prepared", "start analysis"].includes(status)) {
analyzeElement.classList.remove("disabled", "hide");
} else {
analyzeElement.classList.add("disabled", "hide");
}
buildElement = document.getElementById("build");
if (status === "unprepared" && numFiles > 0) {
buildElement.classList.remove("disabled", "hide");
} else {
buildElement.classList.add("disabled", "hide");
}
}
}
{% if corpus.creator == current_user %}
var informationUpdater = new InformationUpdater({{ corpus.id }}, false);
{% else %}
var informationUpdater = new InformationUpdater({{ corpus.id }}, true);
document.addEventListener("DOMContentLoaded", () => {
nopaque.socket.emit("foreign_user_data_stream_init", {{ corpus.user_id }});
});
{% endif %}
</script>
{% endblock %}

View File

@ -1,45 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<h3 id="title">...</h3>
<p id="description">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</p>
<a class="btn waves-effect waves-light" href="{{ url_for('corpora.corpus', corpus_id=corpus.id) }}"><i class="material-icons left">arrow_back</i>Back to corpus</a>
</div>
<div class="col s12 m8">
<form method="POST">
{{ edit_corpus_file_form.hidden_tag() }}
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12 m4">
{{ M.render_field(edit_corpus_file_form.author, data_length='255', material_icon='person') }}
</div>
<div class="col s12 m4">
{{ M.render_field(edit_corpus_file_form.title, data_length='255', material_icon='title') }}
</div>
<div class="col s12 m4">
{{ M.render_field(edit_corpus_file_form.publishing_year, material_icon='access_time') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(edit_corpus_file_form.submit, material_icon='send') }}
</div>
</div>
<br>
<ul class="collapsible hoverable">
<li>
<div class="collapsible-header"><i class="material-icons">edit</i>Edit additional metadata</div>
<div class="collapsible-body">
{% for field in edit_corpus_file_form
if field.short_name not in ['author', 'csrf_token', 'publishing_year', 'submit', 'title'] %}
{{ M.render_field(field) }}
{% endfor %}
</div>
</li>
</ul>
</form>
</div>
{% endblock %}

View File

@ -1,261 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set headline = '<i class="left material-icons service" data-service="{service}" style="font-size: inherit;"></i>Job view'.format(service=job.service) %}
{% block page_content %}
<div class="col s12">
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s8 m9 l10">
<span class="card-title title">{{ job.title }}</span>
</div>
<div class="col s4 m3 l2 right-align">
<span class="chip status white-text"></span>
<div class="active preloader-wrapper small" id="progress-indicator">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
<div class="col s12">
<p class="description">{{ job.description }}</p>
</div>
<div class="col s12">&nbsp;</div>
<div class="col s12 m6">
<div class="input-field">
<input disabled id="creation-date" type="text" value="{{ job.creation_date.strftime('%m/%d/%Y, %H:%M:%S %p') }}">
<label for="creation-date">Creation date</label>
</div>
</div>
<div class="col s12 m6">
<div class="input-field">
<input class="end-date" disabled id="end-date" type="text" value="">
<label for="end-date">End date</label>
</div>
</div>
<div class="col s12 m4">
<div class="input-field">
<input disabled id="service" type="text" value="{{ job.service }}">
<label for="service">Service</label>
</div>
</div>
<div class="col s12 m4">
<div class="input-field">
<input disabled id="service-args" type="text" value="{{ job.service_args|e }}">
<label for="service-args">Service arguments</label>
</div>
</div>
<div class="col s12 m4">
<div class="input-field">
<input disabled id="service-version" type="text" value="{{ job.service_version }}">
<label for="service-version">Service version</label>
</div>
</div>
</div>
</div>
<div class="card-action right-align">
<a href="#" class="btn disabled waves-effect waves-light"><i class="material-icons left">settings</i>Export Parameters</a>
<a data-target="delete-job-modal" class="waves-effect waves-light btn red modal-trigger"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</div>
<div class="col s12">
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12 m2">
<span class="card-title"><i class="left material-icons" style="font-size: inherit;">input</i>Inputs</span>
<p>Original input files.</p>
</div>
<div class="col s12 m10">
<div class="inputs row">
{% for input in job.inputs %}
<div class="col s12 m6">
<a class="btn waves-effect waves-light" download href="{{ url_for('jobs.download_job_input', job_id=job.id, job_input_id=input.id) }}">
<i class="material-icons left">file_download</i>{{ input.filename }}
</a>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col s12">
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12 m2">
<span class="card-title"><i class="left material-icons" style="font-size: inherit;">done</i>Results</span>
<p>Processed result files.</p>
</div>
<div class="col s12 m10">
<div class="results row">
<div class="show-if-only-child">
<span class="card-title"><i class="left material-icons" style="font-size: inherit;">file_download</i>Nothing here...</span>
<p>No results available (yet). Is the job already completed?</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modals -->
<div id="delete-job-modal" class="modal">
<div class="modal-content">
<h4>Confirm deletion</h4>
<p>Do you really want to delete the job {{ job.title }}? All associated files will be permanently deleted.</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('jobs.delete_job', job_id=job.id) }}"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
<script>
class InformationUpdater {
constructor(jobId, foreignJobFlag) {
this.jobId = jobId;
this.foreignJobFlag = foreignJobFlag;
if (this.foreignJobFlag) {
nopaque.foreignJobsSubscribers.push(this);
} else {
nopaque.jobsSubscribers.push(this);
}
}
_init() {
let job;
job = (this.foreignJobFlag ? nopaque.foreignUser.jobs[this.jobId]
: nopaque.user.jobs[this.jobId]);
// Results
this.addResults(job.results);
// End date
this.setEndDate(job.end_date);
// Status
this.setStatus(job.status);
}
_update(patch) {
let pathArray;
for (let operation of patch) {
/* "/jobs/{jobId}/..." -> ["{jobId}", ...] */
pathArray = operation.path.split("/").slice(2);
if (pathArray[0] != this.jobId) {continue;}
switch(operation.op) {
case "add":
if (pathArray[1] === "results") {
this.addResults([operation.value]);
}
break;
case "delete":
location.reload();
break;
case "replace":
if (pathArray[1] === "end_date") {
this.setEndDate(operation.value);
} else if (pathArray[1] === "status") {
this.setStatus(operation.value);
}
break;
default:
break;
}
}
}
addResults(results) {
let resultsArray, resultsElements, resultsHTML, resultType;
resultsArray = Object.values(results);
resultsArray.sort(function (a, b) {
if (a.filename < b.filename) {return -1;}
if (a.filename > b.filename) {return 1;}
return 0;
});
resultsHTML = "";
for (let result of resultsArray) {
if (result.filename.endsWith(".pdf.zip")) {
resultType = "PDF";
} else if (result.filename.endsWith(".txt.zip")) {
resultType = "TXT";
} else if (result.filename.endsWith(".vrt.zip")) {
resultType = "VRT";
} else if (result.filename.endsWith(".xml.zip")) {
resultType = "XML";
} else {
resultType = "ALL";
}
resultsHTML += `<div class="col s4 m3 l2">
<a class="btn waves-effect waves-light" download href="/jobs/${result.job_id}/results/${result.id}/download">
<i class="material-icons left">file_download</i>${resultType}
</a>
</div>`;
}
resultsElements = document.querySelectorAll(".results");
for (let resultsElement of resultsElements) {
resultsElement.innerHTML += resultsHTML;
}
}
setEndDate(timestamp) {
let endDate;
if (timestamp === null) {
endDate = "N.a.";
} else {
endDate = new Date(timestamp * 1000).toLocaleString("en-US");
}
document.getElementById("end-date").value = endDate;
M.updateTextFields();
}
setStatus(status) {
let progressIndicator, statusElements;
if (status === "complete") {
progressIndicator = document.getElementById("progress-indicator");
progressIndicator.classList.add("hide");
}
statusElements = document.querySelectorAll(".status");
for (let statusElement of statusElements) {
statusElement.dataset.status = status;
}
}
}
{% if job.creator == current_user %}
var informationUpdater = new InformationUpdater({{ job.id }}, false);
{% else %}
var informationUpdater = new InformationUpdater({{ job.id }}, true);
document.addEventListener("DOMContentLoaded", () => {
nopaque.socket.emit("foreign_user_data_stream_init", {{ job.user_id }});
});
{% endif %}
</script>
{% endblock %}

View File

@ -1,86 +0,0 @@
{% macro render_field(field) %}
{% if field.flags.required and field.type not in ['FileField', 'MultipleFileField'] %}
{% if 'class_' in kwargs and 'validate' not in kwargs['class_'] %}
{% set tmp = kwargs.update({'class_': kwargs['class_'] + ' validate'}) %}
{% else %}
{% set tmp = kwargs.update({'class_': 'validate'}) %}
{% endif %}
{% endif %}
{% if field.type == 'BooleanField' %}
{{ render_boolean_field(field, *args, **kwargs) }}
{% elif field.type == 'DecimalRangeField' %}
{{ render_decimal_range_field(field, *args, **kwargs) }}
{% elif field.type == 'IntegerField' %}
{% set tmp = kwargs.update({'type': 'number'}) %}
{% if 'class_' in kwargs and 'validate' not in kwargs['class_'] %}
{% set tmp = kwargs.update({'class_': kwargs['class_'] + ' validate'}) %}
{% else %}
{% set tmp = kwargs.update({'class_': 'validate'}) %}
{% endif %}
{{ render_generic_field(field, *args, **kwargs) }}
{% elif field.type == 'SubmitField' %}
{{ render_submit_field(field, *args, **kwargs) }}
{% elif field.type in ['FileField', 'MultipleFileField'] %}
{{ render_file_field(field, *args, **kwargs) }}
{% elif field.type in ['PasswordField', 'SelectField', 'StringField'] %}
{{ render_generic_field(field, *args, **kwargs) }}
{% endif %}
{% endmacro %}
{% macro render_boolean_field(field) %}
{% set label = kwargs.pop('label', True) %}
<div class="switch">
{% if 'material_icon' in kwargs %}
<i class="material-icons prefix">{{ kwargs.pop('material_icon') }}</i>
{% endif %}
<label>
{% if label %}
{{ field.label.text }}
{% endif %}
{{ field(*args, **kwargs) }}
<span class="lever"></span>
</label>
{% for error in field.errors %}
<span class="helper-text red-text">{{ error }}</span>
{% endfor %}
</div>
{% endmacro %}
{% macro render_file_field(field) %}
{% set placeholder = kwargs.pop('placeholder', '') %}
<div class="file-field input-field">
<div class="btn">
<span>{{ field.label.text }}</span>
{{ field(*args, **kwargs) }}
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="{{ placeholder }}">
</div>
</div>
{% endmacro %}
{% macro render_generic_field(field) %}
{% set label = kwargs.pop('label', True) %}
<div class="input-field">
{% if 'material_icon' in kwargs %}
<i class="material-icons prefix">{{ kwargs.pop('material_icon') }}</i>
{% endif %}
{{ field(*args, **kwargs) }}
{% if label %}
{{ field.label }}
{% endif %}
{% for error in field.errors %}
<span class="helper-text red-text">{{ error }}</span>
{% endfor %}
</div>
{% endmacro %}
{% macro render_submit_field(field) %}
<button class="btn waves-effect waves-light" id="{{ field.id }}" name="{{ field.name }}" type="submit" value="{{ field.label.text }}">
{{ field.label.text }}
{% if 'material_icon' in kwargs %}
<i class="material-icons right">{{ kwargs.pop('material_icon') }}</i>
{% endif %}
</button>
{% endmacro %}

View File

@ -1,111 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12" id="corpora">
<h3>My Corpora</h3>
<p>This service enables you to group your files into corpora. You can create as many as you want and edit them at all times.</p>
<div class="card">
<div class="card-content">
<div class="input-field">
<i class="material-icons prefix">search</i>
<input id="search-corpus" class="search" type="search"></input>
<label for="search-corpus">Search corpus</label>
</div>
<table>
<thead>
<tr>
<th></th>
<th>
<span class="sort" data-sort="title">Title</span>
<span class="sort" data-sort="description">Description</span>
</th>
<th><span class="sort" data-sort="status">Status</span></th>
<th></th>
</tr>
</thead>
<tbody class="list"></tbody>
</table>
<ul class="pagination"></ul>
</div>
<div class="card-action right-align">
<a class="waves-effect waves-light btn" href="{{ url_for('corpora.add_corpus') }}">New corpus<i class="material-icons right">add</i></a>
</div>
</div>
</div>
<div class="col s12" id="jobs">
<h3>My Jobs</h3>
<p>A job is the execution of a service provided by nopaque. You can create any number of jobs and let them be processed simultaneously.</p>
<div class="card">
<div class="card-content">
<div class="input-field">
<i class="material-icons prefix">search</i>
<input id="search-job" class="search" type="search"></input>
<label for="search-job">Search job</label>
</div>
<table>
<thead>
<tr>
<th><span class="sort" data-sort="service">Service</span></th>
<th>
<span class="sort" data-sort="title">Title</span>
<span class="sort" data-sort="description">Description</span>
</th>
<th><span class="sort" data-sort="status">Status</span></th>
<th></th>
</tr>
</thead>
<tbody class="list"></tbody>
</table>
<ul class="pagination"></ul>
</div>
<div class="card-action right-align">
<p><a class="modal-trigger waves-effect waves-light btn" href="#" data-target="new-job-modal"><i class="material-icons left">add</i>New job</a></p>
</div>
</div>
</div>
<div id="new-job-modal" class="modal">
<div class="modal-content">
<h4>Select a service</h4>
<div class="row">
<div class="col s12 m4">
<a href="{{ url_for('services.service', service='file-setup') }}" style="color: rgba(0,0,0,0.87);">
<div class="card-panel center-align hoverable">
<i class="large material-icons" style="color: #ee6e73;">burst_mode</i>
<p>File setup</p>
<p class="light">Digital copies of text based research data (books, letters, etc.) often comprise various files and formats. nopaque converts and merges those files to facilitate further processing and the application of other services.</p>
</div>
</a>
</div>
<div class="col s12 m4">
<a href="{{ url_for('services.service', service='ocr') }}" style="color: rgba(0,0,0,0.87);">
<div class="card-panel center-align hoverable">
<i class="large material-icons" style="color: #ee6e73;">find_in_page</i>
<p>Optical Character Recognition</p>
<p class="light">nopaque converts your image data like photos or scans into text data through a process called OCR. This step enables you to proceed with further computational analysis of your documents.</p>
</div>
</a>
</div>
<div class="col s12 m4">
<a href="{{ url_for('services.service', service='nlp') }}" style="color: rgba(0,0,0,0.87);">
<div class="card-panel center-align hoverable">
<i class="large material-icons" style="color: #ee6e73;">format_textdirection_l_to_r</i>
<p>Natural Language Processing</p>
<p class="light">By means of computational linguistic data processing (tokenization, lemmatization, part-of-speech tagging and named-entity recognition) nopaque extracts additional information from your text.</p>
</div>
</a>
</div>
</div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light btn-flat">Close</a>
</div>
</div>
<script>
var corpusList = new RessourceList("corpora", nopaque.corporaSubscribers,
"corpus");
var jobList = new RessourceList("jobs", nopaque.jobsSubscribers, "job");
</script>
{% endblock %}

View File

@ -1,35 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12">
<div class="card">
<form method="POST">
{{ feedback_form.hidden_tag() }}
<div class="card-content">
<p class="range-field">
{{ feedback_form.like_range.label }}
{{ feedback_form.like_range(class='validate', type='range', min=1, max=10) }}
</p>
<div class="input-field">
<i class="material-icons prefix">email</i>
{{ feedback_form.email(class='validate', type='email') }}
{{ feedback_form.email.label }}
{% for error in feedback_form.email.errors %}
<span class="helper-text red-text">{{ error }}</span>
{% endfor %}
</div>
<div class="input-field">
<i class="material-icons prefix">mode_edit</i>
{{ feedback_form.feedback(class='materialize-textarea', data_length=255) }}
{{ feedback_form.feedback.label }}
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(feedback_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,211 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set parallax = True %}
{% block page_content %}
<div class="section white">
<div class="row container">
<div class="col s12">
<h2>nopaque</h2>
<p>From text to data to analysis</p>
</div>
</div>
</div>
<div class="parallax-container">
<div class="parallax">
<img src="{{ url_for('static', filename='images/parallax_lq/01_books_antique_book_old.jpg') }}" alt="">
</div>
</div>
<div class="section white scrollspy" id="information">
<div class="row container">
<div class="col s12 m10">
<div class="row">
<div class="col s12">
<h3>Why you should use nopaque</h3>
<p>nopaque is a custom-built web application for researchers who want to get out more of their images and texts without having to bother about the technical side of things. You can focus on what really interests you, nopaque does the rest.</p>
</div>
<div class="col s12">
<div class="row">
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">flash_on</i>
<p>Speeds up your work</p>
<p class="light">All tools provided by nopaque are carefully selected to provide a complete tool suite without being held up by compatibility issues.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">cloud</i>
<p>Cloud infrastructure</p>
<p class="light">All computational work is processed within nopaques cloud infrastructure. You don't need to install any software. Great, right?</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">group</i>
<p>User friendly</p>
<p class="light">You can start right away without having to read mile-long manuals. All services come with default settings that make it easy for you to just get going. Also great, right?</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">settings</i>
<p>Meshing processes</p>
<p class="light">No matter where you step in, nopaque facilitates and accompanies your research. Its workflow perfectly ties in with your research process.</p>
</div>
</div>
</div>
</div>
</div>
<div class="col s12 m2">
<ul class="section table-of-contents">
<li><a href="#information">Why you should use nopaque</a></li>
<li><a href="#services">What nopaque can do for you</a></li>
{% if current_user.is_anonymous %}
<li><a href="#registration-and-log-in">Registration and log in</a></li>
{% endif %}
<li><a href="#workflow">Workflow</a></li>
</ul>
</div>
</div>
</div>
<div class="parallax-container">
<div class="parallax">
<img src="{{ url_for('static', filename='images/parallax_lq/02_concept_document_focus_letter.jpg') }}" alt="">
</div>
</div>
<div class="section white scrollspy" id="services">
<div class="row container">
<div class="col s12 m10">
<div class="row">
<div class="col s12">
<h3>What nopaque can do for you</h3>
<p>All services and processes are logically linked and built upon each other. You can follow them step by step or directly choose the one that suits your needs best. And while the process is computed in nopaques cloud, you can just keep working.</p>
</div>
<div class="col s12">
<br class="hide-on-small-only">
<div class="row">
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">burst_mode</i>
<p>File setup</p>
<p class="light">Digital copies of text based research data (books, letters, etc.) often comprise various files and formats. nopaque converts and merges those files to facilitate further processing and the application of other services.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">find_in_page</i>
<p>Optical Character Recognition</p>
<p class="light">nopaque converts your image data like photos or scans into text data through OCR making it machine readable. This step enables you to proceed with further computational analysis of your documents.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">format_textdirection_l_to_r</i>
<p>Natural Language Processing</p>
<p class="light">By means of computational linguistic data processing (tokenization, lemmatization, part-of-speech tagging and named-entity recognition) nopaque extracts additional information from your text.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">search</i>
<p>Corpus analysis</p>
<p class="light">nopaque lets you create and upload as many text corpora as you want. It makes use of CQP Query Language, which allows for complex search requests with the aid of metadata and NLP tags.</p>
</div>
</div>
</div>
</div>
</div>
<div class="col s12 m2">
<ul class="section table-of-contents">
<li><a href="#information">Why you should use nopaque</a></li>
<li><a href="#services">What nopaque can do for you</a></li>
{% if current_user.is_anonymous %}
<li><a href="#registration-and-log-in">Registration and log in</a></li>
{% endif %}
<li><a href="#workflow">Workflow</a></li>
</ul>
</div>
</div>
</div>
<div class="parallax-container">
<div class="parallax">
<img src="{{ url_for('static', filename='images/parallax_lq/03_text_data_wide.png') }}" alt="">
</div>
</div>
{% if current_user.is_anonymous %}
<div class="section white scrollspy" id="registration-and-log-in">
<div class="row container">
<div class="col s12 m10">
<div class="row">
<div class="col s12 m4">
<h3>Registration and Log in</h3>
<p>Want to boost your research and get going? nopaque is free and no download is needed. Register now!</p>
<a class="btn waves-effect waves-light" href="{{ url_for('auth.register') }}"><i class="material-icons left">person_add</i>Register</a>
</div>
<div class="col s12 m8">
<br class="hide-on-small-only">
<div class="card">
<form method="POST">
<div class="card-content">
<span class="card-title">Log in</span>
{{ login_form.hidden_tag() }}
{{ M.render_field(login_form.user, material_icon='person') }}
{{ M.render_field(login_form.password, material_icon='vpn_key') }}
<div class="row" style="margin-bottom: 0;">
<div class="col s6 left-align">
<a href="{{ url_for('auth.reset_password_request') }}">Forgot your password?</a>
</div>
<div class="col s6 right-align">
{{ M.render_field(login_form.remember_me) }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(login_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
</div>
</div>
<div class="col s12 m2">
<ul class="section table-of-contents">
<li><a href="#information">Why you should use nopaque</a></li>
<li><a href="#services">What nopaque can do for you</a></li>
{% if current_user.is_anonymous %}
<li><a href="#registration-and-log-in">Registration and log in</a></li>
{% endif %}
<li><a href="#workflow">Workflow</a></li>
</ul>
</div>
</div>
</div>
<div class="parallax-container">
<div class="parallax">
<img src="{{ url_for('static', filename='images/parallax_lq/04_german_text_book_paper.jpg') }}" alt="">
</div>
</div>
{% endif %}
<div class="section white scrollspy" id="workflow">
<div class="row container">
<div class="col s12 m10">
<h3>Workflow</h3>
<h4>Coming soon...</h4>
</div>
<div class="col s12 m2">
<ul class="section table-of-contents">
<li><a href="#information">Why you should use nopaque</a></li>
<li><a href="#services">What nopaque can do for you</a></li>
{% if current_user.is_anonymous %}
<li><a href="#registration-and-log-in">Registration and log in</a></li>
{% endif %}
<li><a href="#workflow">Workflow</a></li>
</ul>
</div>
</div>
</div>
<div class="parallax-container">
<div class="parallax">
<img src="{{ url_for('static', filename='images/parallax_lq/05_chapter_book_text_tale.jpg') }}" alt="">
</div>
</div>
{% endblock %}

View File

@ -1,202 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set parallax = True %}
{% block page_content %}
<style>
{% if request.args.get('print') == 'True' %}
html {
/* DIN 0 bei 150dpi */
width: 4697;
height: 7022px;
}
div.navbar-fixed {
transform: scale(3);
transform-origin: 0 0;
}
footer.page-footer {
transform: scale(3);
transform-origin: 0 0;
margin-top: 5496px;
}
.print-transform {
transform: scale(3);
transform-origin: 0 0;
}
{% endif %}
.parallax-container {
height: 321px;
}
</style>
<div class="print-transform">
<div class="section">
<div class="row container">
<div class="col s12 m5">
<h1>nopaque</h1>
<p>From text to data to analysis</p>
<p class="light">Patrick Jentsch, Stephan Porada and Helene Schlicht</p>
</div>
<div class="col s12 m7">
<p>&nbsp;</p>
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s3">
<p>&nbsp;</p>
<img class="responsive-img" src="https://www.uni-bielefeld.de/sfb1288/images/Logo_SFB1288_DE_300dpi.png">
</div>
<div class="col s9">
<p>nopaque is a web application that helps to convert heterogeneous textual source material into standard-compliant research data for subsequent analysis. nopaque is designed to accompany your research process.</p>
<p>The web application is developed within the DFG-funded Collaborative Research Center (SFB) 1288 "Practices of Comparison" by the subproject INF "Data Infrastructure and Digital Humanities".</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="parallax-container">
<img src="{{ url_for('static', filename='images/parallax_hq/books_antique_book_old.jpg') }}" width="100%" alt="" style="margin-top: -200px;">
</div>
<div class="section white scrollspy" id="information">
<div class="row container">
<div class="col s12">
<div class="row">
<div class="col s12">
<h3>Why you should use nopaque</h3>
<p>nopaque is a custom-built web application for researchers who want to get out more of their images and texts without having to bother about the technical side of things. You can focus on what really interests you, nopaque does the rest.</p>
<p>nopaques utilization of container virtualization guarantees high interoperability, reusability and reproducibility of research results. All processing steps are carried out in containers created on demand, based on static images with fixed software versions including all dependencies.</p>
</div>
<div class="col s12">
<div class="row">
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">flash_on</i>
<p>Speeds up your work</p>
<p class="light">All tools provided by nopaque are carefully selected to provide a complete tool suite without being held up by compatibility issues.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">cloud</i>
<p>Cloud infrastructure</p>
<p class="light">All computational work is processed within nopaques cloud infrastructure. You don't need to install any software. Great, right?</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">group</i>
<p>User friendly</p>
<p class="light">You can start right away without having to read mile-long manuals. All services come with default settings that make it easy for you to just get going. Also great, right?</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">settings</i>
<p>Meshing processes</p>
<p class="light">No matter where you step in, nopaque facilitates and accompanies your research. Its workflow perfectly ties in with your research process.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="parallax-container">
<img src="{{ url_for('static', filename='images/parallax_hq/concept_document_focus_letter.jpg') }}" width="100%" alt="" style="margin-top: -350px;">
</div>
<div class="section white scrollspy" id="services">
<div class="row container">
<div class="col s12">
<div class="row">
<div class="col s12">
<h3>What nopaque can do for you</h3>
<p>All services and processes are logically linked and built upon each other. You can follow them step by step or directly choose the one that suits your needs best. And while the process is computed in nopaques cloud infrastructure, you can just keep working.</p>
</div>
<div class="col s12">
<br class="hide-on-small-only">
<div class="row">
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">burst_mode</i>
<p>File setup</p>
<p class="light">Digital copies of text based research data (books, letters, etc.) often comprise various files and formats. nopaque converts and merges those files to facilitate further processing and the application of other services.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">find_in_page</i>
<p>Optical Character Recognition</p>
<p class="light">nopaque converts your image data like photos or scans into text data through OCR making it machine readable. This step enables you to proceed with further computational analysis of your documents.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">format_textdirection_l_to_r</i>
<p>Natural Language Processing</p>
<p class="light">By means of computational linguistic data processing (tokenization, lemmatization, part-of-speech tagging and named-entity recognition) nopaque extracts additional information from your text.</p>
</div>
<div class="col s12 m6 l3 center-align">
<i class="large material-icons" style="color: #ee6e73;">search</i>
<p>Corpus analysis</p>
<p class="light">nopaque lets you create and upload as many text corpora as you want. It makes use of CQP Query Language, which allows for complex search requests with the aid of metadata and NLP tags.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="parallax-container">
<img src="{{ url_for('static', filename='images/parallax_hq/text_data_wide.png') }}" width="100%" alt="" style="margin-top: -450px;">
</div>
<div class="section white scrollspy" id="registration-and-log-in">
<div class="row container">
<div class="col s12">
<div class="row">
<!--
<div class="col s12 m4">
<h3>Registration and Log in</h3>
<p>Want to boost your research and get going? nopaque is free and no download is needed. Register now!</p>
<a class="btn waves-effect waves-light" href="{{ url_for('auth.register') }}"><i class="material-icons left">person_add</i>Register</a>
</div>-->
<div class="col s12">
<div class="card">
<form method="POST">
{{ login_form.hidden_tag() }}
<div class="card-content">
<span class="card-title">Registration and Log in</span>
<div class="input-field">
<i class="material-icons prefix">person</i>
{{ login_form.user(class='validate') }}
{{ login_form.user.label }}
{% for error in login_form.user.errors %}
<span class="helper-text red-text">{{ error }}</span>
{% endfor %}
</div>
<div class="input-field">
<i class="material-icons prefix">vpn_key</i>
{{ login_form.password(class='validate') }}
{{ login_form.password.label }}
{% for error in login_form.password.errors %}
<span class="helper-text red-text">{{ error }}</span>
{% endfor %}
</div>
<div class="row" style="margin-bottom: 0;">
<div class="col s6 left-align">
<a href="{{ url_for('auth.reset_password_request') }}">Forgot your password?</a>
|
<a href="{{ url_for('auth.reset_password_request') }}">No account yet?</a>
</div>
<div class="col s6 right-align">
{{ materialize.submit_button(login_form.submit) }}
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,9 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<h3>Privacy policy</h3>
{% endblock %}

View File

@ -1,243 +0,0 @@
{% import "macros/materialize.html.j2" as M %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="theme-color" content="#ee6e73">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
nopaque
{% if title and request.path != url_for('main.index') %}
{{ title }}
{% endif %}
</title>
<link rel="icon" href="{{ url_for('static', filename='images/nopaque_logo.png') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='fonts/Material_design_icons/material-icons.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/Materialize/materialize.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/nopaque.css') }}">
{% if current_user.is_authenticated %}
<style>
/*
* ### Start sidenav-fixed offset ###
* 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)
}
}
/* ### End sidenav-fixed offset ### */
</style>
{% endif %}
<script src="{{ url_for('static', filename='js/JSONPatch.js/jsonpatch.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/Dark_Reader/darkreader.js') }}"></script>
<script src="{{ url_for('static', filename='js/List.js/list.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/Socket.IO/socket.io.slim.js') }}"></script>
<script src="{{ url_for('static', filename='js/nopaque.js') }}"></script>
<script src="{{ url_for('static', filename='js/nopaque.lists.js') }}"></script>
<script>
{% if current_user.is_authenticated %}
{% if current_user.setting_dark_mode %}
DarkReader.enable({"brightness": 150, "contrast": 100, "sepia": 0});
{% endif %}
document.addEventListener("DOMContentLoaded", () => {
nopaque.socket.init();
nopaque.socket.emit("user_data_stream_init");
});
{% endif %}
nopaque.flashedMessages = {{ get_flashed_messages(with_categories=True)|tojson }};
</script>
</head>
<body>
<header>
<div class="navbar-fixed">
<nav>
<div class="nav-wrapper">
<a href="{{ url_for('main.index') }}" class="brand-logo center"><i class="material-icons">opacity</i>nopaque</a>
{% if current_user.is_authenticated %}
<a href="#" data-target="sidenav-main" class="sidenav-trigger"><i class="material-icons">menu</i></a>
{% endif %}
<ul class="right">
<!--<li><a id="nav-notifications" class="dropdown-trigger no-autoinit" href="#!" data-target="nav-notifications-dropdown"><i class="material-icons">notifications</i></a></li>-->
<li>
<a id="nav-account" class="dropdown-trigger no-autoinit" href="#!" data-target="nav-account-dropdown">
{% if current_user.is_authenticated %}
{{ current_user.username }}<i class="material-icons right">account_circle</i>
{% else %}
<i class="material-icons">account_circle</i>
{% endif %}
</a>
</li>
</ul>
</div>
</nav>
</div>
<!-- Dropdown menus for the navbar -->
<div id="nav-notifications-dropdown" class="dropdown-content grey-text text-darken-4">
<p>Notifications</p>
</div>
<ul id="nav-account-dropdown" class="dropdown-content">
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('profile.settings') }}"><i class="material-icons">settings</i>Settings</a></li>
<li><a href="{{ url_for('auth.logout') }}"><i class="material-icons">power_settings_new</i>Log out</a></li>
{% else %}
<li><a href="{{ url_for('auth.login') }}"><i class="material-icons">person</i>Log in</a></li>
<li><a href="{{ url_for('auth.register') }}"><i class="material-icons">person_add</i>Register</a></li>
{% endif %}
</ul>
<ul id="sidenav-main" class="sidenav sidenav-fixed{% if not current_user.is_authenticated %} hide{% endif %}">
<li><a href="{{ url_for('main.index') }}"><i class="material-icons">opacity</i>nopaque</a></li>
<li><a href="#"><i class="material-icons">linear_scale</i>Workflow</a></li>
<li><a href="{{ url_for('main.dashboard') }}"><i class="material-icons">dashboard</i>Dashboard</a></li>
<li><a href="{{ url_for('main.dashboard', _anchor='corpora') }}" style="padding-left: 47px;"><i class="material-icons">book</i>My Corpora</a></li>
<li><a href="{{ url_for('main.dashboard', _anchor='jobs') }}" style="padding-left: 47px;"><i class="material-icons">work</i>My Jobs</a></li>
<li><div class="divider"></div></li>
<li><a class="subheader">Processes and Services</a></li>
<li><a href="{{ url_for('services.service', service='file-setup') }}"><i class="material-icons">burst_mode</i>File setup</a></li>
<li><a href="{{ url_for('services.service', service='ocr') }}"><i class="material-icons">find_in_page</i>OCR</a></li>
<li><a href="{{ url_for('services.service', service='nlp') }}"><i class="material-icons">format_textdirection_l_to_r</i>NLP</a></li>
<li><a href="{{ url_for('services.service', service='corpus_analysis') }}"><i class="material-icons">search</i>Corpus analysis</a></li>
<li><div class="divider"></div></li>
<li><a class="subheader">Account</a></li>
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('profile.settings') }}"><i class="material-icons">settings</i>Settings</a></li>
<li><a href="{{ url_for('auth.logout') }}"><i class="material-icons">power_settings_new</i>Log out</a></li>
{% else %}
<li><a href="{{ url_for('auth.login') }}"><i class="material-icons">person</i>Log in</a></li>
<li><a href="{{ url_for('auth.register') }}"><i class="material-icons">person_add</i>Register</a></li>
{% endif %}
{% if current_user.is_administrator() %}
<li><div class="divider"></div></li>
<li><a class="subheader">Administration</a></li>
<li><a href="{{ url_for('admin.index') }}"><i class="material-icons">build</i>Administration tools</a></li>
{% endif %}
</ul>
</header>
{%- macro insert_page_content() -%}
{% block page_content %}{% endblock %}
{%- endmacro -%}
{% if parallax %}
<main>
{{ insert_page_content() }}
</main>
{% else %}
<main class="grey lighten-5">
{% if not full_width %}
<div class="container">
{% endif %}
<div class="row">
<div class="col s12">
<h2>
{% if headline %}
{{ headline }}
{% elif title %}
{{ title }}
{% else %}
Unnamed page
{% endif %}
</h2>
</div>
{{ insert_page_content() }}
</div>
{% if not full_width %}
</div>
{% endif %}
</div>
{% endif %}
</main>
<footer class="page-footer">
<div class="container">
<div class="row">
<div class="col s6 m3">
<a href="https://www.dfg.de/">
<img class="responsive-img" src="{{ url_for('static', filename='images/logo_-_dfg.gif') }}">
</a>
</div>
<div class="col s6 m3 offset-m1 center-align">
<a href="https://www.uni-bielefeld.de/sfb1288/">
<img class="responsive-img" src="{{ url_for('static', filename='images/logo_-_sfb_1288.png') }}">
</a>
</div>
<div class="col s12 m3 offset-m1">
<h5 class="white-text">Legal Notice</h5>
<ul>
<li><a class="grey-text text-lighten-3" href="https://www.uni-bielefeld.de/(en)/impressum/">Legal Notice</a> / <a class="grey-text text-lighten-3">Privacy statement</a></li>
<li><a class="grey-text text-lighten-3">Terms of use</a></li>
<li></li>
</ul>
</div>
</div>
</div>
<div class="footer-copyright">
<div class="container">
<div class="row" style="margin-bottom: 0;">
<div class="col s12 m2">
<span>© 2020 Bielefeld University</span>
</div>
<div class="col s12 m10 right-align">
<a class="btn-small pink waves-effect waves-light" href="mailto:{{ config.NOPAQUE_CONTACT }}?subject={{ config.NOPAQUE_MAIL_SUBJECT_PREFIX }} Contact"><i class="left material-icons">rate_review</i>Contact</a>
<a class="btn-small green waves-effect waves-light" href=""><i class="left material-icons">feedback</i>Feedback</a>
<a class="btn-small orange waves-effect waves-light" href="https://gitlab.ub.uni-bielefeld.de/sfb1288inf/opaque"><i class="left material-icons">code</i>GitLab</a>
</div>
</div>
</div>
</div>
</footer>
<!--
<footer class="page-footer">
<div class="container">
<div class="row">
<div class="col s12 m3">
<a href="https://www.dfg.de/">
<img class="responsive-img" src="{{ url_for('static', filename='images/logo_-_dfg.gif') }}">
</a>
</div>
<div class="col s12 m6">
<h5 class="white-text" style="margin-left: -15px;">Contact</h5>
<div class="row">
<p>Contact our interdisciplinary team via email: <b>inf_sfb1288@lists.uni-bielefeld.de</b></p>
<p>Silke Schwandt (Digital History), Johanna Vompras (Research Data Management), Julia Becker (Cultural Studies), Patrick Jentsch (Cognitive Informatics), Anna Neubert (Digital Humanities), Stephan Porada (Interdisciplinary Media Studies), Helene Schlicht (History, Philosophy)
</div>
</div>
<div class="col s12 m3">
<div class="row">
<div class="col s8">
<h5 class="white-text">Reminder</h5>
<p>
Check out our website for nopaque's upcomming release:<br>
<small>www.uni-bielefeld.de/sfb1288/projekte/inf.html</small>
</p>
</div>
<div class="col s4">
<p>&nbsp;</p>
<img class="responsive-img" src="{{ url_for('static', filename='images/qr_-_inf.svg') }}">
</div>
</div>
</div>
</div>
</div>
</footer>
-->
<script src="{{ url_for('static', filename='js/Materialize/materialize.min.js') }}"></script>
</body>
</html>

View File

@ -1,136 +0,0 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<div class="col s12 m4">
<h3>General settings</h3>
</div>
<div class="col s12 m8">
<br class="hide-on-small-only">
<div class="card">
<form method="POST">
<div class="card-content">
{{ edit_general_settings_form.hidden_tag() }}
<div class="row">
<div class="col s9">
<p><i class="material-icons left">brightness_3</i>{{ edit_general_settings_form.dark_mode.label.text }}</p>
<p class="light">Activate dark mode to ease your eyes.</p>
</div>
<div class="col s3 right-align">
{{ M.render_field(edit_general_settings_form.dark_mode, label=False) }}
</div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 m8">
<p><i class="material-icons left">notifications</i>Job status site notifications</p>
<p class="light">Receive site notifications about job status changes.</p>
</div>
<div class="col s12 m4 right-align" style="margin-top: -1rem;">
{{ M.render_field(edit_general_settings_form.job_status_site_notifications, label=False) }}
</div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 m8">
<p><i class="material-icons left">notifications</i>Job status mail notifications</p>
<p class="light">Receive mail notifications about job status changes.</p>
</div>
<div class="col s12 m4 right-align" style="margin-top: -1rem;">
{{ M.render_field(edit_general_settings_form.job_status_mail_notifications, label=False) }}
</div>
<!--
Seperate each setting with the following two elements
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
-->
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(edit_general_settings_form.save_settings, material_icon='send') }}
</div>
</form>
</div>
</div>
<div class="col s12"></div>
<div class="col s12 m4">
<h3>Change password</h3>
</div>
<div class="col s12 m8">
<br class="hide-on-small-only">
<div class="card">
<form method="POST">
<div class="card-content">
{{ edit_password_form.hidden_tag() }}
{{ M.render_field(edit_password_form.current_password, data_length='128', material_icon='vpn_key') }}
{{ M.render_field(edit_password_form.password, data_length='128', material_icon='vpn_key') }}
{{ M.render_field(edit_password_form.password_confirmation, data_length='128', material_icon='vpn_key') }}
</div>
<div class="card-action right-align">
{{ M.render_field(edit_password_form.save_password, material_icon='send') }}
</div>
</form>
</div>
</div>
<div class="col s12"></div>
<div class="col s12 m4">
<h3>Change email</h3>
</div>
<div class="col s12 m8">
<br class="hide-on-small-only">
<div class="card">
<form method="POST">
<div class="card-content">
{{ edit_email_form.hidden_tag() }}
{{ M.render_field(edit_email_form.email, class_='validate', material_icon='email', type='email') }}
</div>
<div class="card-action right-align">
{{ M.render_field(edit_email_form.save_email, material_icon='send') }}
</div>
</form>
</div>
</div>
<div class="col s12"></div>
<div class="col s12 m4">
<h3>Delete account</h3>
</div>
<div class="col s12 m8">
<br class="hide-on-small-only">
<div class="card">
<div class="card-content">
<p>Deleting an account has the following effects:</p>
<ul>
<li>All data associated with your corpora and jobs will be permanently deleted.</li>
<li>All settings will be permanently deleted.</li>
</ul>
</div>
<div class="card-action right-align">
<a href="#delete-account-modal" class="btn modal-trigger red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</div>
<!-- Modals -->
<div class="modal" id="delete-account-modal">
<div class="modal-content">
<h4>Confirm deletion</h4>
<p>Do you really want to delete your account and all associated data? All associated corpora, jobs and files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a href="{{ url_for('profile.delete') }}" class="btn red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
{% endblock %}

View File

@ -1,48 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set headline = '<i class="material-icons left service" data-service="corpus_analysis" style="font-size: inherit;"></i>Corpus analysis' %}
{% block page_content %}
<div class="col s12 m3 push-m9">
{% include 'services/roadmap.html.j2' %}
</div>
<div class="col s12 m9 pull-m3">
<p>Nopaque lets you create and upload as many text corpora as you want. It makes use of CQP Query Language, which allows for complex search requests with the aid of metadata and NLP tags. The results can either be displayed as text or abstract visualizations.</p>
</div>
<div class="col s12">
<div class="card">
<div class="card-content" id="corpora">
<div class="input-field">
<i class="material-icons prefix">search</i>
<input id="search-corpus" class="search" type="search"></input>
<label for="search-corpus">Search corpus</label>
</div>
<table>
<thead>
<tr>
<th></th>
<th>
<span class="sort" data-sort="title">Title</span>
<span class="sort" data-sort="description">Description</span>
</th>
<th><span class="sort" data-sort="status">Status</span></th>
<th></th>
</tr>
</thead>
<tbody class="list"></tbody>
</table>
<ul class="pagination"></ul>
</div>
<div class="card-action right-align">
<a class="waves-effect waves-light btn" href="{{ url_for('corpora.add_corpus') }}">New corpus<i class="material-icons right">add</i></a>
</div>
</div>
</div>
<script>
var corpusList = new RessourceList("corpora", nopaque.corporaSubscribers,
"corpus", {page: 10});
</script>
{% endblock %}

View File

@ -1,64 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set headline = '<i class="material-icons left service" data-service="file-setup" style="font-size: inherit;"></i>File setup' %}
{% block page_content %}
<div class="col s12 m3 push-m9">
{% include 'services/roadmap.html.j2' %}
</div>
<div class="col s12 m9 pull-m3">
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12">
<div class="card-panel z-depth-0">
<span class="card-title"><i class="left material-icons">layers</i>Merge process</span>
<p>nopaque converts and merges your files in its cloud infrastructure to facilitate further processing and the application of other services. You only have to number your files in the correct order to receive a PDF file.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col s12">
<h3>Submit a job</h3>
<div class="card">
<form class="nopaque-submit-form" data-progress-modal="progress-modal">
<div class="card-content">
{{ add_job_form.hidden_tag() }}
<div class="row">
<div class="col s12 l4">
{{ M.render_field(add_job_form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 l8">
{{ M.render_field(add_job_form.description, data_length='255', material_icon='description') }}
</div>
<div class="col s12">
{{ M.render_field(add_job_form.files, accept='image/jpeg, image/png, image/tiff', placeholder='Choose your .jpeg, .png or .tiff files') }}
</div>
<div class="col s12 hide">
{{ M.render_field(add_job_form.version, material_icon='apps') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(add_job_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
<div id="progress-modal" class="modal">
<div class="modal-content">
<h4><i class="material-icons prefix">file_upload</i> Uploading files...</h4>
<div class="progress">
<div class="determinate" style="width: 0%"></div>
</div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div>
</div>
{% endblock %}

View File

@ -1,106 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set headline = '<i class="material-icons left service" data-service="nlp" style="font-size: inherit;"></i>Natural Language Processing' %}
{% block page_content %}
<div class="col s12 m3 push-m9">
{% include 'services/roadmap.html.j2' %}
</div>
<div class="col s12 m9 pull-m3">
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12 m6">
<div class="card-panel z-depth-0">
<span class="card-title"><i class="left material-icons">layers</i>Tokenization</span>
<p>Your text is split up into sentences and words, so called tokens, which can then be analyzed.</p>
</div>
</div>
<div class="col s12 m6">
<div class="card-panel z-depth-0">
<span class="card-title"><i class="left material-icons">layers</i>Lemmatization</span>
<p>All inflected forms of a word are grouped together so that it can be analyzed as a single item.</p>
</div>
</div>
<div class="col s12 m6">
<div class="card-panel z-depth-0">
<span class="card-title"><i class="left material-icons">layers</i>Part-of-speech Tagging</span>
<p>In accordance with its definition and context, each word is marked up as corresponding to a particular part of speech.</p>
</div>
</div>
<div class="col s12 m6">
<div class="card-panel z-depth-0">
<span class="card-title"><i class="left material-icons">layers</i>Named-Entity Recognition</span>
<p>Named entities are located and classified into specific categories like persons or locations.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col s12">
<h3>Submit a job</h3>
<div class="card">
<form class="nopaque-submit-form" data-progress-modal="progress-modal">
<div class="card-content">
{{ add_job_form.hidden_tag() }}
<div class="row">
<div class="col s12 l4">
{{ M.render_field(add_job_form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 l8">
{{ M.render_field(add_job_form.description, data_length='255', material_icon='description') }}
</div>
<div class="col s12 l5">
{{ M.render_field(add_job_form.files, accept='text/plain', placeholder='Choose your .txt files') }}
</div>
<div class="col s12 l4">
{{ M.render_field(add_job_form.language, material_icon='language') }}
</div>
<div class="col s12 l3">
{{ M.render_field(add_job_form.version, material_icon='apps') }}
</div>
<div class="col s12">
<span class="card-title">Preprocessing</span>
</div>
<div class="col s9">
<p>{{ add_job_form.check_encoding.label.text }}</p>
<p class="light">If the input files are not created with the nopaque OCR service or you do not know if your text files are UTF-8 encoded, check this switch. We will try to automatically determine the right encoding for your texts to process them.</p>
</div>
<div class="col s3 right-align">
<div class="switch">
<label>
{{ add_job_form.check_encoding() }}
<span class="lever"></span>
</label>
</div>
</div>
<!--
Seperate each setting with the following
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
-->
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(add_job_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
<div id="progress-modal" class="modal">
<div class="modal-content">
<h4><i class="material-icons prefix">file_upload</i> Uploading files...</h4>
<div class="progress">
<div class="determinate" style="width: 0%"></div>
</div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div>
</div>
{% endblock %}

View File

@ -1,133 +0,0 @@
{% extends "nopaque.html.j2" %}
{% set headline = '<i class="material-icons left service" data-service="ocr" style="font-size: inherit;"></i>Optical Character Recognition' %}
{% block page_content %}
<div class="col s12 m3 push-m9">
{% include 'services/roadmap.html.j2' %}
</div>
<div class="col s12 m9 pull-m3">
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12">
<div class="card-panel z-depth-0">
<span class="card-title"><i class="left material-icons">layers</i>OCR</span>
<p>In this process, nopaque converts your image data like photos or scans into text data. This step enables you to proceed with the computational analysis of your documents.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col s12">
<h3>Submit a job</h3>
<div class="card">
<form class="nopaque-submit-form" data-progress-modal="progress-modal">
<div class="card-content">
{{ add_job_form.hidden_tag() }}
<div class="row">
<div class="col s12 l4">
{{ M.render_field(add_job_form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 l8">
{{ M.render_field(add_job_form.description, data_length='255', material_icon='description') }}
</div>
<div class="col s12 l5">
{{ M.render_field(add_job_form.files, accept='application/pdf', placeholder='Choose your .pdf files') }}
</div>
<div class="col s12 l4">
{{ M.render_field(add_job_form.language, material_icon='language') }}
</div>
<div class="col s12 l3">
{{ M.render_field(add_job_form.version, material_icon='apps') }}
</div>
<div class="col s12">
<span class="card-title">Preprocessing</span>
</div>
<div class="col s9">
<p>{{ add_job_form.binarization.label.text }}</p>
<p class="light">Based on a brightness threshold pixels are converted into either black or white. It is useful to reduce noise in images. (<b>longer duration</b>)</p>
</div>
<div class="col s3 right-align">
<div class="switch">
<label>
{{ add_job_form.binarization() }}
<span class="lever"></span>
</label>
</div>
</div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s9">
<p>Page range</p>
<p class="light"></p>
</div>
<div class="col s3 right-align">
<div class="switch">
<label>
<input disabled type="checkbox">
<span class="lever"></span>
</label>
</div>
</div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s9">
<p>Page rotation</p>
<p class="light"></p>
</div>
<div class="col s3 right-align">
<div class="switch">
<label>
<input disabled type="checkbox">
<span class="lever"></span>
</label>
</div>
</div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s9">
<p>Page split</p>
<p class="light"></p>
</div>
<div class="col s3 right-align">
<div class="switch">
<label>
<input disabled type="checkbox">
<span class="lever"></span>
</label>
</div>
</div>
<!--
Seperate each setting with the following
<div class="col s12"><p>&nbsp;</p></div>
<div class="col s12 divider"></div>
<div class="col s12"><p>&nbsp;</p></div>
-->
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(add_job_form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
<div id="progress-modal" class="modal">
<div class="modal-content">
<h4><i class="material-icons left">file_upload</i>Uploading files...</h4>
<div class="progress">
<div class="determinate" style="width: 0%"></div>
</div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div>
</div>
{% endblock %}

View File

@ -1,20 +0,0 @@
<ul class="table-of-contents" id="roadmap">
<li><b>Roadmap</b></li>
<li>
<a href="{{ url_for('services.service', service='file-setup') }}">File setup</a>
</li>
<li>
<a href="{{ url_for('services.service', service='ocr') }}">Optical Character Recognition</a>
</li>
<li>
<a href="{{ url_for('services.service', service='nlp') }}">Natural Language Processing</a>
</li>
<li>
<a href="{{ url_for('services.service', service='corpus_analysis') }}">Corpus analysis</a>
</li>
</ul>
<script>
for (let entry of document.querySelectorAll(`#roadmap a`)) {
if (entry.href === window.location.href) {entry.classList.add("active");}
}
</script>