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
* are handleing the representation of data stored in the model.
*/
notifyView(caseIdentifier, msg=null) {
const event = new CustomEvent('notify', { detail: {
'caseIdentifier': caseIdentifier,
'msg': msg
}
});
notifyView(caseIdentifier, detailObject={}) {
detailObject.caseIdentifier = caseIdentifier;
const event = new CustomEvent('notify', { detail: detailObject });
console.info('Dispatching Notification:', caseIdentifier);
document.dispatchEvent(event);
}

View File

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

View File

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

View File

@ -21,7 +21,7 @@ class ResultsList extends List {
* the options below are used.
*/
static options = {
page: 10,
page: 30,
pagination: [{
name: "paginationTop",
paginationClass: "paginationTop",
@ -37,7 +37,6 @@ class ResultsList extends List {
};
constructor(idOrElement, options) {
super(idOrElement, options);
this.options = options;
/**
* All span tokens which are holding events if expert
* mode is on. Collected here to delete later on.
@ -68,16 +67,22 @@ class ResultsList extends List {
// TODO: multipleResults=false, atattchSomeCallback=false ?
getHTMLElements(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 = [];
selector = selector.replace('_', '-');
selector = selector.replace(/_/g, '-');
selector.match(/\w+/g).forEach((word) => {
let tmp = word[0].toUpperCase() + word.slice(1);
cleanKey.push(tmp);
});
cleanKey[0] = cleanKey[0].toLowerCase();
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.
// Just alters the resultsList.page property
changeHitsPerPage(event) {
changeHitsPerPage() {
try {
// console.log(this);
this.page = event.target.value;
this.update();
this.activateInspect();
this.pageChangeEventInteractionHandler(interactionElements);
if (expertModeSwitchElement.checked) {
this.expertModeOn("query-display"); // page holds new result rows, so add new tooltips
if (event.type === "change") {
nopaque.flash("Updated matches per page.", "corpus")
}
nopaque.flash("Updated matches per page.", "corpus")
} 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
// also if pagination is clicked
changeContext(event) {
let array;
let lc;
let newContextValue;
let rc;
changeContext() {
try {
if (event.type === "change") {
nopaque.flash("Updated context per match!", "corpus");
}
} catch (e) {
} finally {
newContextValue = document.getElementById("display-options-form-result_context").value;
lc = document.getElementsByClassName("left-context");
rc = document.getElementsByClassName("right-context");
let newContextValue = this.displayOptionsFormResultContext.value;
let lc = document.querySelectorAll(".left-context");
let rc = document.querySelectorAll(".right-context");
for (let element of lc) {
array = Array.from(element.childNodes);
for (let element of array.reverse().slice(newContextValue)) {
let arrayLc = Array.from(element.childNodes);
for (let element of arrayLc.reverse().slice(newContextValue)) {
element.classList.add("hide");
}
for (let element of array.slice(0, newContextValue)) {
for (let element of arrayLc.slice(0, newContextValue)) {
element.classList.remove("hide");
}
}
for (let element of rc) {
array = Array.from(element.childNodes);
for (let element of array.slice(newContextValue)) {
let arrayRc = Array.from(element.childNodes);
for (let element of arrayRc.slice(newContextValue)) {
element.classList.add("hide");
}
for (let element of array.slice(0, newContextValue)) {
for (let element of arrayRc.slice(0, newContextValue)) {
element.classList.remove("hide");
}
}
}
}
}
// ###### Expert view event functions ######
// 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.
*/
function connectingCallback(resultsList, msg=null) {
function connectingCallback(resultsList, detail) {
resultsList.getHTMLElements(['#analysis-init-modal']);
resultsList.analysisInitModal = M.Modal.init(resultsList.analysisInitModal,
{dismissible: false});
resultsList.analysisInitModal.open();
}
function connectedCallback(resultsList, msg=null) {
function connectedCallback(resultsList, detail) {
resultsList.analysisInitModal.close();
}
function connectingFaildeCallback(resultsList, msg=null) {
function connectingFaildeCallback(resultsList, detail) {
resultsList.getHTMLElements([
'#analysis-init-progress',
'#analysis-init-error'
]);
resultsList.analysisInitProgress.classList.toggle('hide');
resultsList.analysisInitError.classList.toggle('hide');
resultsList.analysisInitError.textContent = msg;
resultsList.analysisInitError.textContent = detail.msg;
}
function queryDataPreparingCallback(resultsList, msg=null) {
resultsList.getHTMLElements(['#interactions-menu']);
function queryDataPreparingCallback(resultsList, detail) {
// 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.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 { connectingCallback,
connectedCallback,
connectingFaildeCallback,
queryDataPreparingCallback, };
export {
connectingCallback,
connectedCallback,
connectingFaildeCallback,
queryDataPreparingCallback,
queryDataRecievingCallback,
queryDataRecievedCallback,
};

View File

@ -12,6 +12,8 @@ import {
connectedCallback,
connectingFaildeCallback,
queryDataPreparingCallback,
queryDataRecievingCallback,
queryDataRecievedCallback,
} from './callbacks.js';
function recieveNotification(eventType, resultsList) {
@ -20,30 +22,32 @@ function recieveNotification(eventType, resultsList) {
switch (caseIdentifier) {
case 'connecting':
console.info('Recieved notification:', caseIdentifier);
connectingCallback(resultsList);
connectingCallback(resultsList, event.detail);
// execute callback
break;
case 'connected':
console.info('Recieved notification:', caseIdentifier);
connectedCallback(resultsList);
connectedCallback(resultsList, event.detail);
break;
case 'connecting-failed':
console.info('Recieved notification:', caseIdentifier);
// execute callback
connectingFaildeCallback(resultsList, event.detail.msg);
connectingFaildeCallback(resultsList, event.detail);
break;
case 'query-data-prepareing':
console.info('Recieved notification:', caseIdentifier);
// execute callback
queryDataPreparingCallback(resultsList);
queryDataPreparingCallback(resultsList, event.detail);
break;
case 'query-data-recieving':
console.info('Recieved notification:', caseIdentifier);
// execute callback
queryDataRecievingCallback(resultsList, event.detail);
break;
case 'query-data-recieved':
console.info('Recieved notification:', caseIdentifier);
// execute callback
queryDataRecievedCallback(resultsList, event.detail);
break;
default:
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
* 250 pixels from the headline element.
*/
function scrollToTop() {
let headline = document.querySelector(".headline");
let scrollToTop = document.querySelector("#menu-scroll-to-top-div");
window.addEventListener("scroll", (event) => {
function scrollToTop(scrollToElementSelector, triggerElementSelector) {
let headline = document.querySelector(scrollToElementSelector);
let scrollToTop = document.querySelector(triggerElementSelector);
window.addEventListener('scroll', (event) => {
if (pageYOffset > 250) {
scrollToTop.classList.toggle("hide", false);
scrollToTop.classList.toggle('hide', false);
} else {
scrollToTop.classList.toggle("hide", true);
scrollToTop.classList.toggle('hide', true);
}
});
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 {
recieveNotification,
} from '../../static/js/modules/corpus_analysis/view/listeners.js';
import {
scrollToTop,
} from '../../static/js/modules/corpus_analysis/view/scrollToTop.js'
/**
* Second Phase:
@ -114,7 +117,7 @@ document.addEventListener("DOMContentLoaded", () => {
* object as the View handeling the represnetation of the data.
*/
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
* Afterwards load them.
@ -145,18 +148,18 @@ document.addEventListener("DOMContentLoaded", () => {
listenForMetaData]);
client.loadSocketEventListeners();
/**
* Register resultsView listeners listening to nitification events.
* Register resultsList listeners listening to nitification events.
*/
const listenForNotification = new NotificationListener('notify',
recieveNotification);
resultsView.setNotificationListeners([listenForNotification]);
resultsView.loadNotificationListeners();
resultsList.setNotificationListeners([listenForNotification]);
resultsList.loadNotificationListeners();
// Connect client to server
client.notifyView('connecting');
client.connect();
// Send a query and recieve its answer data
let queryFormElement = document.getElementById('query-form');
let queryFormElement = document.querySelector('#query-form');
queryFormElement.addEventListener('submit', (event) => {
try {
/**
@ -178,6 +181,25 @@ document.addEventListener("DOMContentLoaded", () => {
results.data.getQueryStr(queryFormElement);
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>
{% endblock %}

View File

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

View File

@ -26,12 +26,14 @@ result.-->
<span id="total-match-count"></span>
matches loaded.
<br>
<br>
Matches occured in
<span id="text-lookup-count"></span>
corpus files:
<br>
<span id=text-lookup-titles></span>
</p>
<br>
<p class="hide" id="query-results-user-feedback">
<i class="material-icons tiny">help</i>
Server is sending your results.