Add result rendering for the user etc.

This commit is contained in:
Stephan Porada 2020-08-25 15:56:04 +02:00
parent d2453c2cc3
commit 763183435d
10 changed files with 183 additions and 69 deletions

View File

@ -64,12 +64,9 @@ class Client {
* This functions sends events to the View to trigger specific functions that * This functions sends events to the View to trigger specific functions that
* are handleing the representation of data stored in the model. * are handleing the representation of data stored in the model.
*/ */
notifyView(caseIdentifier, msg=null) { notifyView(caseIdentifier, detailObject={}) {
const event = new CustomEvent('notify', { detail: { detailObject.caseIdentifier = caseIdentifier;
'caseIdentifier': caseIdentifier, const event = new CustomEvent('notify', { detail: detailObject });
'msg': msg
}
});
console.info('Dispatching Notification:', caseIdentifier); console.info('Dispatching Notification:', caseIdentifier);
document.dispatchEvent(event); document.dispatchEvent(event);
} }

View File

@ -5,7 +5,6 @@
function saveMetaData() { function saveMetaData() {
let [payload, client, results, rest] = arguments; let [payload, client, results, rest] = arguments;
results.metaData.init(payload) results.metaData.init(payload)
client.recivedMetaData = true;
console.info('Metada saved:', results); console.info('Metada saved:', results);
} }
@ -18,21 +17,29 @@ function saveMetaData() {
function prepareQueryData() { function prepareQueryData() {
// deletes old data from query issued before this new query // deletes old data from query issued before this new query
let [payload, client, results, rest] = arguments; let [payload, client, results, rest] = arguments;
// always initialize the results to delete data from the query issued before
results.init(); results.init();
results.data.match_count = payload.match_count;
client.requestQueryProgress = 0; client.requestQueryProgress = 0;
client.notifyView('query-data-prepareing'); client.notifyView('query-data-prepareing', { results: results });
} }
function saveQueryData(args) { function saveQueryData(args) {
let [payload, client, results, rest] = arguments; 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 // incorporating new chunk data into full results
results.data.matches.push(...payload.chunk.matches); results.data.matches.push(...payload.chunk.matches);
results.data.addData(payload.chunk.cpos_lookup, 'cpos_lookup'); results.data.addData(payload.chunk.cpos_lookup, 'cpos_lookup');
results.data.addData(payload.chunk.text_lookup, 'text_lookup'); results.data.addData(payload.chunk.text_lookup, 'text_lookup');
results.data.cpos_ranges = payload.chunk.cpos_ranges; results.data.cpos_ranges = payload.chunk.cpos_ranges;
results.data.match_count = results.data.matches.length; let queryFormElement = document.querySelector('#query-form');
results.data.getQueryStr(queryFormElement);
client.requestQueryProgress = payload.progress; client.requestQueryProgress = payload.progress;
client.notifyView('query-data-recieving') client.notifyView('query-data-recieving',
{ results: results,
client: client,
dataLength: dataLength });
console.info('Query data chunk saved', results.data); console.info('Query data chunk saved', results.data);
if (client.requestQueryProgress === 100) { if (client.requestQueryProgress === 100) {
client.notifyView('query-data-recieved'); client.notifyView('query-data-recieved');

View File

@ -28,7 +28,7 @@ function recieveConnected(type, client) {
let errorText = `Error ${response.code} - ${response.msg}`; let errorText = `Error ${response.code} - ${response.msg}`;
console.group('Connection failed!') console.group('Connection failed!')
console.error(`corpus_analysis_init: ${errorText}`); console.error(`corpus_analysis_init: ${errorText}`);
client.notifyView('conntecting-failed', errorText); client.notifyView('connecting-failed', { msg: errorText });
console.groupEnd(); console.groupEnd();
} }
}); });

View File

@ -21,7 +21,7 @@ class ResultsList extends List {
* the options below are used. * the options below are used.
*/ */
static options = { static options = {
page: 10, page: 30,
pagination: [{ pagination: [{
name: "paginationTop", name: "paginationTop",
paginationClass: "paginationTop", paginationClass: "paginationTop",
@ -37,7 +37,6 @@ class ResultsList extends List {
}; };
constructor(idOrElement, options) { constructor(idOrElement, options) {
super(idOrElement, options); super(idOrElement, options);
this.options = options;
/** /**
* All span tokens which are holding events if expert * All span tokens which are holding events if expert
* mode is on. Collected here to delete later on. * mode is on. Collected here to delete later on.
@ -68,16 +67,22 @@ class ResultsList extends List {
// TODO: multipleResults=false, atattchSomeCallback=false ? // TODO: multipleResults=false, atattchSomeCallback=false ?
getHTMLElements(arrayOfSelectors) { getHTMLElements(arrayOfSelectors) {
for (let selector of arrayOfSelectors) { for (let selector of arrayOfSelectors) {
let element = document.querySelector(selector); let element;
let elements;
if (selector.startsWith('#')) {
element = document.querySelector(selector);
} else {
elements = document.querySelectorAll(selector);
}
let cleanKey = []; let cleanKey = [];
selector = selector.replace('_', '-'); selector = selector.replace(/_/g, '-');
selector.match(/\w+/g).forEach((word) => { selector.match(/\w+/g).forEach((word) => {
let tmp = word[0].toUpperCase() + word.slice(1); let tmp = word[0].toUpperCase() + word.slice(1);
cleanKey.push(tmp); cleanKey.push(tmp);
}); });
cleanKey[0] = cleanKey[0].toLowerCase(); cleanKey[0] = cleanKey[0].toLowerCase();
cleanKey = cleanKey.join(''); cleanKey = cleanKey.join('');
this[cleanKey] = element; this[cleanKey] = element ? element: elements;
} }
} }
@ -554,59 +559,58 @@ class ResultsList extends List {
// Event function that changes the shown hits per page. // Event function that changes the shown hits per page.
// Just alters the resultsList.page property // Just alters the resultsList.page property
changeHitsPerPage(event) { changeHitsPerPage() {
try { try {
// console.log(this); if (event.type === "change") {
this.page = event.target.value; nopaque.flash("Updated matches per page.", "corpus")
this.update();
this.activateInspect();
this.pageChangeEventInteractionHandler(interactionElements);
if (expertModeSwitchElement.checked) {
this.expertModeOn("query-display"); // page holds new result rows, so add new tooltips
} }
nopaque.flash("Updated matches per page.", "corpus")
} catch (e) { } catch (e) {
// console.log(e);
// console.log("resultsList has no results right now."); } finally {
this.page = this.displayOptionsFormResultsPerPage.value;
this.update();
} }
// TODO: reimplement the followinmg stuff
// this.activateInspect();
// this.pageChangeEventInteractionHandler(interactionElements);
// if (expertModeSwitchElement.checked) {
// this.expertModeOn("query-display"); // page holds new result rows, so add new tooltips
// }
} }
// Event function triggered on context select change // Event function triggered on context select change
// also if pagination is clicked // also if pagination is clicked
changeContext(event) { changeContext() {
let array;
let lc;
let newContextValue;
let rc;
try { try {
if (event.type === "change") { if (event.type === "change") {
nopaque.flash("Updated context per match!", "corpus"); nopaque.flash("Updated context per match!", "corpus");
} }
} catch (e) { } catch (e) {
} finally { } finally {
newContextValue = document.getElementById("display-options-form-result_context").value; let newContextValue = this.displayOptionsFormResultContext.value;
lc = document.getElementsByClassName("left-context"); let lc = document.querySelectorAll(".left-context");
rc = document.getElementsByClassName("right-context"); let rc = document.querySelectorAll(".right-context");
for (let element of lc) { for (let element of lc) {
array = Array.from(element.childNodes); let arrayLc = Array.from(element.childNodes);
for (let element of array.reverse().slice(newContextValue)) { for (let element of arrayLc.reverse().slice(newContextValue)) {
element.classList.add("hide"); element.classList.add("hide");
} }
for (let element of array.slice(0, newContextValue)) { for (let element of arrayLc.slice(0, newContextValue)) {
element.classList.remove("hide"); element.classList.remove("hide");
} }
} }
for (let element of rc) { for (let element of rc) {
array = Array.from(element.childNodes); let arrayRc = Array.from(element.childNodes);
for (let element of array.slice(newContextValue)) { for (let element of arrayRc.slice(newContextValue)) {
element.classList.add("hide"); element.classList.add("hide");
} }
for (let element of array.slice(0, newContextValue)) { for (let element of arrayRc.slice(0, newContextValue)) {
element.classList.remove("hide"); element.classList.remove("hide");
} }
} }
}
} }
}
// ###### Expert view event functions ###### // ###### Expert view event functions ######
// function to create a tooltip for the current hovered token // function to create a tooltip for the current hovered token

View File

@ -2,34 +2,112 @@
* This file contains all the callbacks triggered by the notificationListener. * This file contains all the callbacks triggered by the notificationListener.
*/ */
function connectingCallback(resultsList, msg=null) { function connectingCallback(resultsList, detail) {
resultsList.getHTMLElements(['#analysis-init-modal']); resultsList.getHTMLElements(['#analysis-init-modal']);
resultsList.analysisInitModal = M.Modal.init(resultsList.analysisInitModal, resultsList.analysisInitModal = M.Modal.init(resultsList.analysisInitModal,
{dismissible: false}); {dismissible: false});
resultsList.analysisInitModal.open(); resultsList.analysisInitModal.open();
} }
function connectedCallback(resultsList, msg=null) { function connectedCallback(resultsList, detail) {
resultsList.analysisInitModal.close(); resultsList.analysisInitModal.close();
} }
function connectingFaildeCallback(resultsList, msg=null) { function connectingFaildeCallback(resultsList, detail) {
resultsList.getHTMLElements([ resultsList.getHTMLElements([
'#analysis-init-progress', '#analysis-init-progress',
'#analysis-init-error' '#analysis-init-error'
]); ]);
resultsList.analysisInitProgress.classList.toggle('hide'); resultsList.analysisInitProgress.classList.toggle('hide');
resultsList.analysisInitError.classList.toggle('hide'); resultsList.analysisInitError.classList.toggle('hide');
resultsList.analysisInitError.textContent = msg; resultsList.analysisInitError.textContent = detail.msg;
} }
function queryDataPreparingCallback(resultsList, msg=null) { function queryDataPreparingCallback(resultsList, detail) {
resultsList.getHTMLElements(['#interactions-menu']); // remove all items from resultsList, like from the query issued before
resultsList.clear()
// get needed HTML Elements
let results = detail.results;
resultsList.getHTMLElements(
['#interactions-menu',
'#recieved-match-count',
'#total-match-count',
'#text-lookup-count',
'#text-lookup-titles',
'#query-results-user-feedback',
'#query-progress-bar',
'#query-results-create',
'#add-to-sub-results'
]);
// set some initial values for the user feedback
resultsList.recievedMatchCount.textContent = 0;
resultsList.totalMatchCount.textContent = results.data.match_count;
resultsList.textLookupTitles.textContent = '';
resultsList.textLookupCount.textContent = 0;
// show or enable some things for the user
resultsList.interactionsMenu.classList.toggle('hide', false) resultsList.interactionsMenu.classList.toggle('hide', false)
resultsList.addToSubResults.setAttribute("disabled", "");
resultsList.queryResultsUserFeedback.classList.toggle('hide', false);
resultsList.queryProgressBar.classList.toggle('hide', false);
// hide ore disable some things for the user
resultsList.queryResultsCreate.classList.toggle('disabled', true);
}
function queryDataRecievingCallback(resultsList, detail) {
// load the data into the resultsList and show them to the user
let results = detail.results;
let client = detail.client;
let start = detail.dataLength;
let resultItems = [];
for (let [index, match] of Object.entries(results.data.matches).slice(start)) {
resultItems.push({ ...match, ...{ 'index': parseInt(index) } });
}
if (client.dynamicMode) {
resultsList.add(resultItems, (items) => {
for (let item of items) {
item.elm = resultsList.createResultRowElement(item, results.data);
}
});
// 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();
resultsList.changeContext();
} else if (!client.dynamicMode) {
results.jsList.add(resultItems, (items) => {
for (let item of items) {
item.elm = results.jsList.createResultRowElement(item, payload.chunk,
true);
}
});
}
}
function queryDataRecievedCallback(resultsList, detail) {
// hide or disable some things for the user
resultsList.queryResultsUserFeedback.classList.toggle('hide');
resultsList.queryProgressBar.classList.toggle('hide');
// show or enable some things for the user
resultsList.queryResultsCreate.classList.toggle('disabled');
resultsList.addToSubResults.removeAttribute("disabled");
} }
// export the callbacks // export the callbacks
export { connectingCallback, export {
connectedCallback, connectingCallback,
connectingFaildeCallback, connectedCallback,
queryDataPreparingCallback, }; connectingFaildeCallback,
queryDataPreparingCallback,
queryDataRecievingCallback,
queryDataRecievedCallback,
};

View File

@ -12,6 +12,8 @@ import {
connectedCallback, connectedCallback,
connectingFaildeCallback, connectingFaildeCallback,
queryDataPreparingCallback, queryDataPreparingCallback,
queryDataRecievingCallback,
queryDataRecievedCallback,
} from './callbacks.js'; } from './callbacks.js';
function recieveNotification(eventType, resultsList) { function recieveNotification(eventType, resultsList) {
@ -20,30 +22,32 @@ function recieveNotification(eventType, resultsList) {
switch (caseIdentifier) { switch (caseIdentifier) {
case 'connecting': case 'connecting':
console.info('Recieved notification:', caseIdentifier); console.info('Recieved notification:', caseIdentifier);
connectingCallback(resultsList); connectingCallback(resultsList, event.detail);
// execute callback // execute callback
break; break;
case 'connected': case 'connected':
console.info('Recieved notification:', caseIdentifier); console.info('Recieved notification:', caseIdentifier);
connectedCallback(resultsList); connectedCallback(resultsList, event.detail);
break; break;
case 'connecting-failed': case 'connecting-failed':
console.info('Recieved notification:', caseIdentifier); console.info('Recieved notification:', caseIdentifier);
// execute callback // execute callback
connectingFaildeCallback(resultsList, event.detail.msg); connectingFaildeCallback(resultsList, event.detail);
break; break;
case 'query-data-prepareing': case 'query-data-prepareing':
console.info('Recieved notification:', caseIdentifier); console.info('Recieved notification:', caseIdentifier);
// execute callback // execute callback
queryDataPreparingCallback(resultsList); queryDataPreparingCallback(resultsList, event.detail);
break; break;
case 'query-data-recieving': case 'query-data-recieving':
console.info('Recieved notification:', caseIdentifier); console.info('Recieved notification:', caseIdentifier);
// execute callback // execute callback
queryDataRecievingCallback(resultsList, event.detail);
break; break;
case 'query-data-recieved': case 'query-data-recieved':
console.info('Recieved notification:', caseIdentifier); console.info('Recieved notification:', caseIdentifier);
// execute callback // execute callback
queryDataRecievedCallback(resultsList, event.detail);
break; break;
default: default:
console.error('Recieved unkown notification case identifier'); console.error('Recieved unkown notification case identifier');

View File

@ -2,18 +2,18 @@
* Function to show a scroll to top button if the user has scrolled down * Function to show a scroll to top button if the user has scrolled down
* 250 pixels from the headline element. * 250 pixels from the headline element.
*/ */
function scrollToTop() { function scrollToTop(scrollToElementSelector, triggerElementSelector) {
let headline = document.querySelector(".headline"); let headline = document.querySelector(scrollToElementSelector);
let scrollToTop = document.querySelector("#menu-scroll-to-top-div"); let scrollToTop = document.querySelector(triggerElementSelector);
window.addEventListener("scroll", (event) => { window.addEventListener('scroll', (event) => {
if (pageYOffset > 250) { if (pageYOffset > 250) {
scrollToTop.classList.toggle("hide", false); scrollToTop.classList.toggle('hide', false);
} else { } else {
scrollToTop.classList.toggle("hide", true); scrollToTop.classList.toggle('hide', true);
} }
}); });
scrollToTop.onclick = () => { scrollToTop.onclick = () => {
headline.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"}); headline.scrollIntoView({behavior: 'smooth', block: 'end', inline: 'nearest'});
}; };
} }

View File

@ -96,6 +96,9 @@ import {
import { import {
recieveNotification, recieveNotification,
} from '../../static/js/modules/corpus_analysis/view/listeners.js'; } from '../../static/js/modules/corpus_analysis/view/listeners.js';
import {
scrollToTop,
} from '../../static/js/modules/corpus_analysis/view/scrollToTop.js'
/** /**
* Second Phase: * Second Phase:
@ -114,7 +117,7 @@ document.addEventListener("DOMContentLoaded", () => {
* object as the View handeling the represnetation of the data. * object as the View handeling the represnetation of the data.
*/ */
let results = new Results(); let results = new Results();
let resultsView = new ResultsList('result-list', ResultsList.options); let resultsList = new ResultsList('result-list', ResultsList.options);
/** /**
* Register listeners listening to socket.io events and their callbacks * Register listeners listening to socket.io events and their callbacks
* Afterwards load them. * Afterwards load them.
@ -145,18 +148,18 @@ document.addEventListener("DOMContentLoaded", () => {
listenForMetaData]); listenForMetaData]);
client.loadSocketEventListeners(); client.loadSocketEventListeners();
/** /**
* Register resultsView listeners listening to nitification events. * Register resultsList listeners listening to nitification events.
*/ */
const listenForNotification = new NotificationListener('notify', const listenForNotification = new NotificationListener('notify',
recieveNotification); recieveNotification);
resultsView.setNotificationListeners([listenForNotification]); resultsList.setNotificationListeners([listenForNotification]);
resultsView.loadNotificationListeners(); resultsList.loadNotificationListeners();
// Connect client to server // Connect client to server
client.notifyView('connecting'); client.notifyView('connecting');
client.connect(); client.connect();
// Send a query and recieve its answer data // Send a query and recieve its answer data
let queryFormElement = document.getElementById('query-form'); let queryFormElement = document.querySelector('#query-form');
queryFormElement.addEventListener('submit', (event) => { queryFormElement.addEventListener('submit', (event) => {
try { try {
/** /**
@ -178,6 +181,25 @@ document.addEventListener("DOMContentLoaded", () => {
results.data.getQueryStr(queryFormElement); results.data.getQueryStr(queryFormElement);
client.query(results.data.query); client.query(results.data.query);
}); });
/**
* Display events
* 1. live update of hits per page if hits per page value is changed
*/
resultsList.getHTMLElements([
'#display-options-form-results_per_page',
'#display-options-form-result_context'
]);
resultsList.displayOptionsFormResultsPerPage.onchange = () => {
resultsList.changeHitsPerPage();
};
resultsList.displayOptionsFormResultContext.onchange = () => {
resultsList.changeContext();
};
// enable scroll to Top
scrollToTop('.headline', '#menu-scroll-to-top-div');
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -7,7 +7,7 @@ results.-->
<div class="row"> <div class="row">
<div class="col s12"> <div class="col s12">
<div class="switch"> <div class="switch">
Sub-Results creation: Sub-Results:
<label> <label>
Off Off
<input type="checkbox" <input type="checkbox"

View File

@ -26,12 +26,14 @@ result.-->
<span id="total-match-count"></span> <span id="total-match-count"></span>
matches loaded. matches loaded.
<br> <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> <br>
<span id=text-lookup-titles></span> <span id=text-lookup-titles></span>
</p> </p>
<br>
<p class="hide" id="query-results-user-feedback"> <p class="hide" id="query-results-user-feedback">
<i class="material-icons tiny">help</i> <i class="material-icons tiny">help</i>
Server is sending your results. Server is sending your results.