Push before rework part 2

This commit is contained in:
Stephan Porada 2020-08-20 16:03:37 +02:00
parent b3e8976c1c
commit 21ce07f3ef
10 changed files with 309 additions and 128 deletions

View File

@ -1,8 +1,10 @@
/** /**
* This class is used to create an CorpusAnalysisClient object. * This class is used to create a CorpusAnalysisClient object.
* The client handels the client server communication. * The client handels the client server communication.
* It requests data (e.g. the analysis session or query results) from the * It requests data (e.g. the analysis session or query results) from the
* the server and recieves them. * the server and recieves them, if it dynamicMode is true.
* If dynamicMode is false, the client can also handle data that is already
* loaded and not coming in in chunks.
*/ */
class CorpusAnalysisClient { class CorpusAnalysisClient {
constructor({corpusId = null, constructor({corpusId = null,
@ -19,11 +21,9 @@ class CorpusAnalysisClient {
this.socketEventListeners = {}; this.socketEventListeners = {};
/** /**
* Set client into imported mode if SOME THIGN IS INDICATING it * Disable all console logging.
* * Credits to https://gist.github.com/kmonsoor/0244fdb4ad79a4826371e58a1a5fa984
*/ */
// Disable all console logging. Credits to https://gist.github.com/kmonsoor/0244fdb4ad79a4826371e58a1a5fa984
if (!logging) { if (!logging) {
(() => { (() => {
let console = (window.console = window.console || {}); let console = (window.console = window.console || {});
@ -32,7 +32,7 @@ class CorpusAnalysisClient {
'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd',
'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table',
'time', 'timeEnd', 'timeStamp', 'trace', 'warn' 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'
].forEach(method => { ].forEach((method) => {
console[method] = () => {}; console[method] = () => {};
}); });
})(); })();
@ -41,14 +41,18 @@ class CorpusAnalysisClient {
// Registers one or more SocketEventListeners to the CorpusAnalysisClient. // Registers one or more SocketEventListeners to the CorpusAnalysisClient.
setSocketEventListeners(socketEventListeners) { setSocketEventListeners(socketEventListeners) {
for (let listener of socketEventListeners) { for (let socketEventListener of socketEventListeners) {
this.socketEventListeners[listener.type] = listener.listenerFunction; this.socketEventListeners[socketEventListener.type] = socketEventListener;
} }
} }
/**
* Loads the SocketEventListeners so they will be triggered on their assigned
* type strings because they double as the socket event event names.
*/
loadSocketEventListeners() { loadSocketEventListeners() {
for (let [type, listener] of Object.entries(this.socketEventListeners)) { for (let [type, listener] of Object.entries(this.socketEventListeners)) {
listener(this); listener.listenerFunction(type, this);
} }
} }
@ -64,12 +68,14 @@ class CorpusAnalysisClient {
* string as the key. The selector will be converted to a valid JavaScript * string as the key. The selector will be converted to a valid JavaScript
* Field name i. e. #html-id-string -> this.htmlIdString * Field name i. e. #html-id-string -> this.htmlIdString
* The value will be the identifed element fetched with the querySelector * The value will be the identifed element fetched with the querySelector
* method. MutlipleResults and atattchSomeCallback not yet implemented. * method.
*/ */
getHTMLElements(arrayOfSelectors, multipleResults=false, atattchSomeCallback=false) { // TODO: multipleResults=false, atattchSomeCallback=false ?
getHTMLElements(arrayOfSelectors) {
for (let selector of arrayOfSelectors) { for (let selector of arrayOfSelectors) {
let element = document.querySelector(selector); let element = document.querySelector(selector);
let cleanKey = []; let cleanKey = [];
selector = selector.replace('_', '-');
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);
@ -82,7 +88,8 @@ class CorpusAnalysisClient {
/** /**
* Requests a corpus analysis session via socket.io. * Requests a corpus analysis session via socket.io.
* Opens a loading modal at the start of the request * Opens a loading modal at the start of the request.
* Will be closed if session has been successfully recieved.
*/ */
requestSession() { requestSession() {
console.info('corpus_analysis_init: Client requesting session via', console.info('corpus_analysis_init: Client requesting session via',
@ -95,7 +102,7 @@ class CorpusAnalysisClient {
} }
/** /**
* Sends the query string to the server. * Request query data for the query string that has been sent to the server.
*/ */
requestQueryData(queryStr) { requestQueryData(queryStr) {
console.info('corpus_analysis_query: Client requesting query data via', console.info('corpus_analysis_query: Client requesting query data via',
@ -180,16 +187,57 @@ class CorpusAnalysisDisplay {
} }
/** /**
* This class is used to create an CorpusAnalysisDisplay object. * This class is used to create an SocketEventListener.
* Input is one HTMLElement that can then be hidden or shown depending on * Input are an identifying type string, the listener function and callbacks
* its CSS classes. * which will be executed as part of the listener function. The identifying
* type string is also used as the socket event event identifier.
*/ */
class SocketEventListener { class SocketEventListener {
constructor(type, listenerFunction) { constructor(type, listenerFunction) {
this.listenerCallbacks = {};
this.listenerFunction = listenerFunction; this.listenerFunction = listenerFunction;
this.type = type; this.type = type;
} }
// Registers callbacks to this SocketEventListener
setCallbacks(listenerCallbacks) {
for (let listenerCallback of listenerCallbacks) {
this.listenerCallbacks[listenerCallback.type] = listenerCallback;
}
}
/** Shorthand to execute all registered callbacks with same args in insertion
* order.
* NOTE:
* Since ECMAScript 2015, objects do preserve creation order for
* string and Symbol keys. In JavaScript engines that comply with the
* ECMAScript 2015 spec, iterating over an object with only string keys will
* yield the keys in order of insertion.
* So all modern Browsers.
*/
executeCallbacks(args) {
for (let [type, listenerCallback] of Object.entries(this.listenerCallbacks)) {
listenerCallback.callbackFunction(...args);
}
}
}
/**
* This class is used to create an ListenerCallback which will be registered
* to an SocketEventListener so the Listener cann invoke the ListenerCallback
* callback functions.
*/
class ListenerCallback {
constructor(type, callbackFunction) {
this.callbackFunction = callbackFunction;
this.type = type;
}
} }
// export Classes from this module // export Classes from this module
export {CorpusAnalysisClient, CorpusAnalysisDisplay, SocketEventListener}; export {
CorpusAnalysisClient,
CorpusAnalysisDisplay,
SocketEventListener,
ListenerCallback,
};

View File

@ -62,3 +62,6 @@ class InteractionElements {
}; };
} }
} }
// export Classes
export { InteractionElement, InteractionElements };

View File

@ -1,10 +1,8 @@
// This callback is called on socket.on "query".
// Does some hiding, showing disabling etc.
/** /**
* This call back is called when the SocketEventListener 'recieveQueryStatus' * This callback should be registered to the SocketEventListener 'recieveQueryStatus'.
* has been triggered. It just gets the incoming status data of the issued * It just gets the incoming status data of the issued query
* and does some preperation work like hiding or showing elements and deleting * and does some preperation work like hiding or showing elements and deleting
* the date from the last query. * the data from the last query.
*/ */
function querySetup(payload, client) { function querySetup(payload, client) {
// deletes old data from query issued before this new query // deletes old data from query issued before this new query
@ -12,23 +10,29 @@ function querySetup(payload, client) {
// load necessary HTMLElements with selectory syntax and save them as fields // load necessary HTMLElements with selectory syntax and save them as fields
client.getHTMLElements(['#query-progress-bar', '#query-results-user-feedback', client.getHTMLElements(['#query-progress-bar', '#query-results-user-feedback',
'#recieved-match-count', '#total-match-count', '#recieved-match-count', '#total-match-count',
'#text-lookup-count', '#text-lookup-titles']); '#text-lookup-count', '#text-lookup-titles',
'#query-results-create', '#add-to-sub-results']);
client.requestQueryProgress = 0; client.requestQueryProgress = 0;
client.recievedMatchCount.textContent = 0; client.recievedMatchCount.textContent = 0;
client.totalMatchCount.textContent = `${payload.match_count}`; client.totalMatchCount.textContent = `${payload.match_count}`;
client.queryResultsUserFeedback.classList.toggle('hide'); client.queryResultsUserFeedback.classList.toggle('hide');
client.queryProgressBar.classList.toggle('hide'); client.queryProgressBar.classList.toggle('hide');
client.queryProgressBar.lastElementChild.style.width = '0%' client.queryProgressBar.lastElementChild.style.width = '0%';
if (client.dynamicMode) {
client.addToSubResults.toggleAttribute('disabled');
client.queryResultsCreate.classList.toggle('disabled');
}
} }
/** /**
* This callback is called when the SocketEventListener 'recieveQueryData' * This callback should be registered to the SocketEventListener 'recieveQueryData'
* has been triggered. It takes the incoming chunk and renders the results in a * It takes the incoming chunk and renders the results using the
* the results.jsList. It can either handle live incoming data or imported * results.jsList object. It can either handle live incoming data chunks or
* results data. * already loaded/imported results data.
*/ */
function queryRenderResults(payload, client) { function queryRenderResults(payload, client) {
client.getHTMLElements(['#recieved-match-count', '#match-count']) client.getHTMLElements(['#recieved-match-count', '#match-count',
'#display-options-form-expert_mode']);
const renderResults = (data) => { const renderResults = (data) => {
/** /**
* resultItem saves the incoming chunk matches as objects to add those later * resultItem saves the incoming chunk matches as objects to add those later
@ -59,11 +63,10 @@ function queryRenderResults(payload, client) {
* activate, hide or show elements if all reults have been recieved * activate, hide or show elements if all reults have been recieved
* also load some new elements taht have not ben loaded before * also load some new elements taht have not ben loaded before
*/ */
client.getHTMLElements(['#query-results-create']);
client.queryProgressBar.classList.toggle('hide'); client.queryProgressBar.classList.toggle('hide');
client.queryResultsUserFeedback.classList.toggle('hide'); client.queryResultsUserFeedback.classList.toggle('hide');
client.queryResultsCreate.classList.toggle('disabled'); client.queryResultsCreate.classList.toggle('disabled');
// resultsExportElement.classList.remove("disabled"); client.addToSubResults.toggleAttribute('disabled');
// addToSubResultsElement.removeAttribute("disabled"); // addToSubResultsElement.removeAttribute("disabled");
// // inital expert mode check and sub results activation // // inital expert mode check and sub results activation
// client.results.jsList.activateInspect(); // client.results.jsList.activateInspect();
@ -75,19 +78,21 @@ function queryRenderResults(payload, client) {
// } // }
} }
} else if (!client.dynamicMode) { } else if (!client.dynamicMode) {
client.requestQueryProgress === 100;
client.queryResultsUserFeedback.classList.toggle('hide');
renderResults(payload); renderResults(payload);
helperQueryRenderResults({'chunk': payload}, client); helperQueryRenderResults({'chunk': payload}, client);
client.queryProgressBar.classList.toggle('hide'); client.queryProgressBar.classList.toggle('hide');
client.queryResultsUserFeedback.classList.toggle('hide'); client.queryResultsUserFeedback.classList.toggle('hide');
client.results.jsList.activateInspect(); client.results.jsList.activateInspect();
if (expertModeSwitchElement.checked) { if (client.displayOptionsFormExpertMode.checked) {
client.results.jsList.expertModeOn("query-display"); client.results.jsList.expertModeOn("query-display");
} }
} }
} }
/**
* Helper function that saves result data into the client.results.data object.
* Also does some showing and hiding of Elements and user feedback text.
*/
function helperQueryRenderResults (payload, client) { function helperQueryRenderResults (payload, client) {
// updating table on finished item creation callback via createResultRowElement // updating table on finished item creation callback via createResultRowElement
client.results.jsList.update(); client.results.jsList.update();
@ -111,6 +116,5 @@ function helperQueryRenderResults (payload, client) {
client.requestQueryProgress = payload.progress; client.requestQueryProgress = payload.progress;
} }
// TODO: Add data to data objekt using its own socket on event? // export callbacks
export { querySetup, queryRenderResults };
export { querySetup, queryRenderResults }

View File

@ -5,10 +5,10 @@ import { querySetup, queryRenderResults } from './nopaque.listenerCallbacks.js'
* Closes the loading modal that has been opend with requestSession at the * Closes the loading modal that has been opend with requestSession at the
* start of the request. * start of the request.
*/ */
function recieveSession(client) { function recieveSession(type, client) {
client.socket.on('corpus_analysis_init', (response) => { client.socket.on(type, (response) => {
/** /**
* Check if request for session was ok. * Check if request for session was OK.
* If OK execute callbacks and hide/show displays. * If OK execute callbacks and hide/show displays.
*/ */
console.group('recieve session') console.group('recieve session')
@ -44,11 +44,11 @@ function recieveSession(client) {
* was invalid etc. * was invalid etc.
* Also prepares the result.jsList for the incoming data. * Also prepares the result.jsList for the incoming data.
*/ */
function recieveQueryStatus(client) { function recieveQueryStatus(type, client) {
client.socket.on('corpus_analysis_query', (response) => { client.socket.on(type, (response) => {
/** /**
* Check if issued query was ok. * Check if issued query was OK.
* If OK execute callbacks and hide/show displays. * If OK execute registered callbacks and hide/show displays.
*/ */
console.group('corpus_analysis_query: Client recieving query process', console.group('corpus_analysis_query: Client recieving query process',
'status via socket.on'); 'status via socket.on');
@ -59,8 +59,8 @@ function recieveQueryStatus(client) {
if (client.displays.query != undefined) { if (client.displays.query != undefined) {
client.displays.query.setVisibilityByStatus("success"); client.displays.query.setVisibilityByStatus("success");
} }
// executing the callbacks // executing the registered callbacks
querySetup(response.payload, client); client.socketEventListeners[type].executeCallbacks([response.payload, client]);
} else { } else {
let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; let errorText = `Error ${response.payload.code} - ${response.payload.msg}`;
if (response.payload.code == 1281) { if (response.payload.code == 1281) {
@ -83,20 +83,22 @@ function recieveQueryStatus(client) {
/** /**
* Recieves the query data from the request and handles it. * Recieves the query data from the request and handles it.
*/ */
function recieveQueryData(client) { function recieveQueryData(type, client) {
console.group('corpus_analysis_query_results: Client recieving or loading', console.group('corpus_analysis_query_results: Client recieving or loading',
'query data.'); 'query data.');
if (client.dynamicMode) { if (client.dynamicMode) {
console.info('Client recieving query data via socket.on'); console.info('Client recieving query data via socket.on');
client.socket.on('corpus_analysis_query_results', (response) => { client.socket.on(type, (response) => {
console.info('Recieved chunk', response); console.info('Recieved chunk', response);
queryRenderResults(response.payload, client); // executing the registered callbacks
client.socketEventListeners[type].executeCallbacks([response.payload, client]);
console.info('Added chunk data to results.data and rendered it with', console.info('Added chunk data to results.data and rendered it with',
'results.jsList'); 'results.jsList');
}); });
} else { } else {
console.info('Client loading imported query data from database.'); console.info('Client loading imported query data from database.');
queryRenderResults(client.results.data, client); // executing the registered callbacks
client.socketEventListeners[type].executeCallbacks([client.results.data, client]);
} }
console.groupEnd(); console.groupEnd();
} }

View File

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

View File

@ -425,6 +425,10 @@ RessourceList.options = {
class ResultsList extends List { class ResultsList extends List {
/**
* If no options are given when a new instance of this class is created
* the options below are used.
*/
static options = { static options = {
page: 10, page: 10,
pagination: [{ pagination: [{
@ -443,12 +447,19 @@ class ResultsList extends List {
constructor(idOrElement, options) { constructor(idOrElement, options) {
super(idOrElement, options); super(idOrElement, options);
this.options = options; this.options = options;
this.eventTokens = {}; // all span tokens which are holdeing events if expert /**
// mode is on. Collected here to delete later on * All span tokens which are holding events if expert
this.currentExpertTokenElements = {}; // all token elements which have added * mode is on. Collected here to delete later on.
// classes like chip and hoverable for expert view. Collected */
//here to delete later on this.eventTokens = {};
this.addToSubResultsStatus = {}; // holds True/false for check buttons used to add matches tu sub-results. If checked, it is True. If unchecked, it is false. Buttons for this have the class add. Those little round check buttons. /**
* all token elements which have added
* classes like chip and hoverable for expert view. Collected
* here to delete later on
*/
this.currentExpertTokenElements = {};
// holds True/false for check buttons used to add matches tu sub-results. If checked, it is True. If unchecked, it is false. Buttons for this have the class add. Those little round check buttons.
this.addToSubResultsStatus = {};
this.addToSubResultsIdsToShow = new Set(); // If check button is pressed its corresponding data_index is saved in this set. The set is shown to the user. this.addToSubResultsIdsToShow = new Set(); // If check button is pressed its corresponding data_index is saved in this set. The set is shown to the user.
} }
@ -620,7 +631,7 @@ class ResultsList extends List {
// ###### 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() {
if (progress === 100) { if (this.requestQueryProgress === 100) {
let inspectBtnElements; let inspectBtnElements;
inspectBtnElements = document.getElementsByClassName("inspect"); inspectBtnElements = document.getElementsByClassName("inspect");
for (let inspectBtn of inspectBtnElements) { for (let inspectBtn of inspectBtnElements) {
@ -958,45 +969,43 @@ class ResultsList extends List {
// ###### 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
tooltipEventCreate(event) { tooltipEventCreate(event, client) {
// console.log("Create Tooltip on mouseover."); // console.log("Create Tooltip on mouseover.");
let token; let token = client.results.data.cpos_lookup[event.target.dataset.cpos];
token = results.data.cpos_lookup[event.target.dataset.cpos];
if (!token) { if (!token) {
token = this.contextData.cpos_lookup[event.target.dataset.cpos]; token = this.contextData.cpos_lookup[event.target.dataset.cpos];
} }
this.addToolTipToTokenElement(event.target, token); this.addToolTipToTokenElement(event.target, token, client);
} }
// Function to destroy the current Tooltip for the current hovered tooltip // Function to destroy the current Tooltip for the current hovered tooltip
// on mouse leave // on mouse leave
tooltipEventDestroy(event) { tooltipEventDestroy() {
// console.log("Tooltip destroy on leave."); // console.log("Tooltip destroy on leave.");
this.currentTooltipElement.destroy(); this.currentTooltipElement.destroy();
} }
expertModeOn(htmlId) {
// turn 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
expertModeOn(htmlId, client) {
if (!Array.isArray(this.currentExpertTokenElements[htmlId])) { if (!Array.isArray(this.currentExpertTokenElements[htmlId])) {
this.currentExpertTokenElements[htmlId] = []; this.currentExpertTokenElements[htmlId] = [];
} }
let container = document.getElementById(htmlId); let container = document.getElementById(htmlId);
let tokens = container.querySelectorAll("span.token"); let tokens = container.querySelectorAll("span.token");
this.currentExpertTokenElements[htmlId].push(...tokens); this.currentExpertTokenElements[htmlId].push(...tokens);
this.tooltipEventCreateBind = this.tooltipEventCreate.bind(this);
this.tooltipEventDestroyBind = this.tooltipEventDestroy.bind(this);
this.eventTokens[htmlId] = []; this.eventTokens[htmlId] = [];
for (let tokenElement of this.currentExpertTokenElements[htmlId]) { for (let tokenElement of this.currentExpertTokenElements[htmlId]) {
tokenElement.classList.add("chip", "hoverable", "expert-view"); tokenElement.classList.add("chip", "hoverable", "expert-view");
tokenElement.onmouseover = this.tooltipEventCreateBind; const eventCreate = (event, arg) => this.tooltipEventCreate(event, arg);
tokenElement.onmouseout = this.tooltipEventDestroyBind; tokenElement.onmouseover = (event) => eventCreate(event, client);
tokenElement.onmouseout = () => this.tooltipEventDestroy();
this.eventTokens[htmlId].push(tokenElement); this.eventTokens[htmlId].push(tokenElement);
} }
} }
// fuction that creates Tooltip for one token and extracts the corresponding // fuction that creates Tooltip for one token and extracts the corresponding
// infos from the result JSON // infos from the result JSON
addToolTipToTokenElement(tokenElement, token) { addToolTipToTokenElement(tokenElement, token, client) {
this.currentTooltipElement; this.currentTooltipElement;
this.currentTooltipElement = M.Tooltip.init(tokenElement, this.currentTooltipElement = M.Tooltip.init(tokenElement,
{"html": `<table> {"html": `<table>
@ -1013,11 +1022,11 @@ class ResultsList extends List {
NER: ${token.ner} NER: ${token.ner}
</td> </td>
<td class="left-align"> <td class="left-align">
Title: ${results.data.text_lookup[token.text].title} Title: ${client.results.data.text_lookup[token.text].title}
<br> <br>
Author: ${results.data.text_lookup[token.text].author} Author: ${client.results.data.text_lookup[token.text].author}
<br> <br>
Publishing year: ${results.data.text_lookup[token.text].publishing_year} Publishing year: ${client.results.data.text_lookup[token.text].publishing_year}
</td> </td>
</tr> </tr>
</table>`} </table>`}

View File

@ -69,22 +69,45 @@
<script type="module"> <script type="module">
/** /**
* First Phase: * First Phase:
* document content is loaded and scripts are being imported and executed * Document content is loaded and scripts are being imported and executed.
*/ */
import { CorpusAnalysisClient, import {
CorpusAnalysisClient,
CorpusAnalysisDisplay, CorpusAnalysisDisplay,
SocketEventListener } from '../../static/js/modules/nopaque.CorpusAnalysisClient.js'; SocketEventListener,
import { recieveSession, recieveQueryStatus, ListenerCallback,
recieveQueryData } from '../../static/js/modules/nopaque.listenerFunctions.js'; } from '../../static/js/modules/nopaque.CorpusAnalysisClient.js';
import { Results, Data, MetaData } from '../../static/js/nopaque.Results.js'; import {
import { ResultsList } from '../../static/js/nopaque.lists.js'; recieveSession,
recieveQueryStatus,
recieveQueryData,
} from '../../static/js/modules/nopaque.listenerFunctions.js';
import {
querySetup,
queryRenderResults,
} from '../../static/js/modules/nopaque.listenerCallbacks.js'
import {
Results,
Data,
MetaData,
} from '../../static/js/nopaque.Results.js';
import {
ResultsList,
} from '../../static/js/nopaque.lists.js';
import {
scrollToTop,
} from '../../static/js/modules/nopaque.scrollToTop.js';
import {
InteractionElement,
InteractionElements,
} from '../../static/js/modules/nopaque.InteractionElement.js';
/** /**
* Second Phase: * Second Phase:
* Asynchronus and event driven code * Asynchronus and event driven code
*/ */
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
// Initialize the CorpusAnalysisClient // Initialize the CorpusAnalysisClient dynamic mode
let corpusId = {{ corpus_id}} let corpusId = {{ corpus_id}}
const client = new CorpusAnalysisClient({'corpusId': corpusId, const client = new CorpusAnalysisClient({'corpusId': corpusId,
'socket': nopaque.socket, 'socket': nopaque.socket,
@ -95,7 +118,7 @@ document.addEventListener("DOMContentLoaded", () => {
const initLoadingElement = document.getElementById("init-display"); const initLoadingElement = document.getElementById("init-display");
const initLoadingModal = M.Modal.init(initLoadingElement, const initLoadingModal = M.Modal.init(initLoadingElement,
{"dismissible": false}); {"dismissible": false});
// Set up display elements which hare show depending on the client status // Set up display elements which are shown depending on the client status
const initLoadingDisplay = new CorpusAnalysisDisplay(initLoadingModal); const initLoadingDisplay = new CorpusAnalysisDisplay(initLoadingModal);
client.getHTMLElements(['#query-display']); client.getHTMLElements(['#query-display']);
const queryDisplay = new CorpusAnalysisDisplay(client.queryDisplay); const queryDisplay = new CorpusAnalysisDisplay(client.queryDisplay);
@ -105,8 +128,6 @@ document.addEventListener("DOMContentLoaded", () => {
/** /**
* Initializing the results object holding all the data of a query. * Initializing the results object holding all the data of a query.
* Also holds the metadata of one query. * Also holds the metadata of one query.
* resultsListOptions is set to determine how many results per page are
* shown etc.
* Lastly it contains the object ResultsList which is a list.js * Lastly it contains the object ResultsList which is a list.js
* subclass which handles the visual representation of the query data. * subclass which handles the visual representation of the query data.
*/ */
@ -116,16 +137,70 @@ document.addEventListener("DOMContentLoaded", () => {
let resultsList = new ResultsList("result-list", ResultsList.options); let resultsList = new ResultsList("result-list", ResultsList.options);
let resultsMetaData = new MetaData(); let resultsMetaData = new MetaData();
let results = new Results(data, resultsList, resultsMetaData); let results = new Results(data, resultsList, resultsMetaData);
// make results part of the client // Make results part of the client
client.results = results; client.results = results;
console.info('Initialized the Results object.') console.info('Initialized the Results object.')
// register listeners listening to socket.io events and load them /**
* Initialization of interactionElemnts
* An interactionElement is an object identifing a switch or button via
* htmlID. Callbacks are set for these elements which will be triggered on
* a pagination interaction by the user or if the status of the element has
* been altered. (Like the switche has ben turned on or off).
*/
let interactionElements = new InteractionElements();
const expertModeInteraction = new InteractionElement("display-options-form-expert_mode");
expertModeInteraction.setCallback('on',
results.jsList.expertModeOn,
results.jsList,
['query-display', client]);
expertModeInteraction.setCallback('off',
results.jsList.expertModeOff,
results.jsList,
['query-display', client]);
const subResultsInteraction = new InteractionElement("add-to-sub-results");
subResultsInteraction.setCallback('on',
results.jsList.activateAddToSubResults,
results.jsList);
subResultsInteraction.setCallback('off',
results.jsList.deactivateAddToSubResults,
results.jsList);
const activateInspectInteraction = new InteractionElement('inspect',
false);
activateInspectInteraction.setCallback('noCheck',
results.jsList.activateInspect,
results.jsList);
const changeContextInteraction = new InteractionElement('display-options-form-results_per_page',
false);
changeContextInteraction.setCallback('noCheck',
results.jsList.changeContext,
results.jsList)
interactionElements.addInteractions([expertModeInteraction,
subResultsInteraction,
activateInspectInteraction,
changeContextInteraction]);
/**
* Checks if a change for every interactionElement happens and executes
* the callbacks accordingly.
*/
interactionElements.onChangeExecute();
/**
* Register listeners listening to socket.io events and their callbacks
* Afterwards load them.
*/
const listenForSession = new SocketEventListener('corpus_analysis_init', const listenForSession = new SocketEventListener('corpus_analysis_init',
recieveSession); recieveSession);
const listenForQueryStatus = new SocketEventListener('corpus_analysis_query', const listenForQueryStatus = new SocketEventListener('corpus_analysis_query',
recieveQueryStatus); recieveQueryStatus);
const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
querySetup);
listenForQueryStatus.setCallbacks([queryStatusCallback]);
const listenForQueryData = new SocketEventListener('corpus_analysis_query_results', const listenForQueryData = new SocketEventListener('corpus_analysis_query_results',
recieveQueryData); recieveQueryData);
const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
queryRenderResults);
listenForQueryData.setCallbacks([queryDataCallback]);
client.setSocketEventListeners([listenForSession, listenForQueryStatus, client.setSocketEventListeners([listenForSession, listenForQueryStatus,
listenForQueryData]); listenForQueryData]);
client.loadSocketEventListeners(); client.loadSocketEventListeners();
@ -153,6 +228,9 @@ document.addEventListener("DOMContentLoaded", () => {
// Get query string and send query to server // Get query string and send query to server
results.data.getQueryStr(queryFormElement); results.data.getQueryStr(queryFormElement);
client.requestQueryData(results.data.query); client.requestQueryData(results.data.query);
// Add scrollToTop functionality
scrollToTop();
}); });
}); });
</script> </script>

View File

@ -10,8 +10,7 @@ results.-->
Sub-Results creation: Sub-Results creation:
<label> <label>
Off Off
<input disabled <input type="checkbox"
type="checkbox"
id="add-to-sub-results"> id="add-to-sub-results">
<span class="lever"></span> <span class="lever"></span>
On On

View File

@ -9,7 +9,6 @@ the selected sub results.-->
<button class="waves-effect <button class="waves-effect
waves-light waves-light
btn-flat btn-flat
disabled
flat-interaction" flat-interaction"
type="submit" type="submit"
id="query-results-create">Create Results id="query-results-create">Create Results
@ -30,7 +29,6 @@ the selected sub results.-->
waves-light waves-light
btn-flat btn-flat
hide hide
disabled
flat-interaction" flat-interaction"
type="submit" type="submit"
id="sub-results-create">Create Sub-Results id="sub-results-create">Create Sub-Results

View File

@ -59,21 +59,39 @@
* First Phase: * First Phase:
* document content is loaded and scripts are being imported and executed * document content is loaded and scripts are being imported and executed
*/ */
import { CorpusAnalysisClient, import {
CorpusAnalysisClient,
CorpusAnalysisDisplay, CorpusAnalysisDisplay,
SocketEventListener } from '../../static/js/modules/nopaque.CorpusAnalysisClient.js'; SocketEventListener,
import { recieveSession, recieveQueryStatus, ListenerCallback,
recieveQueryData } from '../../static/js/modules/nopaque.listenerFunctions.js'; } from '../../static/js/modules/nopaque.CorpusAnalysisClient.js';
import { Results, Data, MetaData } from '../../static/js/nopaque.Results.js'; import {
import { ResultsList } from '../../static/js/nopaque.lists.js'; recieveSession,
import { queryRenderResults, querySetup } from '../../static/js/modules/nopaque.listenerCallbacks.js' recieveQueryStatus,
recieveQueryData,
} from '../../static/js/modules/nopaque.listenerFunctions.js';
import {
querySetup,
queryRenderResults,
} from '../../static/js/modules/nopaque.listenerCallbacks.js'
import {
Results,
Data,
MetaData,
} from '../../static/js/nopaque.Results.js';
import {
ResultsList,
} from '../../static/js/nopaque.lists.js';
import {
scrollToTop,
} from '../../static/js/modules/nopaque.scrollToTop.js';
/** /**
* Second Phase: * Second Phase:
* Asynchronus and event driven code * Asynchronus and event driven code
*/ */
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
// Initialize the CorpusAnalysisClient // Initialize the CorpusAnalysisClient with dynamicMode as false
const client = new CorpusAnalysisClient({'logging': true, const client = new CorpusAnalysisClient({'logging': true,
'dynamicMode': false}); 'dynamicMode': false});
console.info("CorpusAnalysisClient created as client:", client); console.info("CorpusAnalysisClient created as client:", client);
@ -85,8 +103,6 @@ document.addEventListener("DOMContentLoaded", () => {
/** /**
* Initializing the results object holding all the data of a query. * Initializing the results object holding all the data of a query.
* Also holds the metadata of one query. * Also holds the metadata of one query.
* resultsListOptions is set to determine how many results per page are
* shown etc.
* Lastly it contains the object ResultsList which is a list.js * Lastly it contains the object ResultsList which is a list.js
* subclass which handles the visual representation of the query data. * subclass which handles the visual representation of the query data.
*/ */
@ -114,7 +130,22 @@ document.addEventListener("DOMContentLoaded", () => {
'onOpenEnd': deleteOverlay}); 'onOpenEnd': deleteOverlay});
// saving imported data into client object // saving imported data into client object
const payload = {{ query_result_file_content|tojson|safe }}; const payload = {{ query_result_file_content|tojson|safe }};
/**
* Register listeners and their callbacks. Because we are using the client
* not in dynamic mode we will not load the listeners. We just call the
* callbacks of the listeners manually. This is done to keep the setup of
* the client in dynamic or not dynamic mode similarish.
*/
const listenForQueryStatus = new SocketEventListener('corpus_analysis_query',
recieveQueryStatus);
const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
querySetup);
listenForQueryStatus.setCallbacks([queryStatusCallback]);
const listenForQueryData = new SocketEventListener('corpus_analysis_query_results',
recieveQueryData);
const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
queryRenderResults);
listenForQueryData.setCallbacks([queryDataCallback]);
// //
// // Initialization of interactionElemnts // // Initialization of interactionElemnts
@ -160,9 +191,8 @@ document.addEventListener("DOMContentLoaded", () => {
// } // }
// //
// render results directly with callbacks because we are not in dynamic mode // render results directly with callbacks because we are not in dynamic mode
querySetup(payload, client); listenForQueryStatus.listenerCallbacks['corpus_analysis_query'].callbackFunction(payload, client);
queryRenderResults(payload, client); listenForQueryData.listenerCallbacks['corpus_analysis_query_results'].callbackFunction(payload, client);
// // ### Show corpus Metadata // // ### Show corpus Metadata
// showMetaDataButton.onclick = () => { // showMetaDataButton.onclick = () => {
// metaDataModal.open(); // metaDataModal.open();
@ -185,19 +215,8 @@ document.addEventListener("DOMContentLoaded", () => {
// } // }
// }); // });
// //
// // scroll to top button if user scrolled down the list // Add scrollToTop functionality
// let headline = document.querySelector(".headline"); scrollToTop();
// let scrollToTop = document.querySelector("#menu-scroll-to-top-div");
// window.addEventListener("scroll", (event) => {
// if (pageYOffset > 250) {
// scrollToTop.classList.toggle("hide", false);
// } else {
// scrollToTop.classList.toggle("hide", true);
// }
// });
// scrollToTop.onclick = () => {
// headline.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
// };
}); });
</script> </script>
{% endblock %} {% endblock %}