Add Results viewer functionality with ne javascript and fix some errors.

This commit is contained in:
Stephan Porada 2020-09-10 15:33:04 +02:00
parent fd1d1c2fc3
commit 6b05651f05
7 changed files with 231 additions and 49 deletions

View File

@ -30,24 +30,43 @@ function prepareQueryData() {
*/
function saveQueryData() {
let [payload, client, results, rest] = arguments;
// get data matches length before new chun kdata is being inserted
let dataLength = results.data.matches.length;
// incorporating new chunk data into full results
results.data.matches.push(...payload.chunk.matches);
results.data.addData(payload.chunk.cpos_lookup, 'cpos_lookup');
results.data.addData(payload.chunk.text_lookup, 'text_lookup');
results.data.cpos_ranges = payload.chunk.cpos_ranges;
let queryFormElement = document.querySelector('#query-form');
results.data.getQueryStr(queryFormElement);
client.requestQueryProgress = payload.progress;
client.notifyView('query-data-recieving',
{ results: results,
client: client,
dataLength: dataLength });
console.info('Query data chunk saved', results.data);
if (client.requestQueryProgress === 100) {
client.isBusy = false;
client.notifyView('query-data-recieved');
if (client.dynamicMode) {
// get data matches length before new chunk data is being inserted
// incorporating new chunk data into full results
results.data.matches.push(...payload.chunk.matches);
results.data.addData(payload.chunk.cpos_lookup, 'cpos_lookup');
results.data.addData(payload.chunk.text_lookup, 'text_lookup');
results.data.cpos_ranges = payload.chunk.cpos_ranges;
let queryFormElement = document.querySelector('#query-form');
results.data.getQueryStr(queryFormElement);
client.requestQueryProgress = payload.progress;
client.notifyView('query-data-recieving',
{ results: results,
client: client,
dataLength: dataLength });
console.info('Query data chunk saved', results.data);
if (client.requestQueryProgress === 100) {
client.isBusy = false;
client.notifyView('query-data-recieved');
}
} else {
results.data.matches.push(...payload.matches);
results.data.addData(payload.cpos_lookup, 'cpos_lookup');
results.data.addData(payload.text_lookup, 'text_lookup');
results.data.cpos_ranges = payload.cpos_ranges;
let queryFormElement = document.querySelector('#query-form');
results.data.getQueryStr(queryFormElement);
client.requestQueryProgress = 100;
client.notifyView('query-data-recieving',
{ results: results,
client: client,
dataLength: dataLength });
console.info('Query data chunk saved', results.data);
if (client.requestQueryProgress === 100) {
console.log(results.data);
client.notifyView('query-data-recieved');
}
}
}

View File

@ -52,7 +52,7 @@ class Data {
let queryStr;
queryFormData = new FormData(queryFormElement);
queryStr = queryFormData.get('query-form-query');
this["query"] = queryStr;
this['query'] = queryStr;
}
// function creates a unique and safe filename for the download

View File

@ -336,21 +336,28 @@ class ResultsList extends List {
return fake_response
}
// gets result cpos infos for one dataIndex (list of length 1) to send back to
// gets result cpos infos for dataIndexes (use list of length 1 for one match) to send back to
// the server
inspect(dataIndex, type) {
inspect(client, results, dataIndex, type) {
// initialize context modal
this.getHTMLElements([
'#context-modal',
'#context-results',
'#create-inspect-menu',
'#create-from-inspect',
]);
this.contextModal = M.Modal.init(this.contextModal);
// get result infos from server and show them in context modal
this.contextId = dataIndex[0];
this.contextResults.innerHTML = ""; // clear it from old inspects
this.notifyClient('get-results', {resultsType: 'inspect-results',
dataIndexes: [dataIndex]});
if (client.dynamicMode) {
this.notifyClient('get-results', {resultsType: 'inspect-results',
dataIndexes: [dataIndex]});
} else {
results.inspectResultsData.matches = [results.data.matches[dataIndex[0]]];
results.inspectResultsData.cpos_ranges = results.data.cpos_ranges;
this.showMatchContext(results, client)
}
// match nr for user to display derived from data_index
let contextMatchNrElement = document.getElementById("context-match-nr");
contextMatchNrElement.textContent = this.contextId + 1;
@ -361,7 +368,7 @@ class ResultsList extends List {
let addToSubResultsIdsBtn = document.createElement("a");
addToSubResultsIdsBtn.setAttribute("class", classes + ` add`);
addToSubResultsIdsBtn.innerHTML = '<i class="material-icons">add</i>';
addToSubResultsIdsBtn.onclick= () => {this.addToSubResults(dataIndex[0], false)};
addToSubResultsIdsBtn.onclick= () => {this.addToSubResults(dataIndex[0], client, false)};
// checks if the match has or has not been added to sub results yet
// sets the color and status of the button accordingly
if (this.addToSubResultsStatus[dataIndex[0]]) {
@ -371,6 +378,10 @@ class ResultsList extends List {
}
this.createInspectMenu.innerHTML = '';
this.createInspectMenu.appendChild(addToSubResultsIdsBtn);
// Hide create menu if not in dynamic mode
if (!client.dynamicMode) {
this.createFromInspect.classList.add('hide');
}
}
// create Element from HTML String helper function
@ -384,7 +395,7 @@ class ResultsList extends List {
// Used as a callback to handle incoming match context results when inspect
// has been used.
showMatchContext(results) {
showMatchContext(results, client) {
this.getHTMLElements([
'#context-results',
@ -403,7 +414,12 @@ class ResultsList extends List {
let tokenHTMlElement;
let token;
for (let cpos of lc) {
token = results.inspectResultsData.cpos_lookup[cpos];
if (client.dynamicMode) {
token = results.inspectResultsData.cpos_lookup[cpos];
// If client is not in dynamic mode use cpos_lookup from results.data
} else {
token = results.data.cpos_lookup[cpos];
}
uniqueS.add(token.s)
htmlTokenStr = `<span class="token"` +
`data-sid="${token.s}"` +
@ -414,7 +430,12 @@ class ResultsList extends List {
tokenHTMLArray.push(tokenHTMlElement);
}
for (let cpos of c) {
token = results.inspectResultsData.cpos_lookup[cpos];
if (client.dynamicMode) {
token = results.inspectResultsData.cpos_lookup[cpos];
// If client is not in dynamic mode use cpos_lookup from results.data
} else {
token = results.data.cpos_lookup[cpos];
}
uniqueContextS.add(token.s);
uniqueS.add(token.s);
htmlTokenStr = `<span class="token bold light-green"` +
@ -428,7 +449,12 @@ class ResultsList extends List {
}
results.inspectResultsData["context_s_ids"] = Array.from(uniqueContextS);
for (let cpos of rc) {
token = results.inspectResultsData.cpos_lookup[cpos];
if (client.dynamicMode) {
token = results.inspectResultsData.cpos_lookup[cpos];
// If client is not in dynamic mode use cpos_lookup from results.data
} else {
token = results.data.cpos_lookup[cpos];
}
uniqueS.add(token.s)
htmlTokenStr = `<span class="token"` +
`data-sid="${token.s}"` +
@ -665,7 +691,7 @@ class ResultsList extends List {
this.eventTokens[htmlId] = [];
}
createResultRowElement(item, chunk, imported=false) {
createResultRowElement(item, chunk, client, imported=false) {
let aCellElement;
let addToSubResultsBtn;
let cCellElement;
@ -733,7 +759,9 @@ class ResultsList extends List {
);
addToSubResultsBtn.innerHTML = '<i class="material-icons add-btn">add</i>';
aCellElement.appendChild(inspectBtn);
aCellElement.appendChild(addToSubResultsBtn);
if (client.dynamicMode) {
aCellElement.appendChild(addToSubResultsBtn);
}
// add text titles at front as first td of one row
textTitlesCellElement.textContent = [...textTitles].join(", ");
matchRowElement.insertAdjacentHTML("afterbegin", textTitlesCellElement.outerHTML);

View File

@ -89,7 +89,9 @@ function queryDataRecievingCallback(resultsList, detail) {
if (client.dynamicMode) {
resultsList.add(resultItems, (items) => {
for (let item of items) {
item.elm = resultsList.createResultRowElement(item, results.data);
item.elm = resultsList.createResultRowElement(item,
results.data,
client);
}
});
// update user feedback about query status
@ -110,12 +112,27 @@ function queryDataRecievingCallback(resultsList, detail) {
resultsList.expertModeOn('query-display', results);
}
} else if (!client.dynamicMode) {
results.jsList.add(resultItems, (items) => {
resultsList.add(resultItems, (items) => {
for (let item of items) {
item.elm = results.jsList.createResultRowElement(item, payload.chunk,
true);
item.elm = resultsList.createResultRowElement(item,
results.data,
client,
true);
}
});
// update user feedback about query status
resultsList.recievedMatchCount.textContent = results.data.matches.length;
resultsList.queryProgressBar.firstElementChild.style.width = `${client.requestQueryProgress}%`;
resultsList.textLookupCount.textContent = `${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})`);
}
resultsList.textLookupTitles.textContent = `${titles.join(', ')}`;
// updating table on finished item creation callback via createResultRowElement
resultsList.update();
resultsList.changeHitsPerPage(client, results);
resultsList.changeContext();
}
}
@ -158,7 +175,7 @@ function resultsDataRecievedCallback(resultsList, detail) {
*/
resultsList.subResultsCreate.classList.toggle('disabled', true);
}
resultsList.showMatchContext(detail.results);
resultsList.showMatchContext(detail.results, detail.client);
}
}

View File

@ -187,6 +187,7 @@ document.addEventListener("DOMContentLoaded", () => {
listenForMetaData,
listenForViewNotification,
listenForResults]);
console.log(client.eventListeners);
// Load the listeners so that they will be executed if triggered
client.loadSocketEventListeners();
/**
@ -225,21 +226,21 @@ document.addEventListener("DOMContentLoaded", () => {
});
// Get all needed HTMLElements for the following event listeners.
resultsList.getHTMLElements([
'#display-options-form-results_per_page',
'.pagination',
'#display-options-form-expert_mode',
'#display-options-form-result_context',
'#show-meta-data',
'#meta-data-modal',
'#meta-data-modal-content',
'#full-results-create',
'#sub-results-create',
'#full-results-export',
'#sub-results-export',
'#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',
'#query-results-download-modal',
'#query-results-table',
'#display-options-form-expert_mode',
'.pagination',
'#inspect-results-export',
'#show-meta-data',
'#sub-results-create',
'#sub-results-export',
]);
/**
@ -280,7 +281,7 @@ document.addEventListener("DOMContentLoaded", () => {
let dataIndex;
if (event.target.classList.contains('inspect-btn')) {
dataIndex = parseInt(event.target.closest('tr').dataset.index);
resultsList.inspect([dataIndex], 'inspect');
resultsList.inspect(client, results, [dataIndex], 'inspect');
} else if (event.target.classList.contains('add-btn')) {
dataIndex = parseInt(event.target.closest('tr').dataset.index);
resultsList.addToSubResults(dataIndex, client);

View File

@ -42,7 +42,7 @@
</div>
</div>
</div>
<div class="col s12 m6 l6">
<div class="col s12 m6 l6" id="create-from-inspect">
<div class="section">
<h6 style="margin-top: 0px;">Create</h6>
<div class="divider" style="margin-bottom: 10px;"></div>

View File

@ -34,11 +34,15 @@
<div class="col s12" id="query-display">
<div class="card">
<div class="card-content" id="result-list" style="overflow: hidden;">
<div class="row">
<div class="row" id="interactions-menu">
{% include 'interactions/infos.html.j2' %}
{% include 'interactions/display.html.j2' %}
{% include 'interactions/analysis.html.j2' %}
{% include 'interactions/cite.html.j2' %}
<div class="hide">
{% include 'interactions/export.html.j2' %}
{% include 'interactions/create.html.j2' %}
</div>
</div>
{% include 'tables/query_results.html.j2' %}
</div>
@ -93,6 +97,10 @@ import {
ResultsList,
ViewEventListener,
} from '../../static/js/modules/corpus_analysis/view/ResultsView.js';
// Import listener which will be registered to the ViewEventListener class.
import {
recieveClientNotification,
} from '../../static/js/modules/corpus_analysis/view/listeners.js';
import {
scrollToTop,
} from '../../static/js/modules/corpus_analysis/view/scrollToTop.js'
@ -130,7 +138,116 @@ document.addEventListener("DOMContentLoaded", () => {
saveQueryData,
[client, results]);
listenForQueryData.setCallbacks([queryDataCallback]);
// TODO: execute callbacks manually with right input
// 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);
resultsList.setNotificationListeners([listenForClientNotification]);
resultsList.loadNotificationListeners();
// Get all needed HTMLElements for the following event listeners.
resultsList.getHTMLElements([
'.add-btn',
'.pagination',
'#display-options-form-expert_mode',
'#display-options-form-result_context',
'#display-options-form-results_per_page',
'#full-results-create',
'#meta-data-modal-content',
'#meta-data-modal',
'#query-results-table',
'#show-meta-data',
'#sub-results-create',
]);
// Execute client event listener callbacks manually because dynamicMode is false
client.eventListeners['corpus_analysis_query'].executeCallbacks([resultsJson])
client.eventListeners['corpus_analysis_query_results'].executeCallbacks([resultsJson])
/**
* The following listener handles what functions are called when the user
* does use the page navigation to navigate to a new page.
*/
for (let element of resultsList.pagination) {
element.addEventListener("click", (event) => {
// Shows match context according to the user picked value on a new page.
resultsList.changeContext();
// De- or activates expertMode on new page depending on switch value.
if (resultsList.displayOptionsFormExpertMode.checked) {
resultsList.expertModeOn('query-display', results);
} else {
resultsList.expertModeOff('query-display');
}
// Activates inspect buttons on new page if client is not busy.
resultsList.toggleInspectButtons(client);
});
}
/**
* The following event Listener handles the expert mode switch for the list.
*/
resultsList.displayOptionsFormExpertMode.onchange = (event) => {
if (event.target.checked) {
resultsList.expertModeOn('query-display', results);
} else {
resultsList.expertModeOff('query-display');
}
};
/**
* The following event Listener handles the add-btn and the inspect-btn
* onclick events via bubbleing.
*/
resultsList.queryResultsTable.addEventListener('click', (event) => {
let dataIndex;
if (event.target.classList.contains('inspect-btn')) {
dataIndex = parseInt(event.target.closest('tr').dataset.index);
resultsList.inspect(client, results, [dataIndex], 'inspect');
} else if (event.target.classList.contains('add-btn')) {
dataIndex = parseInt(event.target.closest('tr').dataset.index);
resultsList.addToSubResults(dataIndex, client);
}
})
/**
* Following event listeners handle the change of Context size per match and
* the number of matches shown per page.
*/
resultsList.displayOptionsFormResultsPerPage.onchange = (event) => {
resultsList.changeHitsPerPage(client, results);
};
resultsList.displayOptionsFormResultContext.onchange = (event) => {
resultsList.changeContext();
};
/**
* The following event listener handles the show metadata button and its
* functionality. Before the needed modal is initialized.
*/
resultsList.metaDataModal= M.Modal.init(resultsList.metaDataModal, {
'preventScrolling': false,
'opacity': 0.0,
'dismissible': false,
'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()})
});
resultsList.showMetaData.onclick = () => {
resultsList.metaDataModalContent.textContent = '';
let table = resultsList.createMetaDataForModal(results.metaData);
resultsList.metaDataModalContent.insertAdjacentHTML('afterbegin', table);
resultsList.metaDataModal.open();
let collapsibles = resultsList.metaDataModalContent.querySelectorAll(".text-metadata");
for (let collapsible of collapsibles) {
collapsible.onclick = () => {
let elems = resultsList.metaDataModalContent.querySelectorAll('.collapsible');
let instances = M.Collapsible.init(elems, {accordion: false});
resultsList.createTextDetails(results.metaData);
}
}
};
// Enable scroll to Top functionality.
scrollToTop('#headline', '#menu-scroll-to-top-div');
});