Big Corpus analysis update

This commit is contained in:
Patrick Jentsch
2021-11-16 15:23:57 +01:00
parent c1436c2a5d
commit f6c2292e03
47 changed files with 2549 additions and 1840 deletions

View File

@ -0,0 +1,102 @@
<div class="row" id="concordance-extension-container">
<div class="col s12">
<div class="card">
<div class="card-content">
<form id="concordance-extension-form">
<div class="row">
<div class="input-field col s12 m9">
<i class="material-icons prefix">search</i>
<input class="validate corpus-analysis-action" id="concordance-extension-form-query" name="query" type="text" required pattern=".*\S+.*"></input>
<label for="concordance-extension-form-query">Query</label>
<span class="error-color-text helper-text hide" id="concordance-extension-error"></span>
</div>
<div class="input-field col s12 m3">
<i class="material-icons prefix">arrow_forward</i>
<input class="validate corpus-analysis-action" id="concordance-extension-form-subcorpus-name" name="subcorpus-name" type="text" required pattern="^[A-Z][a-z0-9\-]*" value="Last"></input>
<label for="concordance-extension-form-subcorpus-name">Subcorpus name</label>
</div>
<div class="col s12 m9 l9">
<div class="row">
<div class="input-field col s4 l3">
<i class="material-icons prefix">short_text</i>
<select class="corpus-analysis-action" name="context">
<option value="10" selected>10</option>
<option value="15">15</option>
<option value="20">20</option>
<option value="25">25</option>
<option value="30">30</option>
</select>
<label>Context</label>
</div>
<div class="input-field col s4 l3">
<i class="material-icons prefix">format_list_numbered</i>
<select class="corpus-analysis-action" name="per-page">
<option value="10" selected>10</option>
<option value="15">15</option>
<option value="20">20</option>
<option value="25">25</option>
</select>
<label>Matches per page</label>
</div>
<div class="input-field col s4 l3">
<i class="material-icons prefix">format_shapes</i>
<select name="text-style">
<option value="0">Plain text</option>
<option value="1" selected>Highlight entities</option>
<option value="2">Token text</option>
</select>
<label>Text style</label>
</div>
<div class="input-field col s4 l3">
<i class="material-icons prefix">format_quote</i>
<select name="token-representation">
<option value="lemma">lemma</option>
<option value="pos">pos</option>
<option value="simple_pos">simple_pos</option>
<option value="word" selected>word</option>
</select>
<label>Token representation</label>
</div>
</div>
</div>
<div class="col s12 m3 l3 right-align">
<p class="hide-on-small-only">&nbsp;</p>
<a class="btn disabled tooltipped waves-effect waves-light" data-tooltip="Comming soon..."><i class="material-icons left">build</i> Query builder</a>
<button class="btn waves-effect waves-light corpus-analysis-action" id="concordance-extension-form-submit" type="submit" name="submit">Send <i class="material-icons right">send</i></button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="col s12">
<div id="concordance-extension-subcorpus-list"></div>
<div class="card">
<div class="card-content">
<div class="progress hide" id="concordance-extension-progress">
<div class="indeterminate"></div>
</div>
<div class="row">
<div class="col s9"><p class="hide" id="concordance-extension-subcorpus-info"></p></div>
<div class="col s3 right-align" id="concordance-extension-subcorpus-actions"></div>
</div>
<table class="highlight">
<thead>
<tr>
<th style="width: 2%;"></th>
<th style="width: 8%;">Source</th>
<th class="right-align" style="width: 22.5%;">Left context</th>
<th class="center-align" style="width: 40%;">KWIC</th>
<th class="left-align" style="width: 22.5%;">Right Context</th>
<th class="left-align" style="width: 5%;"></th>
</tr>
</thead>
<tbody id="concordance-extension-subcorpus-items"></tbody>
</table>
<ul class="pagination hide" id="concordance-extension-subcorpus-pagination"></ul>
</div>
</div>
</div>
</div>

View File

@ -1,337 +1,73 @@
{% 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 main_attribs %} class="service-scheme" data-service="corpus-analysis" id="corpus-analysis-app-container"{% endblock main_attribs %}
{% block page_content %}
<div class="row">
<ul class="row tabs no-autoinit" id="corpus-analysis-app-extension-tabs">
<li class="tab col s3"><a class="active" href="#corpus-analysis-app-overview"><i class="nopaque-icons service-icon left" data-service="corpus-analysis"></i>Corpus analysis</a></li>
<li class="tab col s3"><a href="#concordance-extension-container"><i class="material-icons left">list_alt</i>Concordance</a></li>
<li class="tab col s3"><a href="#reader-extension-container"><i class="material-icons left">chrome_reader_mode</i>Reader</a></li>
</ul>
<div class="row" id="corpus-analysis-app-overview">
<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>
<h1>{{ title }}</h1>
</div>
<div class="col s3">
<div class="card extension-selector hoverable" data-target="concordance-extension-container">
<div class="card-content">
<span class="card-title"><i class="material-icons left">list_alt</i>Concordance</span>
<p>Query your corpus with the CQP query language utilizing a KWIC view.</p>
</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 class="col s3">
<div class="card extension-selector hoverable" data-target="reader-extension-container">
<div class="card-content">
<span class="card-title"><i class="material-icons left">chrome_reader_mode</i>Reader</span>
<p>Inspect your corpus in detail with a full text view, including annotations.</p>
</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' %}
{% include "corpora/analyse_corpus.reader.html.j2" %}
{% include "corpora/analyse_corpus.concordance.html.j2" %}
{% endblock page_content %}
{% block modals %}
{{ super() }}
<div class="modal no-autoinit" id="corpus-analysis-app-init-modal">
<div class="modal-content">
<h4>Initializing session...</h4>
<p>If the loading takes to long or an error occured,
<a onclick="window.location.reload()" href="#">click here</a>
to refresh your session or
<a href="{{ url_for('corpora.corpus', corpus_id=corpus.id) }}">go back</a>!
</p>
<div class="progress" id="corpus-analysis-app-init-progress">
<div class="indeterminate"></div>
</div>
<p class="error-color-text hide" id="corpus-analysis-app-init-error"></p>
</div>
</div>
{% endblock modals %}
{% 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');
});
{% assets output="js/nopaque/CorpusAnalysis.min.bundle.js",
"js/nopaque/CorpusAnalysis/CQiClient.js",
"js/nopaque/CorpusAnalysis/CorpusAnalysisApp.js",
"js/nopaque/CorpusAnalysis/CorpusAnalysisConcordance.js",
"js/nopaque/CorpusAnalysis/CorpusAnalysisReader.js" %}
<script src="{{ ASSET_URL }}"></script>
{% endassets %}
<script>
let corpusAnalysisApp = new CorpusAnalysisApp({{ corpus.id }});
let corpusAnalysisConcordance = new CorpusAnalysisConcordance(corpusAnalysisApp);
let corpusAnalysisReader = new CorpusAnalysisReader(corpusAnalysisApp);
corpusAnalysisApp.init();
</script>
{% endblock %}
{% endblock scripts %}

View File

@ -0,0 +1,67 @@
<div class="row" id="reader-extension-container">
<div class="col s12">
<div class="card">
<div class="card-content">
<form id="reader-extension-form">
<div class="row">
<div class="col s12 m9 l10">
<div class="row">
<div class="input-field col s4 m3 l2">
<i class="material-icons prefix">format_list_numbered</i>
<select class="corpus-analysis-action" name="per-page">
<option value="500" selected>500</option>
<option value="1000">1000</option>
<option value="1500">1500</option>
</select>
<label>Tokens per page</label>
</div>
<div class="input-field col s4 m3 l2">
<i class="material-icons prefix">format_shapes</i>
<select name="text-style">
<option value="0">Plain text</option>
<option value="1" selected>Highlight entities</option>
<option value="2">Token text</option>
</select>
<label>Text style</label>
</div>
<div class="input-field col s4 m3 l2">
<i class="material-icons prefix">format_quote</i>
<select name="token-representation">
<option value="lemma">lemma</option>
<option value="pos">pos</option>
<option value="simple_pos">simple_pos</option>
<option value="word" selected>word</option>
</select>
<label>Token representation</label>
</div>
<div class="col s12">
<span class="error-color-text helper-text hide" id="reader-extension-error"></span>
</div>
</div>
</div>
<div class="col s12 m3 l2 right-align">
<p class="hide-on-small-only">&nbsp;</p>
<button class="btn hide waves-effect waves-light corpus-analysis-action" id="reader-extension-form-submit" type="submit" name="submit">Send <i class="material-icons right">send</i></button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="col s12">
<div class="card">
<div class="card-content">
<div class="progress hide" id="reader-extension-progress">
<div class="indeterminate"></div>
</div>
<table>
<tbody>
<tr><td id="reader-extension-corpus"></td></tr>
</tbody>
</table>
<ul class="pagination hide" id="reader-extension-corpus-pagination"></ul>
</div>
</div>
</div>
</div>

View File

@ -1,30 +0,0 @@
<!-- 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

@ -1,30 +0,0 @@
<!-- 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

@ -1,24 +0,0 @@
<!-- 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

@ -1,30 +0,0 @@
{% 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

@ -1,79 +0,0 @@
<!-- 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

@ -1,59 +0,0 @@
<!-- 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

@ -1,5 +0,0 @@
<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

@ -1,12 +0,0 @@
{% 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

@ -1,56 +0,0 @@
{% 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

@ -1,241 +0,0 @@
{% 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

@ -1,131 +0,0 @@
{% 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 %}

View File

@ -82,7 +82,7 @@
<ul class="pagination"></ul>
</div>
<div class="card-action right-align">
<a class="waves-effect waves-light btn" href="{{ url_for('corpora.add_query_result') }}">Add query result<i class="material-icons right">file_upload</i></a>
<a class="waves-effect waves-light btn disabled">Add query result<i class="material-icons right">file_upload</i></a>
</div>
</div>
</div>

View File

@ -31,7 +31,7 @@
{% endif %}
</label>
{% for error in field.errors %}
<span class="helper-text red-text">{{ error }}</span>
<span class="helper-text error-color-text">{{ error }}</span>
{% endfor %}
</div>
{% endmacro %}
@ -47,7 +47,7 @@
<input class="file-path validate" type="text" placeholder="{{ placeholder }}">
</div>
{% for error in field.errors %}
<span class="helper-text red-text">{{ error }}</span>
<span class="helper-text error-color-text">{{ error }}</span>
{% endfor %}
</div>
{% endmacro %}
@ -68,7 +68,7 @@
{{ field.label }}
{% endif %}
{% for error in field.errors %}
<span class="helper-text red-text">{{ error }}</span>
<span class="helper-text error-color-text">{{ error }}</span>
{% endfor %}
</div>
{% endmacro %}

View File

@ -1,21 +0,0 @@
<!-- Table showing the query results of the current query or the imported
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: 35%">Match</th>
<th style="width: 10%">{# Actions #}</th>
<th style="width: 25%">Right Context</th>
</tr>
</thead>
<tbody class="list" id="query-results-table">
</tbody>
</table>
<ul class="pagination paginationBottom"></ul>
</div>