mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2025-06-28 08:50:34 +00:00
Push before rework part 2
This commit is contained in:
@ -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.
|
||||
* 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 {
|
||||
constructor({corpusId = null,
|
||||
@ -19,11 +21,9 @@ class CorpusAnalysisClient {
|
||||
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) {
|
||||
(() => {
|
||||
let console = (window.console = window.console || {});
|
||||
@ -32,7 +32,7 @@ class CorpusAnalysisClient {
|
||||
'error', 'exception', 'group', 'groupCollapsed', 'groupEnd',
|
||||
'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table',
|
||||
'time', 'timeEnd', 'timeStamp', 'trace', 'warn'
|
||||
].forEach(method => {
|
||||
].forEach((method) => {
|
||||
console[method] = () => {};
|
||||
});
|
||||
})();
|
||||
@ -41,14 +41,18 @@ class CorpusAnalysisClient {
|
||||
|
||||
// Registers one or more SocketEventListeners to the CorpusAnalysisClient.
|
||||
setSocketEventListeners(socketEventListeners) {
|
||||
for (let listener of socketEventListeners) {
|
||||
this.socketEventListeners[listener.type] = listener.listenerFunction;
|
||||
for (let socketEventListener of socketEventListeners) {
|
||||
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() {
|
||||
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
|
||||
* Field name i. e. #html-id-string -> this.htmlIdString
|
||||
* 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) {
|
||||
let element = document.querySelector(selector);
|
||||
let cleanKey = [];
|
||||
selector = selector.replace('_', '-');
|
||||
selector.match(/\w+/g).forEach((word) => {
|
||||
let tmp = word[0].toUpperCase() + word.slice(1);
|
||||
cleanKey.push(tmp);
|
||||
@ -82,7 +88,8 @@ class CorpusAnalysisClient {
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
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) {
|
||||
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.
|
||||
* Input is one HTMLElement that can then be hidden or shown depending on
|
||||
* its CSS classes.
|
||||
* This class is used to create an SocketEventListener.
|
||||
* Input are an identifying type string, the listener function and callbacks
|
||||
* 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 {
|
||||
constructor(type, listenerFunction) {
|
||||
this.listenerCallbacks = {};
|
||||
this.listenerFunction = listenerFunction;
|
||||
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 {CorpusAnalysisClient, CorpusAnalysisDisplay, SocketEventListener};
|
||||
export {
|
||||
CorpusAnalysisClient,
|
||||
CorpusAnalysisDisplay,
|
||||
SocketEventListener,
|
||||
ListenerCallback,
|
||||
};
|
67
web/app/static/js/modules/nopaque.InteractionElement.js
Normal file
67
web/app/static/js/modules/nopaque.InteractionElement.js
Normal file
@ -0,0 +1,67 @@
|
||||
class InteractionElement {
|
||||
constructor(htmlId="",
|
||||
checkStatus=true,
|
||||
disabledBefore=true,
|
||||
disabledAfter=false,
|
||||
hideBefore=true,
|
||||
hideAfter=false) {
|
||||
this.htmlId = htmlId;
|
||||
this.element = (htmlId) => {this.element = document.getElementById(htmlId);}
|
||||
this.checkStatus = checkStatus;
|
||||
this.callbacks = {};
|
||||
this.disabledBefore = disabledBefore;
|
||||
this.disabledAfter = disabledAfter;
|
||||
this.hideBefore = hideBefore;
|
||||
this.hideAfter = hideAfter;
|
||||
this.element(this.htmlId);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
class InteractionElements {
|
||||
constructor() {
|
||||
this.interactions = [];
|
||||
}
|
||||
|
||||
addInteractions (interactionsArray) {
|
||||
this.interactions.push(...interactionsArray);
|
||||
}
|
||||
|
||||
onChangeExecute() {
|
||||
// checks if a change for every interactionElement happens and executes
|
||||
// the callbacks accordingly
|
||||
for (let interaction of this.interactions) {
|
||||
if (interaction.checkStatus) {
|
||||
interaction.element.addEventListener("change", (event) => {
|
||||
if (event.target.checked) {
|
||||
let f_on = interaction.bindThisToCallback("on");
|
||||
let args_on = interaction.callbacks.on.args;
|
||||
f_on(...args_on);
|
||||
} else if (!event.target.checked){
|
||||
let f_off = interaction.bindThisToCallback("off");
|
||||
let args_off = interaction.callbacks.off.args;
|
||||
f_off(...args_off);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// export Classes
|
||||
export { InteractionElement, InteractionElements };
|
@ -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'
|
||||
* has been triggered. It just gets the incoming status data of the issued
|
||||
* This callback should be registered to the SocketEventListener 'recieveQueryStatus'.
|
||||
* It just gets the incoming status data of the issued query
|
||||
* 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) {
|
||||
// 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
|
||||
client.getHTMLElements(['#query-progress-bar', '#query-results-user-feedback',
|
||||
'#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.recievedMatchCount.textContent = 0;
|
||||
client.totalMatchCount.textContent = `${payload.match_count}`;
|
||||
client.queryResultsUserFeedback.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'
|
||||
* has been triggered. It takes the incoming chunk and renders the results in a
|
||||
* the results.jsList. It can either handle live incoming data or imported
|
||||
* results data.
|
||||
* This callback should be registered to the SocketEventListener 'recieveQueryData'
|
||||
* It takes the incoming chunk and renders the results using the
|
||||
* results.jsList object. It can either handle live incoming data chunks or
|
||||
* already loaded/imported results data.
|
||||
*/
|
||||
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) => {
|
||||
/**
|
||||
* 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
|
||||
* also load some new elements taht have not ben loaded before
|
||||
*/
|
||||
client.getHTMLElements(['#query-results-create']);
|
||||
client.queryProgressBar.classList.toggle('hide');
|
||||
client.queryResultsUserFeedback.classList.toggle('hide');
|
||||
client.queryResultsCreate.classList.toggle('disabled');
|
||||
// resultsExportElement.classList.remove("disabled");
|
||||
client.addToSubResults.toggleAttribute('disabled');
|
||||
// addToSubResultsElement.removeAttribute("disabled");
|
||||
// // inital expert mode check and sub results activation
|
||||
// client.results.jsList.activateInspect();
|
||||
@ -75,19 +78,21 @@ function queryRenderResults(payload, client) {
|
||||
// }
|
||||
}
|
||||
} else if (!client.dynamicMode) {
|
||||
client.requestQueryProgress === 100;
|
||||
client.queryResultsUserFeedback.classList.toggle('hide');
|
||||
renderResults(payload);
|
||||
helperQueryRenderResults({'chunk': payload}, client);
|
||||
client.queryProgressBar.classList.toggle('hide');
|
||||
client.queryResultsUserFeedback.classList.toggle('hide');
|
||||
client.results.jsList.activateInspect();
|
||||
if (expertModeSwitchElement.checked) {
|
||||
if (client.displayOptionsFormExpertMode.checked) {
|
||||
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) {
|
||||
// updating table on finished item creation callback via createResultRowElement
|
||||
client.results.jsList.update();
|
||||
@ -111,6 +116,5 @@ function helperQueryRenderResults (payload, client) {
|
||||
client.requestQueryProgress = payload.progress;
|
||||
}
|
||||
|
||||
// TODO: Add data to data objekt using its own socket on event?
|
||||
|
||||
export { querySetup, queryRenderResults }
|
||||
// export callbacks
|
||||
export { querySetup, queryRenderResults };
|
@ -5,10 +5,10 @@ import { querySetup, queryRenderResults } from './nopaque.listenerCallbacks.js'
|
||||
* Closes the loading modal that has been opend with requestSession at the
|
||||
* start of the request.
|
||||
*/
|
||||
function recieveSession(client) {
|
||||
client.socket.on('corpus_analysis_init', (response) => {
|
||||
function recieveSession(type, client) {
|
||||
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.
|
||||
*/
|
||||
console.group('recieve session')
|
||||
@ -44,11 +44,11 @@ function recieveSession(client) {
|
||||
* was invalid etc.
|
||||
* Also prepares the result.jsList for the incoming data.
|
||||
*/
|
||||
function recieveQueryStatus(client) {
|
||||
client.socket.on('corpus_analysis_query', (response) => {
|
||||
function recieveQueryStatus(type, client) {
|
||||
client.socket.on(type, (response) => {
|
||||
/**
|
||||
* Check if issued query was ok.
|
||||
* If OK execute callbacks and hide/show displays.
|
||||
* Check if issued query was OK.
|
||||
* If OK execute registered callbacks and hide/show displays.
|
||||
*/
|
||||
console.group('corpus_analysis_query: Client recieving query process',
|
||||
'status via socket.on');
|
||||
@ -59,8 +59,8 @@ function recieveQueryStatus(client) {
|
||||
if (client.displays.query != undefined) {
|
||||
client.displays.query.setVisibilityByStatus("success");
|
||||
}
|
||||
// executing the callbacks
|
||||
querySetup(response.payload, client);
|
||||
// executing the registered callbacks
|
||||
client.socketEventListeners[type].executeCallbacks([response.payload, client]);
|
||||
} else {
|
||||
let errorText = `Error ${response.payload.code} - ${response.payload.msg}`;
|
||||
if (response.payload.code == 1281) {
|
||||
@ -83,20 +83,22 @@ function recieveQueryStatus(client) {
|
||||
/**
|
||||
* 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',
|
||||
'query data.');
|
||||
if (client.dynamicMode) {
|
||||
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);
|
||||
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',
|
||||
'results.jsList');
|
||||
});
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
|
21
web/app/static/js/modules/nopaque.scrollToTop.js
Normal file
21
web/app/static/js/modules/nopaque.scrollToTop.js
Normal 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 };
|
Reference in New Issue
Block a user