Move query_results and interactions into corpora template folder

This commit is contained in:
Stephan Porada
2020-10-08 09:48:49 +02:00
parent 5961a3f843
commit 5e221d90ad
12 changed files with 17 additions and 17 deletions

View File

@ -44,12 +44,12 @@
<div id="interactions-menu" class="row hide"
style="margin-bottom: 0px;">
{# Importing menus for query settings, export etc. #}
{% include 'interactions/infos.html.j2' %}
{% include 'interactions/export.html.j2' %}
{% include 'interactions/create.html.j2' %}
{% include 'interactions/display.html.j2' %}
{% include 'interactions/analysis.html.j2' %}
{% include 'interactions/cite.html.j2' %}
{% include 'corpora/interactions/infos.html.j2' %}
{% include 'corpora/interactions/export.html.j2' %}
{% include 'corpora/interactions/create.html.j2' %}
{% include 'corpora/interactions/display.html.j2' %}
{% include 'corpora/interactions/analysis.html.j2' %}
{% include 'corpora/interactions/cite.html.j2' %}
</div>
{% include 'tables/query_results.html.j2' %}
</div>
@ -57,7 +57,7 @@
</div>
<!-- Scroll to top element -->
{% include 'interactions/scroll_to_top.html.j2' %}
{% include 'corpora/interactions/scroll_to_top.html.j2' %}
<!-- Modals -->
{% include 'modals/show_metadata.html.j2' %}

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 @@
<!-- 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">
{{ M.render_field(display_options_form.results_per_page,
material_icon='format_list_numbered') }}
{{ M.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,61 @@
<!-- 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">
<button id="loading-matches"
class="waves-effect
waves-light
btn-flat
flat-interaction
disabled black-text"
style="color: #000 !important;"
type="submit">
<i class="material-icons left">dvr</i>
<span id="recieved-match-count"></span>/
<span id="total-match-count"></span>
matches loaded
</button>
</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,44 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<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">
{{ add_query_result_form.hidden_tag() }}
<div class="row">
<div class="col s12 m4">
{{ M.render_field(add_query_result_form.title, data_length='32', material_icon='title') }}
</div>
<div class="col s12 m8">
{{ M.render_field(add_query_result_form.description, data_length='255', material_icon='description') }}
</div>
<div class="col s12">
{{ M.render_field(add_query_result_form.file, accept='.json', placeholder='Choose your .json file') }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ M.render_field(add_query_result_form.submit, material_icon='send') }}
</div>
</div>
</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

@ -0,0 +1,241 @@
{% extends "nopaque.html.j2" %}
{% set headline = ' ' %}
{% set full_width = True %}
{% block page_content %}
{{ Macros.insert_color_scheme(corpus_analysis_color_darken) }}
<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>
<!-- Scroll to top element -->
{% include 'corpora/interactions/scroll_to_top.html.j2' %}
<!-- Modals -->
{% include 'modals/show_metadata.html.j2' %}
{% include 'modals/show_corpus_files.html.j2' %}
{% include 'modals/context_modal.html.j2' %}
<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.
*/
document.addEventListener("DOMContentLoaded", () => {
/**
* 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,118 @@
{% extends "nopaque.html.j2" %}
{% block page_content %}
<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-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('query_results.inspect_query_result', query_result_id=query_result.id) }}">Inspect Results<i class="material-icons right">search</i></a>
</div>
</div>
</div>
<!-- Modal Structure -->
<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>
<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 %}