New analysis interface

This commit is contained in:
Stephan Porada 2020-06-19 12:30:05 +02:00
parent be4377a231
commit ab61819005
7 changed files with 313 additions and 146 deletions

View File

@ -57,7 +57,8 @@ def corpus_analysis_get_meta_data(corpus_id):
texts_metadata[text_id][struct_attr.attrs['name'][(len(text_attr.attrs['name']) + 1):]] = struct_attr.values_by_ids(list(range(struct_attr.attrs['size'])))[text_id] texts_metadata[text_id][struct_attr.attrs['name'][(len(text_attr.attrs['name']) + 1):]] = struct_attr.values_by_ids(list(range(struct_attr.attrs['size'])))[text_id]
metadata['corpus_all_texts'] = texts_metadata metadata['corpus_all_texts'] = texts_metadata
metadata['corpus_analysis_date'] = datetime.utcnow().isoformat() metadata['corpus_analysis_date'] = datetime.utcnow().isoformat()
metadata['corpus_cqi_py_version'] = cqi.version metadata['corpus_cqi_py_protocol_version'] = client.api.version
metadata['corpus_cqi_py_package_version'] = cqi.__version__
metadata['corpus_cqpserver_version'] = 'CQPserver v3.4.22' # TODO: make this dynamically metadata['corpus_cqpserver_version'] = 'CQPserver v3.4.22' # TODO: make this dynamically
# write some metadata to the db # write some metadata to the db
@ -127,7 +128,6 @@ def corpus_analysis_query(query):
@socketio.on('corpus_analysis_inspect_match') @socketio.on('corpus_analysis_inspect_match')
@socketio_login_required @socketio_login_required
def corpus_analysis_inspect_match(payload): def corpus_analysis_inspect_match(payload):
payload = payload["payload"]
client = corpus_analysis_clients.get(request.sid) client = corpus_analysis_clients.get(request.sid)
if client is None: if client is None:
response = {'code': 424, 'desc': 'No client found for this session', response = {'code': 424, 'desc': 'No client found for this session',

View File

@ -63,7 +63,7 @@ class AddCorpusForm(FlaskForm):
class QueryForm(FlaskForm): class QueryForm(FlaskForm):
query = StringField('Query', query = StringField('Query',
validators=[DataRequired(), Length(1, 1024)]) validators=[DataRequired(), Length(1, 1024)])
submit = SubmitField('Send query') submit = SubmitField('Search')
class DisplayOptionsForm(FlaskForm): class DisplayOptionsForm(FlaskForm):

View File

@ -0,0 +1,33 @@
class InteractionElement {
constructor(htmlId="",
disabledBefore=true,
disabledAfter=false,
hideBefore=true,
hideAfter=false) {
this.htmlId = htmlId;
this.callbacks = {};
this.disabledBefore = disabledBefore;
this.disabledAfter = disabledAfter;
this.hideBefore = hideBefore;
this.hideAfter = hideAfter;
}
getElement() {
this.interactionStatusElement = document.getElementById(this.htmlId);
return this.interactionStatusElement
}
setCallback(trigger, callback, bindThis, args=[]) {
this.callbacks[trigger] = {
"function": callback,
"bindThis": bindThis,
"args": args
};
}
bindThisToCallback(trigger) {
let callback = this.callbacks[trigger];
let boundedCallback = callback["function"].bind(callback.bindThis);
return boundedCallback;
}
}

View File

@ -7,6 +7,7 @@ function querySetup(payload) {
// This is called when a query was successfull // This is called when a query was successfull
// some hiding and resetting // some hiding and resetting
queryResultsExportElement.classList.add("disabled"); queryResultsExportElement.classList.add("disabled");
addToSubSubcorpusElement.setAttribute("disabled", "");
queryResultsDeterminateElement.style.width = "0%"; queryResultsDeterminateElement.style.width = "0%";
queryResultsProgressElement.classList.remove("hide"); queryResultsProgressElement.classList.remove("hide");
queryResultsUserFeedbackElement.classList.remove("hide"); queryResultsUserFeedbackElement.classList.remove("hide");
@ -14,6 +15,7 @@ function querySetup(payload) {
receivedMatchCountElement.innerText = "0"; receivedMatchCountElement.innerText = "0";
textLookupCountElement.innerText = "0"; textLookupCountElement.innerText = "0";
matchCountElement.innerText = payload.match_count; matchCountElement.innerText = payload.match_count;
textTitlesElement.innterText = "";
// always re initializes results to delete old results from it // always re initializes results to delete old results from it
// this has to be done here again because the last chunk from old results was still being recieved // this has to be done here again because the last chunk from old results was still being recieved
results.clearAll() results.clearAll()
@ -53,6 +55,11 @@ function queryRenderResults(payload) {
// show user current and total match count // show user current and total match count
receivedMatchCountElement.innerText = `${results.data.matches.length}`; receivedMatchCountElement.innerText = `${results.data.matches.length}`;
textLookupCountElement.innerText = `${Object.keys(results.data.text_lookup).length}`; textLookupCountElement.innerText = `${Object.keys(results.data.text_lookup).length}`;
let titles = new Array();
for (let [key, value] of Object.entries(results.data.text_lookup)) {
titles.push(`${value.title} (${value.publishing_year})`);
};
textTitlesElement.innerText = `${titles.join(", ")}`;
console.log("Results recieved:", results.data); console.log("Results recieved:", results.data);
// upate progress status // upate progress status
progress = payload.progress; // global declaration progress = payload.progress; // global declaration
@ -60,10 +67,14 @@ function queryRenderResults(payload) {
queryResultsProgressElement.classList.add("hide"); queryResultsProgressElement.classList.add("hide");
queryResultsUserFeedbackElement.classList.add("hide"); queryResultsUserFeedbackElement.classList.add("hide");
queryResultsExportElement.classList.remove("disabled"); queryResultsExportElement.classList.remove("disabled");
addToSubSubcorpusElement.removeAttribute("disabled");
results.jsList.activateInspect(); results.jsList.activateInspect();
// inital expert mode check and sub subcorpus activation
if (addToSubSubcorpusElement.checked) {
results.jsList.activateAddToSubSubcorpus();
} }
// inital expert mode check and activation
if (expertModeSwitchElement.checked) { if (expertModeSwitchElement.checked) {
results.jsList.expertModeOn("query-display"); results.jsList.expertModeOn("query-display");
} }
}
} }

View File

@ -134,8 +134,27 @@ class ResultsList extends List {
this.currentExpertTokenElements = {}; // all token elements which have added this.currentExpertTokenElements = {}; // all token elements which have added
// classes like chip and hoverable for expert view. Collected // classes like chip and hoverable for expert view. Collected
//here to delete later on //here to delete later on
this.addToSubSubcorpuStatus = {};
} }
// handels interactionElements during a pagination navigation
pageChangeEventInteractionHandler(interactionElements) {
// get elements to check thier status
for (let interaction of interactionElements) {
let element = interaction.getElement();
if (element.checked) {
let f_on = interaction.bindThisToCallback("on");
let args_on = interaction.callbacks.on.args;
f_on(...args_on);
console.log("ON TRIGGERED");
} else {
let f_off = interaction.bindThisToCallback("off");
let args_off = interaction.callbacks.off.args;
f_off(...args_off);
console.log("OFF TRIGGERED");
}
}
}
// get display options from display options form element // get display options from display options form element
static getDisplayOptions(displayOptionsFormElement) { static getDisplayOptions(displayOptionsFormElement) {
@ -152,6 +171,40 @@ class ResultsList extends List {
return displayOptionsData return displayOptionsData
} }
// ###### Functions to add one match to a sub-subcorpus ######
// activate add button
activateAddToSubSubcorpus() {
if (progress === 100) {
let addToSubSubcorpusBtnElements = document.getElementsByClassName("add");
for (let addToSubSubcorpusBtn of addToSubSubcorpusBtnElements) {
addToSubSubcorpusBtn.classList.remove("hide");
}
}
}
// deactivate add button
deactivateAddToSubSubcorpus() {
let addToSubSubcorpusBtnElements = document.getElementsByClassName("add");
for (let addToSubSubcorpusBtn of addToSubSubcorpusBtnElements) {
addToSubSubcorpusBtn.classList.add("hide");
}
}
// add match on click to a SubSubcorpus
addToSubSubcorpus(dataIndex) {
if (!this.addToSubSubcorpuStatus[dataIndex]
|| this.addToSubSubcorpuStatus === undefined) {
event.target.classList.remove("grey");
event.target.classList.add("green");
event.target.innerText = "check";
this.addToSubSubcorpuStatus[dataIndex] = true;
console.log(dataIndex);
} else if (this.addToSubSubcorpuStatus[dataIndex]) {
event.target.classList.remove("green");
event.target.classList.add("grey");
event.target.innerText = "add";
this.addToSubSubcorpuStatus[dataIndex] = false;
}
}
// ###### Functions to inspect one match, to show more details ###### // ###### Functions to inspect one match, to show more details ######
// activate inspect buttons if progress is 100 // activate inspect buttons if progress is 100
activateInspect() { activateInspect() {
@ -167,22 +220,21 @@ class ResultsList extends List {
} }
//gets result cpos infos for one dataIndex to send back to the server //gets result cpos infos for one dataIndex to send back to the server
inspect(dataIndex) { inspect(dataIndex, type) {
this.contextId = dataIndex; this.contextId = dataIndex;
let contextResultsElement; let contextResultsElement;
contextResultsElement = document.getElementById("context-results"); contextResultsElement = document.getElementById("context-results");
contextResultsElement.innerHTML = ""; // clear it from old inspects contextResultsElement.innerHTML = ""; // clear it from old inspects
contextModal.open(); contextModal.open();
nopaque.socket.emit("corpus_analysis_inspect_match", nopaque.socket.emit("corpus_analysis_inspect_match",
{ {"type": type,
payload: {
first_cpos: results.data.matches[dataIndex].c[0], first_cpos: results.data.matches[dataIndex].c[0],
last_cpos: results.data.matches[dataIndex].c[1], last_cpos: results.data.matches[dataIndex].c[1],
} }
}
); );
} }
// create Element from HTML String helper function
HTMLTStrToElement(htmlStr) { HTMLTStrToElement(htmlStr) {
// https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518 // https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
let template = document.createElement("template"); let template = document.createElement("template");
@ -432,20 +484,6 @@ class ResultsList extends List {
} }
// ###### Expert view event functions ###### // ###### Expert view event functions ######
// Event function to check if pagination is used and then look if
// expertModeSwitchElement is checked
// if checked than expertModeOn is executed
// if unchecked expertModeOff is executed
eventHandlerCheck(event) {
if (expertModeSwitchElement.checked) {
this.expertModeOn("query-display");
} else if (!expertModeSwitchElement.checked) {
event.preventDefault();
this.expertModeOff("query-display");
}
}
// function to create a tooltip for the current hovered token // function to create a tooltip for the current hovered token
tooltipEventCreate(event) { tooltipEventCreate(event) {
// console.log("Create Tooltip on mouseover."); // console.log("Create Tooltip on mouseover.");
@ -465,8 +503,12 @@ class ResultsList extends List {
} }
expertModeOn(htmlId) { expertModeOn(htmlId) {
// torn the expert mode on for all tokens in the DOM element identified by its htmlID // turn the expert mode on for all tokens in the DOM element identified by its htmlID
this.currentExpertTokenElements[htmlId] = document.getElementById(htmlId).getElementsByClassName("token"); console.log(this);
if (!Array.isArray(this.currentExpertTokenElements[htmlId])) {
this.currentExpertTokenElements[htmlId] = [];
}
this.currentExpertTokenElements[htmlId].push( ...document.getElementById(htmlId).getElementsByClassName("token"));
this.tooltipEventCreateBind = this.tooltipEventCreate.bind(this); this.tooltipEventCreateBind = this.tooltipEventCreate.bind(this);
this.tooltipEventDestroyBind = this.tooltipEventDestroy.bind(this); this.tooltipEventDestroyBind = this.tooltipEventDestroy.bind(this);
this.eventTokens[htmlId] = []; this.eventTokens[htmlId] = [];
@ -511,6 +553,13 @@ class ResultsList extends List {
// function to remove extra informations and animations from tokens // function to remove extra informations and animations from tokens
expertModeOff(htmlId) { expertModeOff(htmlId) {
// console.log("Expert mode is off."); // console.log("Expert mode is off.");
console.log(this);
if (!Array.isArray(this.currentExpertTokenElements[htmlId])) {
this.currentExpertTokenElements[htmlId] = [];
}
if (!Array.isArray(this.eventTokens[htmlId])) {
this.eventTokens[htmlId] = [];
}
for (let tokenElement of this.currentExpertTokenElements[htmlId]) { for (let tokenElement of this.currentExpertTokenElements[htmlId]) {
tokenElement.classList.remove("chip", "hoverable", "expert-view"); tokenElement.classList.remove("chip", "hoverable", "expert-view");
} }
@ -524,6 +573,7 @@ class ResultsList extends List {
} }
createResultRowElement(item, chunk) { createResultRowElement(item, chunk) {
let addToSubSubcorpusBtn;
let c; let c;
let cCellElement; let cCellElement;
let cpos; let cpos;
@ -579,16 +629,29 @@ class ResultsList extends List {
`<span class="token" data-cpos="${cpos}">${token.word} </span>`); `<span class="token" data-cpos="${cpos}">${token.word} </span>`);
// get text titles of every hit cpos token // get text titles of every hit cpos token
textTitles.add(chunk.text_lookup[token.text].title); textTitles.add(chunk.text_lookup[token.text].title);
// add button to trigger more context to every match td
inspectBtn = document.createElement("a");
inspectBtn.setAttribute("class", `btn-floating btn-flat waves-effect` +
`waves-light grey right inspect disabled`
);
inspectBtn.innerHTML = '<i class="material-icons">search</i>';
inspectBtn.onclick = () => {this.inspect(values.index)};
} }
// add text titles at front as first td of one row // add some interaction buttons
// # some btn css rules and classes
let css = `margin-right: 10px;`
let classes = `btn-floating btn-flat waves-effect` +
`waves-light grey right`
// # add button to trigger more context to every match td
inspectBtn = document.createElement("a");
inspectBtn.setAttribute("class", classes + ` disabled inspect`
);
inspectBtn.setAttribute("style", css)
inspectBtn.innerHTML = '<i class="material-icons">search</i>';
inspectBtn.onclick = () => {this.inspect(values.index, "inspect")};
// # add btn to add matches to sub-subcorpus. hidden per default
addToSubSubcorpusBtn = document.createElement("a");
addToSubSubcorpusBtn.setAttribute("class", classes + ` hide add`
);
addToSubSubcorpusBtn.setAttribute("style", css)
addToSubSubcorpusBtn.innerHTML = '<i class="material-icons">add</i>';
addToSubSubcorpusBtn.onclick= (event) => {this.addToSubSubcorpus(values.index)}
cCellElement.appendChild(inspectBtn); cCellElement.appendChild(inspectBtn);
cCellElement.appendChild(addToSubSubcorpusBtn);
// add text titles at front as first td of one row
textTitlesCellElement.innerText = [...textTitles].join(", "); textTitlesCellElement.innerText = [...textTitles].join(", ");
matchRowElement.insertAdjacentHTML("afterbegin", textTitlesCellElement.outerHTML); matchRowElement.insertAdjacentHTML("afterbegin", textTitlesCellElement.outerHTML);
matchNrElement.innerText = values.index + 1; matchNrElement.innerText = values.index + 1;

View File

@ -1,24 +1,17 @@
{% extends "nopaque.html.j2" %} {% extends "nopaque.html.j2" %}
{% set headline = ' ' %}
{% set full_width = True %} {% set full_width = True %}
{% block page_content %} {% block page_content %}
<div class="col s12"> <div class="col s12">
<ul class="collapsible expandable"> <div class="card">
<li class="active"> <div class="card-content" style="padding-top: 5px;
<!-- <div class="collapsible-header"> padding-bottom: 0px;">
<i class="material-icons">search</i>CQP Query
</div> -->
<!-- Div element above is part of valid materialize collapsible.
Commented out to prevent the user from collapsing it and also to save
space -->
<div class="collapsible-body" style="padding-top: 10px;
padding-right: 2rem;
padding-bottom: 0px;
padding-left: 2rem;">
<!-- Query form --> <!-- Query form -->
<form id="query-form">
<div class="row"> <div class="row">
<form id="query-form">
<div class="col s12 m10"> <div class="col s12 m10">
<div class="input-field"> <div class="input-field">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
@ -33,49 +26,28 @@
</span> </span>
</div> </div>
</div> </div>
<div class="col s12 m2"> <div class="col s12 m2 right-align">
<br class="hide-on-small-only"> <br class="hide-on-small-only">
{{ M.render_field(query_form.submit, material_icon='send') }} {{ M.render_field(query_form.submit, material_icon='send') }}
</div> </div>
</div>
</form> </form>
</div> </div>
</li>
<li class="hoverable">
<div class="collapsible-header">
<i class="material-icons">settings</i>Display Options
</div>
<div class="collapsible-body">
<!-- Display options form -->
<form id="display-options-form">
<div class="row">
<div class="col s12 m6">
{{ M.render_field(display_options_form.results_per_page,
material_icon='format_list_numbered') }}
</div>
<div class="col s12 m6">
{{ M.render_field(display_options_form.result_context,
material_icon='short_text') }}
</div>
<div class="col s12">
{{ M.render_field(display_options_form.expert_mode) }}
</div> </div>
</div> </div>
</form>
</div>
</li>
</ul>
</div> </div>
<!-- entire results div/card --> <!-- entire results div/card -->
<div class="col s12" id="query-display"> <div class="col s12" id="query-display">
<div class="card"> <div class="card">
<div class="card-content" id="result-list" style="overflow: hidden;"> <div class="card-content" id="result-list" style="overflow: hidden;">
<span class="card-title">Query Results</span>
<div class="error-container hide show-on-error"></div> <div class="error-container hide show-on-error"></div>
<div class="hide show-on-success"> <div class="hide show-on-success" style="margin-top:-20px;">
<div class="col s12 m6 l6"> <div class="row" style="margin-bottom: 0px;">
<div class="row"> <div class="col s12 m3 l3" id="results-info">
<div class="row section">
<h6 style="margin-top: 0px;">Infos</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="col" id="infos">
<p> <p>
<span id="received-match-count"> <span id="received-match-count">
</span> of </span> of
@ -84,7 +56,9 @@
<br> <br>
Matches occured in Matches occured in
<span id="text-lookup-count"></span> <span id="text-lookup-count"></span>
corpus files. corpus files:
<br>
<span id=text-titles></span>
</p> </p>
<p id="query-results-user-feedback"> <p id="query-results-user-feedback">
<i class="material-icons">help</i> <i class="material-icons">help</i>
@ -92,24 +66,54 @@
Functions like "Export Results" and "Match Inspect" will be Functions like "Export Results" and "Match Inspect" will be
available after all matches have been loaded. available after all matches have been loaded.
</p> </p>
</div>
<div class="row">
<div class="progress" id="query-results-progress"> <div class="progress" id="query-results-progress">
<div class="determinate" id="query-results-determinate"></div> <div class="determinate" id="query-results-determinate"></div>
</div> </div>
</div> </div>
</div> </div>
<div class="col s12 m6 l6"> </div>
<div class="row"> <div class="col s12 m9 l9" id="actions-and-tools">
<div class="row section">
<div class="col" id="Export">
<h6 style="margin-top: 0px;">Export</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<button id="query-results-export" <button id="query-results-export"
class="waves-effect class="waves-effect
waves-light waves-light
btn-small btn-flat
right disabled" disabled"
type="submit">Export Results type="submit">Export Results
<i class="material-icons right">file_download</i> <i class="material-icons left">file_download</i>
</button> </button>
</div> </div>
<div class="col" id="Create">
<h6 style="margin-top: 0px;">Create</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<div class="switch">
Sub-Subcorpus creation:
<label>
Off
<input disabled
type="checkbox"
id="add-to-sub-subcorpus">
<span class="lever"></span>
On
</label>
</div>
</div>
<div class="col" id="Display">
<h6 style="margin-top: 0px;">Display</h6>
<div class="divider" style="margin-bottom: 10px;"></div>
<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') }}
{{ M.render_field(display_options_form.expert_mode) }}
</form>
</div>
</div>
</div>
</div> </div>
<!-- Table showing the query results --> <!-- Table showing the query results -->
<div class="col s12"> <div class="col s12">
@ -275,11 +279,15 @@
</script> </script>
<script src="{{ url_for('static', filename='js/nopaque.callbacks.js') }}"> <script src="{{ url_for('static', filename='js/nopaque.callbacks.js') }}">
</script> </script>
<script src="{{ url_for('static', filename='js/nopaque.InteractionElement.js') }}">
</script>
<script> <script>
// ###### Defining global variables used in other functions ###### // ###### Defining global variables used in other functions ######
var addToSubSubcorpusElement; // Button to start adding matches to sub-subcorpus
var client; // CorpusAnalysisClient first undefined on DOMContentLoaded defined var client; // CorpusAnalysisClient first undefined on DOMContentLoaded defined
var collapsibleElements; // All collapsibleElements on this page var collapsibleElements; // All collapsibleElements on this page
var contextModal; // Modal to open on inspect for further match context var contextModal; // Modal to open on inspect for further match context
var data; // full JSON object holding match results
var expertModeSwitchElement; // Expert mode switch Element var expertModeSwitchElement; // Expert mode switch Element
var initDisplay; // CorpusAnalysisDisplay object first undfined on DOMContentLoaded defined var initDisplay; // CorpusAnalysisDisplay object first undfined on DOMContentLoaded defined
var matchCountElement; // Total nr. of matches will be displayed in this element var matchCountElement; // Total nr. of matches will be displayed in this element
@ -292,10 +300,11 @@
var queryResultsUserFeedbackElement; // Element showing match count|total etc var queryResultsUserFeedbackElement; // Element showing match count|total etc
var receivedMatchCountElement; // Nr. of loaded matches will be displayed in this element var receivedMatchCountElement; // Nr. of loaded matches will be displayed in this element
var results; // results object var results; // results object
var data; // full JSON object holding match results
var resultsList; // resultsList object var resultsList; // resultsList object
var resultsListOptions; // specifies ResultsList options var resultsListOptions; // specifies ResultsList options
var textLookupCountElement // Nr of texts the matches occured in will be shown in this element var textLookupCountElement // Nr of texts the matches occured in will be shown in this element
var interactionElements; // Interaction elements and their parameters
var textTitlesElement; // matched text titles
// ###### Defining local scope variables ###### // ###### Defining local scope variables ######
let contextPerItemElement; // Form Element for display option let contextPerItemElement; // Form Element for display option
@ -315,12 +324,15 @@
// ###### Initialize variables ###### // ###### Initialize variables ######
client = undefined; client = undefined;
addToSubSubcorpusElement = document.getElementById("add-to-sub-subcorpus");
collapsibleElements = document.querySelector('.collapsible.expandable'); collapsibleElements = document.querySelector('.collapsible.expandable');
contextModal = document.getElementById("context-modal"); contextModal = document.getElementById("context-modal");
contextPerItemElement = document.getElementById("display-options-form-result_context");
contextSentencesElement = document.getElementById("context-sentences"); contextSentencesElement = document.getElementById("context-sentences");
displayOptionsFormElement = document.getElementById("display-options-form"); displayOptionsFormElement = document.getElementById("display-options-form");
expertModeSwitchElement = document.getElementById("display-options-form-expert_mode"); expertModeSwitchElement = document.getElementById("display-options-form-expert_mode");
exportModal = document.getElementById("query-results-download-modal"); exportModal = document.getElementById("query-results-download-modal");
hitsPerPageInputElement = document.getElementById("display-options-form-results_per_page");
initDisplay = undefined; initDisplay = undefined;
initDisplayElement = document.getElementById("init-display"); initDisplayElement = document.getElementById("init-display");
matchCountElement = document.getElementById("match-count"); matchCountElement = document.getElementById("match-count");
@ -334,8 +346,7 @@
queryResultsUserFeedbackElement = document.getElementById("query-results-user-feedback"); queryResultsUserFeedbackElement = document.getElementById("query-results-user-feedback");
receivedMatchCountElement = document.getElementById("received-match-count"); receivedMatchCountElement = document.getElementById("received-match-count");
textLookupCountElement = document.getElementById("text-lookup-count"); textLookupCountElement = document.getElementById("text-lookup-count");
hitsPerPageInputElement = document.getElementById("display-options-form-results_per_page"); textTitlesElement = document.getElementById("text-titles");
contextPerItemElement = document.getElementById("display-options-form-result_context");
// ###### js list options and intialization ###### // ###### js list options and intialization ######
displayOptionsData = ResultsList.getDisplayOptions(displayOptionsFormElement); displayOptionsData = ResultsList.getDisplayOptions(displayOptionsFormElement);
@ -430,25 +441,74 @@
// live update of lr context per item if context value is changed // live update of lr context per item if context value is changed
contextPerItemElement.onchange = results.jsList.changeContext; contextPerItemElement.onchange = results.jsList.changeContext;
// stuff that happens in the list table and should also be checked and
// updated if the pagination is used
interactionElements = new Array();
let expertModeInteraction = new InteractionElement("display-options-form-expert_mode");
expertModeInteraction.setCallback("on",
results.jsList.expertModeOn,
results.jsList,
["query-display"])
expertModeInteraction.setCallback("off",
results.jsList.expertModeOff,
results.jsList,
["query-display"])
let subSubcorpusInteraction = new InteractionElement("add-to-sub-subcorpus");
subSubcorpusInteraction.setCallback("on",
results.jsList.activateAddToSubSubcorpus,
results.jsList);
subSubcorpusInteraction.setCallback("off",
results.jsList.deactivateAddToSubSubcorpus,
results.jsList);
interactionElements.push(expertModeInteraction, subSubcorpusInteraction);
// eventListener if pagination is used to apply new context size to new page // eventListener if pagination is used to apply new context size to new page
// and also activate inspect match if progress is 100 // and also activate inspect match if progress is 100
// also adds more interaction buttons like add to subcorpus
for (let element of paginationElements) { for (let element of paginationElements) {
element.addEventListener("click", results.jsList.changeContext); element.addEventListener("click", results.jsList.changeContext);
element.addEventListener("click", results.jsList.activateInspect); element.addEventListener("click", results.jsList.activateInspect);
element.addEventListener("click", results.jsList.activateAddToSubSubcorpus);
element.addEventListener("click", (event) => {
results.jsList.pageChangeEventInteractionHandler(interactionElements);
});
} }
expertModeSwitchElement.addEventListener("change", (event) => { // checks if a change for every interactionElement happens and executes
// the callbacks accordingly
for (let interaction of interactionElements) {
let element = interaction.getElement()
element.addEventListener("change", (event) => {
if (event.target.checked) { if (event.target.checked) {
results.jsList.expertModeOn("query-display"); let f_on = interaction.bindThisToCallback("on");
for (let element of paginationElements) { let args_on = interaction.callbacks.on.args;
element.onclick = (event) => { f_on(...args_on);
results.jsList.eventHandlerCheck(event)
}
}
} else { } else {
results.jsList.expertModeOff("query-display"); let f_off = interaction.bindThisToCallback("off");
let args_off = interaction.callbacks.off.args;
f_off(...args_off);
} }
}); });
};
// Show add buttons for sub-subcorpus creation if this is pressed
// addToSubSubcorpusElement.addEventListener("change", (event) => {
// if (event.target.checked) {
// results.jsList.activateAddToSubSubcorpus();
// } else {
// results.jsList.deActivateAddToSubSubcorpus();
// }
// });
// expertModeSwitchElement.addEventListener("change", (event) => {
// if (event.target.checked) {
// results.jsList.expertModeOn("query-display");
// } else {
// results.jsList.expertModeOff("query-display");
// }
// });
}); });
// Add onclick to open download modal when Export Results button is pressed // Add onclick to open download modal when Export Results button is pressed

View File

@ -86,9 +86,9 @@
<td style="word-break: break-word;">{{ file.title }}</td> <td style="word-break: break-word;">{{ file.title }}</td>
<td>{{ file.publishing_year }}</td> <td>{{ file.publishing_year }}</td>
<td class="right-align"> <td class="right-align">
<a class="btn-small waves-effect waves-light" href="{{ url_for('corpora.edit_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">edit</i></a> <a class="btn-floating waves-effect waves-light" href="{{ url_for('corpora.edit_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">edit</i></a>
<a class="btn-small waves-effect waves-light" href="{{ url_for('corpora.download_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">file_download</i></a> <a class="btn-floating waves-effect waves-light" href="{{ url_for('corpora.download_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">file_download</i></a>
<a data-target="delete-corpus-file-{{ file.id }}-modal" class="btn-small modal-trigger red waves-effect waves-light"><i class="material-icons">delete</i></a> <a data-target="delete-corpus-file-{{ file.id }}-modal" class="btn-floating modal-trigger red waves-effect waves-light"><i class="material-icons">delete</i></a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}