Change directory structure (move ./nopaque/* to ./)

This commit is contained in:
Patrick Jentsch
2021-07-20 15:07:42 +02:00
parent ff39d8d650
commit d6ab379418
231 changed files with 26 additions and 23 deletions

View File

@ -0,0 +1,28 @@
{% set breadcrumbs %}
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
<li class="tab"><a href="{{ url_for('main.dashboard', _anchor='jobs') }}" target="_self">My corpora</a></li>
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
{% if request.path == url_for('.add_corpus') %}
<li class="tab"><a class="active" href="{{ url_for('.add_corpus') }}" target="_self">{{ title }}</a></li>
{% elif request.path == url_for('.import_corpus') %}
<li class="tab"><a class="active" href="{{ url_for('.import_corpus') }}" target="_self">{{ title }}</a></li>
{% elif request.path == url_for('.corpus', corpus_id=corpus.id) %}
<li class="tab"><a class="active" href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li>
{% elif request.path == url_for('.analyse_corpus', corpus_id=corpus.id) %}
<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li>
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
<li class="tab"><a class="active" href="{{ url_for('.analyse_corpus', corpus_id=corpus.id) }}" target="_self">{{ title }}</a></li>
{% elif request.path == url_for('.add_corpus_file', corpus_id=corpus.id) %}
<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li>
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id, _anchor='files') }}" target="_self">Corpus files</a></li>
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
<li class="tab"><a class="active" href="{{ url_for('.add_corpus_file', corpus_id=corpus.id) }}" target="_self">{{ title }}</a></li>
{% elif request.path == url_for('.corpus_file', corpus_file_id=corpus_file.id, corpus_id=corpus.id) %}
<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li>
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id, _anchor='files') }}" target="_self">Corpus files</a></li>
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
<li class="tab"><a class="active" href="{{ url_for('.corpus_file', corpus_file_id=corpus_file.id, corpus_id=corpus.id) }}" target="_self">{{ corpus_file.author }}: {{ corpus_file.title }} ({{ corpus_file.publishing_year }})</a></li>
{% endif %}
{% endset %}

View File

@ -0,0 +1,41 @@
{% extends "base.html.j2" %}
{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
<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">
{{ form.hidden_tag() }}
<div class="row">
<div class="col s12 m4">
{{ wtf.render_field(form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 m8">
{{ wtf.render_field(form.description, data_length='255', material_icon='description') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ wtf.render_field(form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,86 @@
{% extends "base.html.j2" %}
{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
<div class="col s12 m4">
<p>Fill out the following form to add a corpus file in verticalized text format (.vrt).</p>
<p><b>Do not use the .stand-off.vrt file!</b></p>
</div>
<div class="col s12 m8">
<form class="nopaque-submit-form" data-progress-modal="progress-modal">
<div class="card">
<div class="card-content">
{{ form.hidden_tag() }}
<div class="row">
<div class="col s12 m4">
{{ wtf.render_field(form.author, data_length='255', material_icon='person') }}
</div>
<div class="col s12 m4">
{{ wtf.render_field(form.title, data_length='255', material_icon='title') }}
</div>
<div class="col s12 m4">
{{ wtf.render_field(form.publishing_year, material_icon='access_time') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.file, accept='.vrt', placeholder='Choose your .vrt file') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ wtf.render_field(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 form
if field.short_name not in ['author', 'csrf_token', 'file', 'publishing_year', 'submit', 'title'] %}
{{ wtf.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>
</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

@ -0,0 +1,337 @@
{% extends "base.html.j2" %}
{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="row">
<div class="col s12">
<div class="card">
<div class="card-content" style="padding-top: 5px;
padding-bottom: 0px;">
<!-- Query form -->
<div class="row">
<form class="col s12" id="query-form">
<div class="row">
<div class="input-field col s12 m10">
<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/" target="_blank">
<i class="material-icons" style="font-size: inherit;">help
</i>
CQP query language tutorial
</a>
</span>
</div>
<div class="col s12 m2 right-align" style="margin-top: 1.75em;">
<a class="waves-effect waves-light btn modal-trigger" href="#query-builder-modal"><i class="material-icons left">build</i> Query builder</a>
{{ wtf.render_field(query_form.submit, material_icon='send') }}
</div>
</div>
</form>
</div>
</div>
</div>
</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;">
<div id="interactions-menu" class="row hide"
style="margin-bottom: 0px;">
{# Importing menus for query settings, export etc. #}
{% include 'corpora/interactions/infos.html.j2' %}
{% include 'corpora/interactions/export.html.j2' %}
{% include 'corpora/interactions/create.html.j2' %}
{% include 'corpora/interactions/display.html.j2' %}
</div>
{% include 'tables/query_results.html.j2' %}
</div>
</div>
</div>
</div>
<!-- Scroll to top element -->
{% include 'corpora/interactions/scroll_to_top.html.j2' %}
<!-- Modals -->
{% include 'modals/query_builder.html.j2' %}
{% include 'modals/show_metadata.html.j2' %}
{% include 'modals/analysis_init.html.j2' %}
{% include 'modals/export_query_results.html.j2' %}
{% include 'modals/context_modal.html.j2' %}
{% include 'modals/show_corpus_files.html.j2' %}
{% endblock page_content %}
{% block scripts %}
{{ super() }}
<!-- import modules -->
<script type="module">
/**
* First Phase:
* Document content is loaded and scripts are being imported and executed.
*/
// Import Client classes. Client handles the server client communication.
import {
Client,
ClientEventListener,
ListenerCallback,
} from '../../static/js/modules/corpus_analysis/client/Client.js';
/**
* Import Client listener functions which will listen for defined socket or
* javascript events.
*/
import {
recieveConnected,
recieveMetaData,
recieveQueryStatus,
recieveQueryData,
recieveViewNotification,
recieveResultsData,
} from '../../static/js/modules/corpus_analysis/client/listeners.js';
// Import client listener callbacks so they can be registered to the listeners.
import {
prepareQueryData,
saveQueryData,
saveMetaData,
getResultsData,
saveResultsData,
} from '../../static/js/modules/corpus_analysis/client/callbacks.js';
// Import Results class which will be used to save results data of a query etc.
import {
Results,
} from '../../static/js/modules/corpus_analysis/model/Results.js';
/**
* Import the ResultsList which can be understood as a View class that handles
* how the data from Results is represented to the user. The ViewEventListener
* is used to register listener functions which listen for events emitred by
* the Client.
*/
import {
ResultsList,
ViewEventListener,
} from '../../static/js/modules/corpus_analysis/view/ResultsView.js';
// Import listener which will be registered to the ViewEventListener class.
import {
// listener listening for client dispatched 'notify-vie' custom event.
recieveClientNotification,
// vanilla javascript Event listeners which are listening for button clicks.
pageNavigation,
expertModeSwitch,
actionButtons,
displayOptions,
showMetaData,
showCorpusFiles,
exportFullContextSwitch,
createFullResults,
createSubResults,
exportFullResults,
exportSubResults,
exportSingleMatch,
} from '../../static/js/modules/corpus_analysis/view/listeners.js';
// Import script that implements the scroll to top button.
import {
scrollToTop,
} from '../../static/js/modules/corpus_analysis/view/scrollToTop.js';
// vanilla javascript Event listeners which are listening for button clicks etc
/**
* Second Phase:
* Asynchronus and event driven code.
*/
document.addEventListener("DOMContentLoaded", () => {
// Initialize the client for server client communication in dynamic mode
let corpusId = {{ corpus.id }}
const client = new Client({'corpusId': corpusId,
'socket': nopaque.appClient.socket,
'logging': true,
'dynamicMode': true});
/**
* Initializing the results object as a model holding all the data of a
* query. Also holds the metadata of one query and results data.
* After that initialize the ResultsList object as the View handeling the
* representation of the data for the user.
*/
let results = new Results();
let resultsList = new ResultsList('result-list', ResultsList.options);
/**
* Register listeners listening to socket.io events and their callbacks
* Afterwards load them. Also registers listeners listening for custom
* javascript events emitted by the View.
*/
const listenForConnected = new ClientEventListener('corpus_analysis_init',
recieveConnected);
const listenForMetaData = new ClientEventListener('corpus_analysis_meta_data',
recieveMetaData);
const metaDataCallback = new ListenerCallback('corpus_analysis_meta_data',
saveMetaData,
[client, results]);
listenForMetaData.setCallbacks([metaDataCallback]);
const listenForQueryStatus = new ClientEventListener('corpus_analysis_query',
recieveQueryStatus);
const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
prepareQueryData,
[client, results]);
listenForQueryStatus.setCallbacks([queryStatusCallback]);
const listenForQueryData = new ClientEventListener('corpus_analysis_query_results',
recieveQueryData);
const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
saveQueryData,
[client, results]);
listenForQueryData.setCallbacks([queryDataCallback]);
const listenForResults = new ClientEventListener('corpus_analysis_get_match_with_full_context',
recieveResultsData);
const resultsDataCallback = new ListenerCallback('corpus_analysis_get_match_with_full_context',
saveResultsData,
[client, results]);
listenForResults.setCallbacks([resultsDataCallback]);
// Listen for javascript custom notifications emitted by the View.
const listenForViewNotification = new ClientEventListener('notify-client',
recieveViewNotification);
const getResultsCallback = new ListenerCallback('get-results',
getResultsData,
[client, results]);
listenForViewNotification.setCallbacks([getResultsCallback]);
client.setSocketEventListeners([listenForConnected,
listenForQueryStatus,
listenForQueryData,
listenForMetaData,
listenForViewNotification,
listenForResults]);
// Load the listeners so that they will be executed if triggered
client.loadSocketEventListeners();
/**
* Register resultsList listeners listening to notification events emitted by
* the Client class.
*/
const listenForClientNotification = new ViewEventListener('notify-view',
recieveClientNotification);
/**
* Register vanilla Javascript events to the resultList listening for button
* clicks etc. done by the user.
* Get all needed HTMLElements for those event listeners before.
*/
resultsList.getHTMLElements([
'.pagination',
'#display-options-form-expert_mode',
'#display-options-form-result_context',
'#display-options-form-results_per_page',
'#download-results-json',
'#full-results-create',
'#full-results-export',
'#inspect-results-export',
'#meta-data-modal-content',
['#meta-data-modal', {
'preventScrolling': false,
'opacity': 0.0,
'dismissible': false,
'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()})
}
],
['#query-results-download-modal', {}],
'#query-results-table',
'#show-meta-data',
'#show-corpus-files',
'#show-corpus-files-modal-content',
['#show-corpus-files-modal', {
'preventScrolling': false,
'opacity': 0.0,
'dismissible': false,
'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()})
}
],
'#sub-results-create',
'#sub-results-export',
'#export-full-inspect-context',
]);
let args = [resultsList, results, client];
const listenForPageNavigation = new ViewEventListener('page-navigation',
pageNavigation,
args);
const listenForExpertModeSwitch = new ViewEventListener('expert-mode',
expertModeSwitch,
args);
const listenForActionButtons = new ViewEventListener('action-buttons',
actionButtons,
args);
const listenForDisplayOptions = new ViewEventListener('display-otions',
displayOptions,
args);
const listenForShowMetaData = new ViewEventListener('show-meta-data',
showMetaData,
args);
const listenForShowCorpusFiles = new ViewEventListener('show-corpus-files',
showCorpusFiles,
args);
const listenForExportFullContextSwitch = new ViewEventListener('export-full-context-switch',
exportFullContextSwitch,
args);
const listenForCreateFullResults = new ViewEventListener('create-full-results',
createFullResults,
args);
const listenForCreateSubResults = new ViewEventListener('create-sub-results',
createSubResults,
args);
const listenForExportFullResults = new ViewEventListener('export-full-results',
exportFullResults,
args);
const listenForExportSubResults = new ViewEventListener('export-sub-results',
exportSubResults,
args);
const listenForExportSingleMatch = new ViewEventListener('export-single-match',
exportSingleMatch,
args);
// Set and load defined listeners
resultsList.setViewEventListeners([
listenForClientNotification,
listenForPageNavigation,
listenForExpertModeSwitch,
listenForActionButtons,
listenForDisplayOptions,
listenForShowMetaData,
listenForShowCorpusFiles,
listenForExportFullContextSwitch,
listenForCreateFullResults,
listenForCreateSubResults,
listenForExportFullResults,
listenForExportSubResults,
listenForExportSingleMatch,
]);
resultsList.loadViewEventListeners();
// Connect client to server.
client.notifyView('connecting');
client.connect();
// Send a query and recieve its answer data.
let queryFormElement = document.querySelector('#query-form');
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 e.g.: 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.
*/
let firstPageElement = document.querySelector('a.page');
firstPageElement.click();
} catch (e) {
// No page element is present if first query is submitted.
}
// 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);
});
// Enable scroll to Top functionality.
scrollToTop('header', '#menu-scroll-to-top-div');
});
</script>
{% endblock %}

View File

@ -0,0 +1,125 @@
{% extends "base.html.j2" %}
{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12" data-corpus-id="{{ corpus.id }}" data-user-id="{{ corpus.creator.id }}" id="corpus-display">
<div class="row">
<div class="col s8 m9 l10">
<h1 id="title"><span class="corpus-title"></span></h1>
</div>
<div class="col s4 m3 l2 right-align">
<p>&nbsp;</p>
<p>&nbsp;</p>
<span class="chip status status-color status-text white-text"></span>
<div class="active preloader-wrapper small status-spinner">
<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>
<div class="card service-color-border border-darken" data-service="corpus-analysis" style="border-top: 10px solid">
<div class="card-content">
<div class="row">
<div class="col s12">
<div class="input-field">
<input class="corpus-description" disabled id="corpus-description" type="text">
<label for="corpus-description">Description</label>
</div>
</div>
<div class="col s12 m6">
<div class="input-field">
<input class="corpus-creation-date validate" disabled id="corpus-creation-date" type="text">
<label for="corpus-creation-date">Creation date</label>
</div>
</div>
<div class="col s12 m6">
<div class="input-field">
<input class="corpus-last-edited-date validate" disabled id="corpus-last-edited-date" type="text">
<label for="corpus-last-edited-date">Last edited</label>
</div>
</div>
<div class="col s12 m6">
<div class="input-field">
<input class="corpus-token-ratio validate" disabled id="corpus-token-ratio" type="text">
<label for="corpus-token-ratio">Nr. of tokens used <sup><i class="material-icons tooltipped tiny" data-position="bottom" data-tooltip="Current number of tokens in this corpus. Updates after every analyze session.">help</i></sup></label>
</div>
</div>
</div>
</div>
<div class="card-action right-align">
<a class="analyse-corpus-trigger btn disabled waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">search</i>Analyze</a>
<a class="btn build-corpus-trigger disabled waves-effect waves-light" href="{{ url_for('corpora.prepare_corpus', corpus_id=corpus.id) }}"><i class="nopaque-icons left">K</i>Build</a>
<a class="btn disabled export-corpus-trigger waves-effect waves-light"><i class="material-icons left">import_export</i>Export</a>
<a class="btn modal-trigger red waves-effect waves-light" data-target="delete-corpus-modal"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
<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 <span class="corpus-title"></span>? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a class="btn modal-close waves-effect waves-light" href="#!">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('corpora.delete_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</div>
<div class="col s12" id="corpus-files" data-corpus-id="{{ corpus.id }}" data-user-id="{{ corpus.creator.id }}">
<div class="card">
<div class="card-content">
<span class="card-title" id="files">Corpus files</span>
<div class="input-field">
<i class="material-icons prefix">search</i>
<input class="search" id="search-corpus-files" type="search"></input>
<label for="search-corpus-files">Search corpus files</label>
</div>
<table class="highlight responsive-table">
<thead>
<tr>
<th class="sort" data-sort="filename">Filename</th>
<th class="sort" data-sort="author">Author</th>
<th class="sort" data-sort="title">Title</th>
<th class="sort" data-sort="publishing-year">Publishing year</th>
<th></th>
</tr>
</thead>
<tbody class="list"></tbody>
</table>
<ul class="pagination"></ul>
</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>
</div>
</div>
{% endblock page_content %}
{% block scripts %}
{{ super() }}
<script>
nopaque.appClient.loadUser({{ corpus.creator.id }});
let corpusDisplay = new CorpusDisplay(document.querySelector('#corpus-display'));
let corpusFileList = new CorpusFileList(document.querySelector('#corpus-files'));
</script>
{% endblock scripts %}

View File

@ -0,0 +1,51 @@
{% extends "base.html.j2" %}
{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ corpus_file.author }}: {{ corpus_file.title }} ({{ corpus_file.publishing_year }})</h1>
</div>
<div class="col s12">
<form method="POST">
{{ form.hidden_tag() }}
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12 m4">
{{ wtf.render_field(form.author, data_length='255', material_icon='person') }}
</div>
<div class="col s12 m4">
{{ wtf.render_field(form.title, data_length='255', material_icon='title') }}
</div>
<div class="col s12 m4">
{{ wtf.render_field(form.publishing_year, material_icon='access_time') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ wtf.render_field(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 form
if field.short_name not in ['author', 'csrf_token', 'publishing_year', 'submit', 'title'] %}
{{ wtf.render_field(field, data_length='255', material_icon=field.label.text[0:1]) }}
{% endfor %}
</div>
</li>
</ul>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,58 @@
{% extends "base.html.j2" %}
{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
<div class="col s12 m4">
<p>Fill out the following form to import a corpus.</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">
<form class="nopaque-submit-form" data-progress-modal="progress-modal">
<div class="card">
<div class="card-content">
{{ form.hidden_tag() }}
<div class="row">
<div class="col s12 m4">
{{ wtf.render_field(form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 m8">
{{ wtf.render_field(form.description, data_length='255', material_icon='description') }}
</div>
</div>
<div class="row">
<div class="col s12">
{{ wtf.render_field(form.file, accept='.zip', placeholder='Choose your exported .zip file') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ wtf.render_field(form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
</div>
</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

@ -0,0 +1,30 @@
<!-- WIP. The user should be able to call several analysis tools from here.-->
<div class="col s12 m3 l2" id="anlysis">
<h6 style="margin-top: 0px;">Analysis</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="row">
<div class="col s12">
<button id="placeholder1"
class="waves-effect
waves-light
btn-flat
disabled
flat-interaction"
type="submit">Action One
<i class="material-icons left">cloud</i>
</button>
</div>
<div class="col s12">
<button id="placeholder2"
class="waves-effect
waves-light
btn-flat
disabled
flat-interaction"
type="submit">Action Two
<i class="material-icons left">add</i>
</button>
</div>
</div>
</div>

View File

@ -0,0 +1,30 @@
<!-- WIP. The user should be able to cite nopaque and the current service easily using these buttons.-->
<div class="col s12 m3 l2" id="cite">
<h6 style="margin-top: 0px;">Cite Nopaque</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="row">
<div class="col s12">
<button id="placeholder1"
class="waves-effect
waves-light
btn-flat
disabled
flat-interaction"
type="submit">Action One
<i class="material-icons left">cloud</i>
</button>
</div>
<div class="col s12">
<button id="placeholder2"
class="waves-effect
waves-light
btn-flat
disabled
flat-interaction"
type="submit">Action Two
<i class="material-icons left">add</i>
</button>
</div>
</div>
</div>

View File

@ -0,0 +1,24 @@
<!-- HTML to allow the user to create sub results from the current query
results.-->
<div class="col s12 m3 l2" id="create">
<h6 style="margin-top: 0px;">Create</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="row">
<div class="col s12">
<p>Add matches to Sub-Results with the
<i class="material-icons tiny">add</i>
button in the list or inspect view.
</p>
</div>
<div class="col s12">
<div class="input-field">
<p><span id="nr-marked-matches"></span> matches added for sub-results:</p>
<textarea id="sub-results-indexes-display"
class="materialize-textarea"
disabled>
</textarea>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,30 @@
{% import "materialize/wtf.html.j2" as wtf %}
<!-- HTML to allow the user to change how the results are being displayed.-->
<div class="col s12 m3 l2" id="display">
<h6 style="margin-top: 0px;">Display</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="row">
<div class="col s12">
<form id="display-options-form">
{{ wtf.render_field(display_options_form.results_per_page,
material_icon='format_list_numbered') }}
{{ wtf.render_field(display_options_form.result_context,
material_icon='short_text') }}
<div class="col s12" style="line-height: 38px;">
<div class="col s8">
{{ display_options_form.expert_mode.label.text }}
</div>
<div class="class col s4 right-align">
<div class="switch">
<label style="margin-left: -20px;">
{{ display_options_form.expert_mode() }}
<span class="lever"></span>
</label>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,79 @@
<!-- HTML to allow the user to export the current querey results in full or
the selected sub results.-->
<div class="col s12 m3 l2" id="export">
<h6 style="margin-top: 0px;">Export</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="row">
<div class="col s12" style="line-height: 38px;">
<div class="col s8">
Full context
<a class="tooltipped black-text" data-tooltip="Check this switch to
create results for the download with full context. Creating
results like this will take much longer but you will be able to
inspect your matches in detail when you import them into the query
results viewer.">
<i class="material-icons tiny">info_outline</i>
</a>
</div>
<div class="class col s4 right-align">
<div class="switch">
<label style="margin-left: -20px;">
<input type="checkbox" id="export-full-inspect-context">
<span class="lever"></span>
</label>
</div>
</div>
</div>
<div class="col s12">
<button class="waves-effect
waves-light
btn-flat
disabled
flat-interaction"
type="submit"
id="full-results-create">Create Results
<i class="material-icons left">build</i>
</button>
<button id="full-results-export"
class="waves-effect
waves-light
btn-flat
hide
flat-interaction"
type="submit">Results
<i class="material-icons left">file_download</i>
</button>
</div>
<div class="col s12">
<div class="progress hide" id="full-results-progress-bar">
<div class="determinate"></div>
</div>
</div>
<div class="col s12">
<button class="waves-effect
waves-light
btn-flat
disabled
flat-interaction"
type="submit"
id="sub-results-create">Create Sub-Results
<i class="material-icons left">build</i>
</button>
<button id="sub-results-export"
class="waves-effect
waves-light
btn-flat
hide
flat-interaction"
type="submit">Sub-Results
<i class="material-icons left">file_download</i>
</button>
</div>
<div class="col s12">
<div class="progress hide" id="sub-results-progress-bar">
<div class="determinate"></div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,59 @@
<!-- HTML for showing infos about the current query or result. Also gives
the user the abiltiy to access the meta data for the current query or
result.-->
<div class="col s12 m3 l2" id="infos">
<h6 style="margin-top: 0px;">Infos</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="row">
<div class="col s12"
style="height: 39px;
margin-top: 0px;
padding-top: 5px;
padding-left: 1.75rem;">
<span id="loading-matches"
class="black-text">
<i class="material-icons left">dvr</i>
<span id="recieved-match-count"></span>/
<span id="total-match-count"></span>
matches loaded
</span>
</div>
<div class="col s12">
<div class="progress hide" id="query-progress-bar">
<div class="determinate"></div>
</div>
</div>
<div class="col s12">
<button id="show-meta-data"
class="waves-effect
waves-light
btn-flat
flat-interaction"
type="submit">Corpus Meta Data
<i class="material-icons left">info_outline</i>
</button>
</div>
<div class="col s12">
<button id="show-corpus-files"
class="waves-effect
waves-light
btn-flat
flat-interaction"
type="submit">
<i class="material-icons left">info_outline</i>
Matches in
<span id="text-lookup-count"></span>
files
</button>
</div>
<div class="col s12">
<p class="hide" id="query-results-user-feedback">
<i class="material-icons tiny">help</i>
Server is sending your results.
Functions like "Export Results" and "Match Inspect" will be
available after all matches have been loaded.
</p>
</div>
</div>
</div>

View File

@ -0,0 +1,5 @@
<div id="menu-scroll-to-top-div" class="fixed-action-btn direction-top active hide" style="bottom: 45px; right: 24px;">
<a id="menu-scroll-to-top" class="btn btn-floating btn-large corpus-analysis-color.lighten">
<i class="material-icons">arrow_upward</i>
</a>
</div>

View File

@ -0,0 +1,12 @@
{% set breadcrumbs %}
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
<li class="tab"><a href="{{ url_for('main.dashboard', _anchor='query-results') }}" target="_self">My query results</a></li>
<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
{% if request.path == url_for('.add_query_result') %}
<li class="tab"><a class="active" href="{{ url_for('.add_query_result') }}" target="_self">{{ title }}</a></li>
{% elif request.path == url_for('.query_result', query_result_id=query_result.id) %}
<li class="tab"><a class="active" href="{{ url_for('.query_result', query_result_id=query_result.id) }}" target="_self">{{ query_result.title }}</a></li>
{% elif request.path == url_for('.inspect_query_result', query_result_id=query_result.id) %}
<li class="tab"><a class="active" href="{{ url_for('.inspect_query_result', query_result_id=query_result.id) }}" target="_self">{{ title }}</a></li>
{% endif %}
{% endset %}

View File

@ -0,0 +1,56 @@
{% extends "base.html.j2" %}
{% from "corpora/query_results/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
<div class="col s12 m4">
<p>Fill out the following form to upload and view your exported query data from the corpus analsis.</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">
<form class="nopaque-submit-form" data-progress-modal="progress-modal">
<div class="card">
<div class="card-content">
{{ form.hidden_tag() }}
<div class="row">
<div class="col s12 m4">
{{ wtf.render_field(form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 m8">
{{ wtf.render_field(form.description, data_length='255', material_icon='description') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.file, accept='.json', placeholder='Choose your .json file') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ wtf.render_field(form.submit, material_icon='send') }}
</div>
</div>
</form>
</div>
</div>
</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

@ -0,0 +1,241 @@
{% extends "base.html.j2" %}
{% from "corpora/query_results/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="row">
<div class="col s12">
<div class="card">
<div class="card-content" style="padding-top: 5px; padding-bottom: 0px;">
<!-- Query form -->
<div class="row">
<form id="query-form">
<div class="col s12 m10">
<div class="input-field">
<i class="material-icons prefix">search</i>
<input disabled value="{{ query_metadata.query|escape }}" id="disabled" type="text" class="validate">
<label for="disabled">Query</label>
</div>
</div>
<div class="col s12 m2 right-align">
<br class="hide-on-small-only">
</div>
</form>
</div>
</div>
</div>
</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;">
<div class="row" id="interactions-menu">
{% include 'corpora/interactions/infos.html.j2' %}
{% include 'corpora/interactions/display.html.j2' %}
{% include 'corpora/interactions/analysis.html.j2' %}
{% include 'corpora/interactions/cite.html.j2' %}
<div class="hide">
{# Hide those because they are not needed when inspecting results.
But some of their elements are being asked for by the client. #}
{% include 'corpora/interactions/export.html.j2' %}
{% include 'corpora/interactions/create.html.j2' %}
</div>
</div>
{% include 'tables/query_results.html.j2' %}
</div>
</div>
</div>
</div>
{# Import modals #}
{% include 'modals/show_metadata.html.j2' %}
{% include 'modals/show_corpus_files.html.j2' %}
{% include 'modals/context_modal.html.j2' %}
<!-- Scroll to top element -->
{% include 'corpora/interactions/scroll_to_top.html.j2' %}
{% endblock page_content %}
{% block scripts %}
{{ super() }}
<script type="module">
/**
* First Phase:
* Document content is loaded and scripts are being imported and executed.
*/
// Import Client classes. Client handles the server client communication.
import {
Client,
ClientEventListener,
ListenerCallback,
} from '../../../static/js/modules/corpus_analysis/client/Client.js';
/**
* Import Client listener functions which will listen for defined socket or
* javascript events.
*/
import {
recieveQueryStatus,
recieveQueryData,
} from '../../../static/js/modules/corpus_analysis/client/listeners.js';
// Import client listener callbacks so they can be registered to the listeners.
import {
prepareQueryData,
saveQueryData,
} from '../../../static/js/modules/corpus_analysis/client/callbacks.js';
// Import Results class which will be used to save results data of a query etc.
import {
Results,
} from '../../../static/js/modules/corpus_analysis/model/Results.js';
/**
* Import the ResultsList which can be understood as a View class that handles
* how the data from Results is represented to the user. The ViewEventListener
* is used to register listener functions which listen for events emitred by
* the Client.
*/
import {
ResultsList,
ViewEventListener,
} from '../../../static/js/modules/corpus_analysis/view/ResultsView.js';
// Import listener which will be registered to the ViewEventListener class.
import {
// listener listening for client dispatched 'notify-vie' custom event.
recieveClientNotification,
// vanilla javascript Event listeners which are listening for button clicks.
pageNavigation,
expertModeSwitch,
actionButtons,
displayOptions,
showMetaData,
showCorpusFiles,
} from '../../../static/js/modules/corpus_analysis/view/listeners.js';
import {
scrollToTop,
} from '../../../static/js/modules/corpus_analysis/view/scrollToTop.js'
/**
* Second Phase:
* Asynchronus and event driven code.
*/
/**
* Initializing the results object as a model holding all the data of a
* query. Also holds the metadata of one query and results data.
* After that initialize the ResultsList object as the View handeling the
* representation of the data for the user.
*/
let results = new Results();
let resultsList = new ResultsList('result-list', ResultsList.options);
// Import results data from json file.
const resultsJson = {{ query_result_file_content|tojson|safe }};
// Import metadata from DB passed to this view
const metaDataJson = {{ query_metadata|tojson|safe }};
// Initialize the client with dynamicMode set to false.
const client = new Client({'logging': true,
'dynamicMode': false,
'fullContext': metaDataJson.fullContext});
/**
* Register needed listeners and their callbacks. But we will
* just call the attached callbacks manually. Because dynamicMode is false.
*/
const listenForQueryStatus = new ClientEventListener('corpus_analysis_query',
recieveQueryStatus);
const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
prepareQueryData,
[client, results]);
listenForQueryStatus.setCallbacks([queryStatusCallback]);
const listenForQueryData = new ClientEventListener('corpus_analysis_query_results',
recieveQueryData);
const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
saveQueryData,
[client, results]);
listenForQueryData.setCallbacks([queryDataCallback]);
// Set the event listeners
client.setSocketEventListeners([
listenForQueryStatus,
listenForQueryData,
]);
/**
* Register resultsList listeners listening to notification events emitted by
* the Client class.
*/
const listenForClientNotification = new ViewEventListener('notify-view',
recieveClientNotification);
/**
* Register vanilla Javascript events to the resultList listening for button
* clicks etc. done by the user.
* Get all needed HTMLElements for those event listeners before.
*/
resultsList.getHTMLElements([
'.add-btn',
'.pagination',
'#display-options-form-expert_mode',
'#display-options-form-result_context',
'#display-options-form-results_per_page',
'#full-results-create',
'#full-results-export',
'#inspect-results-export',
'#meta-data-modal-content',
['#meta-data-modal', {
'preventScrolling': false,
'opacity': 0.0,
'dismissible': false,
'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()})
}
],
'#query-results-table',
'#show-meta-data',
'#show-corpus-files',
'#show-corpus-files-modal-content',
['#show-corpus-files-modal', {
'preventScrolling': false,
'opacity': 0.0,
'dismissible': false,
'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()})
}
],
'#sub-results-create',
'#sub-results-export',
]);
let args = [resultsList, results, client];
const listenForPageNavigation = new ViewEventListener('page-navigation',
pageNavigation,
args);
const listenForExpertModeSwitch = new ViewEventListener('expert-mode',
expertModeSwitch,
args);
const listenForActionButtons = new ViewEventListener('action-buttons',
actionButtons,
args);
const listenForDisplayOptions = new ViewEventListener('display-otions',
displayOptions,
args);
const listenForShowMetaData = new ViewEventListener('show-meta-data',
showMetaData,
args);
const listenForShowCorpusFiles = new ViewEventListener('show-corpus-files',
showCorpusFiles,
args);
// Set and load defined listeners
resultsList.setViewEventListeners([
listenForClientNotification,
listenForPageNavigation,
listenForExpertModeSwitch,
listenForActionButtons,
listenForDisplayOptions,
listenForShowMetaData,
listenForShowCorpusFiles,
]);
resultsList.loadViewEventListeners();
// Hide buttons which are not needed when just inspecting results
resultsList.inspectResultsExport.classList.add('hide');
// Execute client event listener callbacks manually because dynamicMode is false
client.eventListeners['corpus_analysis_query'].executeCallbacks([resultsJson]);
// Save meta data to results after the init callback from line above
results.metaData = metaDataJson;
client.eventListeners['corpus_analysis_query_results'].executeCallbacks([resultsJson]);
// Enable scroll to Top functionality.
scrollToTop('#headline', '#menu-scroll-to-top-div');
</script>
{% endblock %}

View File

@ -0,0 +1,131 @@
{% extends "base.html.j2" %}
{% from "corpora/query_results/_breadcrumbs.html.j2" import breadcrumbs with context %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
<div class="col s12">
<p>Below the metadata for the results from the Corpus
<i>{{ query_result.query_metadata.corpus_name }}</i> generated with the query
<i>{{ query_result.query_metadata.query }}</i> are shown.
</p>
</div>
<div class="col s12">
<div class="card">
<div class="card-action right-align">
<a class="waves-effect waves-light btn left-align" href="{{ url_for('services.service', service='corpus_analysis') }}">Back To Overview<i class="material-icons right">arrow_back</i></a>
<a class="waves-effect waves-light btn" href="{{ url_for('corpora.inspect_query_result', query_result_id=query_result.id) }}">Inspect Results<i class="material-icons right">search</i></a>
</div>
<div class="card-content" id="results">
<table class="responsive-table highlight">
<thead>
<tr>
<th>Metadata Description</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{% for pair in query_result.query_metadata|dictsort %}
<tr>
<td>{{ pair[0] }}</td>
{% if pair[0] == 'corpus_all_texts'
or pair[0] == 'text_lookup' %}
<td>
<table>
{% for key, value in pair[1].items() %}
<tr style="border-bottom: none;">
<td>
<i>{{ value['title'] }}</i> written
by <i>{{ value['author'] }}</i>
in <i>{{ value['publishing_year'] }}</i>
<a class="waves-effect
waves-light
btn
right
more-text-detials"
data-metadata-key="{{ pair[0] }}"
data-text-key="{{ key }}">More
<i class="material-icons right"
data-metadata-key="{{ pair[0] }}"
data-text-key="{{ key }}">
info_outline
</i>
</a>
</td>
</tr>
{% endfor %}
</table>
</td>
{% else %}
<td>{{ pair[1] }}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="card-action right-align">
<a class="waves-effect waves-light btn left-align" href="{{ url_for('services.service', service='corpus_analysis') }}">Back To Overview<i class="material-icons right">arrow_back</i></a>
<a class="waves-effect waves-light btn" href="{{ url_for('corpora.inspect_query_result', query_result_id=query_result.id) }}">Inspect Results<i class="material-icons right">search</i></a>
</div>
</div>
</div>
</div>
</div>
<div id="modal-text-details" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Bibliographic data</h4>
<p id="bibliographic-data"></p>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-green red btn">Close</a>
</div>
</div>
{% endblock page_content %}
{% block scripts %}
{{ super() }}
<script>
var moreTextDetailsButtons;
moreTextDetailsButtons = document.getElementsByClassName("more-text-detials");
for (var btn of moreTextDetailsButtons) {
btn.onclick = () => {
let modal = document.getElementById("modal-text-details");
modal = M.Modal.init(modal, {"dismissible": true});
modal.open();
let metadataKey = event.target.dataset.metadataKey;
let textKey = event.target.dataset.textKey;
let textData = {{ query_result.query_metadata|tojson|safe }}[metadataKey][textKey];
console.log(textData);
let bibliographicData = document.getElementById("bibliographic-data");
bibliographicData.innerHTML = "";
let table = document.createElement("table");
for (let [key, value] of Object.entries(textData)) {
table.insertAdjacentHTML("afterbegin",
`
<tr>
<td>${key}</td>
<td>${value}</td>
</tr>
`);
}
table.insertAdjacentHTML("afterbegin",
`
<thead>
<th>Description</th>
<th>Value</th>
</thead>
`)
bibliographicData.appendChild(table);
}
}
</script>
{% endblock %}