mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-11-15 01:05:42 +00:00
Work on View notifications
This commit is contained in:
parent
0507ae4e34
commit
d2453c2cc3
@ -17,7 +17,8 @@ class Client {
|
||||
this.requestQueryProgress = 0;
|
||||
this.socket = socket;
|
||||
this.socketEventListeners = {};
|
||||
this.recivedMetaData = false;
|
||||
this.connected = false;
|
||||
|
||||
|
||||
/**
|
||||
* Disable all console logging.
|
||||
@ -61,10 +62,16 @@ class Client {
|
||||
|
||||
/**
|
||||
* This functions sends events to the View to trigger specific functions that
|
||||
* are handleing the represnetation of data stored in the model.
|
||||
* are handleing the representation of data stored in the model.
|
||||
*/
|
||||
notifyView(SendWhatToDo) {
|
||||
|
||||
notifyView(caseIdentifier, msg=null) {
|
||||
const event = new CustomEvent('notify', { detail: {
|
||||
'caseIdentifier': caseIdentifier,
|
||||
'msg': msg
|
||||
}
|
||||
});
|
||||
console.info('Dispatching Notification:', caseIdentifier);
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
// Registers a CorpusAnalysisDisplay object to the Client.
|
||||
@ -72,31 +79,6 @@ class Client {
|
||||
this.displays[type] = corpusAnalysisDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that takes one or more query selector
|
||||
* strings in an array as an input. The function then creates a
|
||||
* class field in the client object with the query selector
|
||||
* 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.
|
||||
*/
|
||||
// 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);
|
||||
});
|
||||
cleanKey[0] = cleanKey[0].toLowerCase();
|
||||
cleanKey = cleanKey.join('');
|
||||
this[cleanKey] = element;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the corpus analysis session for the specified corpus via
|
||||
* socket.io.
|
||||
@ -159,8 +141,7 @@ class SocketEventListener {
|
||||
*/
|
||||
executeCallbacks(payload) {
|
||||
for (let [type, listenerCallback] of Object.entries(this.listenerCallbacks)) {
|
||||
listenerCallback.args.unshift(payload);
|
||||
listenerCallback.callbackFunction(...listenerCallback.args);
|
||||
listenerCallback.callbackFunction(payload, ...listenerCallback.args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ function saveMetaData() {
|
||||
let [payload, client, results, rest] = arguments;
|
||||
results.metaData.init(payload)
|
||||
client.recivedMetaData = true;
|
||||
console.info('Metada saved:', results.metaData);
|
||||
console.info('Metada saved:', results);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -20,14 +20,23 @@ function prepareQueryData() {
|
||||
let [payload, client, results, rest] = arguments;
|
||||
results.init();
|
||||
client.requestQueryProgress = 0;
|
||||
|
||||
client.notifyView('query-data-prepareing');
|
||||
}
|
||||
|
||||
function saveQueryData(args) {
|
||||
let [payload, client, results, rest] = arguments;
|
||||
results.data.addData(payload);
|
||||
// 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;
|
||||
client.requestQueryProgress = payload.progress;
|
||||
client.notifyView('query-data-recieving')
|
||||
console.info('Query data chunk saved', results.data);
|
||||
if (client.requestQueryProgress === 100) {
|
||||
client.notifyView('query-data-recieved');
|
||||
}
|
||||
}
|
||||
|
||||
function querySetup(payload, client) {
|
||||
|
@ -1,3 +1,9 @@
|
||||
/**
|
||||
* This file contains the listener functions which can be assigned to the
|
||||
* coprus_analysis client. So that the incoming data/status informations will
|
||||
* be handled.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Recieves a corpus analysis connected signal via socket.io.
|
||||
*/
|
||||
@ -14,6 +20,7 @@ function recieveConnected(type, client) {
|
||||
console.info(`corpus_analysis_init: ${response.code} - ${response.msg}`);
|
||||
console.info('corpus_analysis_init: Initialization succeeded');
|
||||
console.info(response);
|
||||
client.notifyView('connected');
|
||||
console.groupEnd();
|
||||
// get meta data immediately
|
||||
client.getMetaData();
|
||||
@ -21,6 +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);
|
||||
console.groupEnd();
|
||||
}
|
||||
});
|
||||
|
@ -8,7 +8,6 @@ class Results {
|
||||
constructor() {
|
||||
this.data = new Data();
|
||||
this.metaData = new MetaData();
|
||||
this.resultsData = new Data();
|
||||
this.subResultsData = new Data();
|
||||
console.info('Initialized the Results object.');
|
||||
}
|
||||
@ -16,7 +15,6 @@ class Results {
|
||||
init() {
|
||||
this.data.init();
|
||||
this.metaData.init();
|
||||
this.resultsData.init()
|
||||
this.subResultsData.init();
|
||||
}
|
||||
|
||||
@ -32,6 +30,7 @@ class Data {
|
||||
this.text_lookup = {}; // same as above for all text ids
|
||||
this.match_count = matchCount;
|
||||
this.corpus_type = 'results';
|
||||
this.cpos_ranges = null;
|
||||
this.query = '';
|
||||
}
|
||||
|
||||
|
@ -1,73 +0,0 @@
|
||||
/**
|
||||
* This class is used to create an Display object.
|
||||
* Input is one HTMLElement that can then be hidden or shown depending on
|
||||
* its CSS classes.
|
||||
*/
|
||||
class Display {
|
||||
constructor(element) {
|
||||
// with this function initalized modals can also be handeld
|
||||
this.element = (() => {if (element instanceof HTMLElement) {
|
||||
return element;
|
||||
} else {
|
||||
element = element['$el'][0];
|
||||
return element;
|
||||
}
|
||||
})();
|
||||
this.errorContainer = element.querySelector('.error-container');
|
||||
this.showOnError = element.querySelectorAll('.show-on-error');
|
||||
this.showOnSuccess = element.querySelectorAll('.show-on-success');
|
||||
this.showWhileWaiting = element.querySelectorAll('.show-while-waiting');
|
||||
this.hideOnComplete = element.querySelectorAll('.hide-on-complete')
|
||||
}
|
||||
|
||||
// Changes the visibility of its own
|
||||
setVisibilityByStatus(status) {
|
||||
switch (status) {
|
||||
case 'error':
|
||||
for (let element of this.showOnError) {
|
||||
element.classList.remove('hide');
|
||||
}
|
||||
for (let element of this.showOnSuccess) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
for (let element of this.showWhileWaiting) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
break;
|
||||
case 'success':
|
||||
for (let element of this.showOnError) {
|
||||
element.classList.add('hide');
|
||||
|
||||
}
|
||||
for (let element of this.showOnSuccess) {
|
||||
element.classList.remove('hide');
|
||||
}
|
||||
for (let element of this.showWhileWaiting) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
break;
|
||||
case 'waiting':
|
||||
for (let element of this.showOnError) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
for (let element of this.showOnSuccess) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
for (let element of this.showWhileWaiting) {
|
||||
element.classList.remove('hide');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Hide all
|
||||
for (let element of this.showOnError) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
for (let element of this.showOnSuccess) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
for (let element of this.showWhileWaiting) {
|
||||
element.classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,20 @@
|
||||
/**
|
||||
* This class implements a NotificationListener that is listening for the
|
||||
* specified
|
||||
*/
|
||||
class NotificationListener {
|
||||
constructor(type, listenerFunction) {
|
||||
this.listenerFunction = listenerFunction;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is implements a View which handles the reprensentation of the
|
||||
* data that has been fetched by the Client of the corpus_analysis. This view
|
||||
* only handles how the data is shown to the user. View extends the list.js
|
||||
* List class.
|
||||
*/
|
||||
|
||||
class ResultsList extends List {
|
||||
/**
|
||||
* If no options are given when a new instance of this class is created
|
||||
@ -42,8 +52,58 @@ class ResultsList extends List {
|
||||
// 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.
|
||||
// notification listeners listening for client notifications (or other in the future?)
|
||||
this.notificationListeners = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that takes one or more query selector
|
||||
* strings in an array as an input. The function then creates a
|
||||
* class field in the ResultsList object with the query selector
|
||||
* 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.
|
||||
*/
|
||||
// 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);
|
||||
});
|
||||
cleanKey[0] = cleanKey[0].toLowerCase();
|
||||
cleanKey = cleanKey.join('');
|
||||
this[cleanKey] = element;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register notificationListeners to the ResultsList. Which will listen for
|
||||
* the specified event.
|
||||
*/
|
||||
setNotificationListeners(notificationListeners) {
|
||||
for (let notificationListener of notificationListeners) {
|
||||
this.notificationListeners[notificationListener.type] = notificationListener;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the notificationListeners so that hey will be listening to their
|
||||
* assigned custom events.
|
||||
*/
|
||||
loadNotificationListeners() {
|
||||
for (let [type, listener] of Object.entries(this.notificationListeners)) {
|
||||
listener.listenerFunction(type, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates cpos either from ranges or not.
|
||||
*/
|
||||
helperCreateCpos(cpos_ranges, cpos_values) {
|
||||
let lc;
|
||||
let c;
|
||||
@ -788,3 +848,6 @@ class ResultsList extends List {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// export classses
|
||||
export { NotificationListener, ResultsList };
|
35
web/app/static/js/modules/corpus_analysis/view/callbacks.js
Normal file
35
web/app/static/js/modules/corpus_analysis/view/callbacks.js
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* This file contains all the callbacks triggered by the notificationListener.
|
||||
*/
|
||||
|
||||
function connectingCallback(resultsList, msg=null) {
|
||||
resultsList.getHTMLElements(['#analysis-init-modal']);
|
||||
resultsList.analysisInitModal = M.Modal.init(resultsList.analysisInitModal,
|
||||
{dismissible: false});
|
||||
resultsList.analysisInitModal.open();
|
||||
}
|
||||
|
||||
function connectedCallback(resultsList, msg=null) {
|
||||
resultsList.analysisInitModal.close();
|
||||
}
|
||||
|
||||
function connectingFaildeCallback(resultsList, msg=null) {
|
||||
resultsList.getHTMLElements([
|
||||
'#analysis-init-progress',
|
||||
'#analysis-init-error'
|
||||
]);
|
||||
resultsList.analysisInitProgress.classList.toggle('hide');
|
||||
resultsList.analysisInitError.classList.toggle('hide');
|
||||
resultsList.analysisInitError.textContent = msg;
|
||||
}
|
||||
|
||||
function queryDataPreparingCallback(resultsList, msg=null) {
|
||||
resultsList.getHTMLElements(['#interactions-menu']);
|
||||
resultsList.interactionsMenu.classList.toggle('hide', false)
|
||||
}
|
||||
|
||||
// export the callbacks
|
||||
export { connectingCallback,
|
||||
connectedCallback,
|
||||
connectingFaildeCallback,
|
||||
queryDataPreparingCallback, };
|
57
web/app/static/js/modules/corpus_analysis/view/listeners.js
Normal file
57
web/app/static/js/modules/corpus_analysis/view/listeners.js
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* This file contains the listener function that will be assigned to the
|
||||
* corpus_analysis ResultsView. The listener is listening for the notification
|
||||
* event which is being dispatched by the corpus_analysis Client. The
|
||||
* notification Event triggers the listener whiche will call different
|
||||
* callback functions depending on the detail information of the notification
|
||||
* event.
|
||||
*/
|
||||
|
||||
import {
|
||||
connectingCallback,
|
||||
connectedCallback,
|
||||
connectingFaildeCallback,
|
||||
queryDataPreparingCallback,
|
||||
} from './callbacks.js';
|
||||
|
||||
function recieveNotification(eventType, resultsList) {
|
||||
document.addEventListener(eventType, (event) => {
|
||||
let caseIdentifier = event.detail.caseIdentifier;
|
||||
switch (caseIdentifier) {
|
||||
case 'connecting':
|
||||
console.info('Recieved notification:', caseIdentifier);
|
||||
connectingCallback(resultsList);
|
||||
// execute callback
|
||||
break;
|
||||
case 'connected':
|
||||
console.info('Recieved notification:', caseIdentifier);
|
||||
connectedCallback(resultsList);
|
||||
break;
|
||||
case 'connecting-failed':
|
||||
console.info('Recieved notification:', caseIdentifier);
|
||||
// execute callback
|
||||
connectingFaildeCallback(resultsList, event.detail.msg);
|
||||
break;
|
||||
case 'query-data-prepareing':
|
||||
console.info('Recieved notification:', caseIdentifier);
|
||||
// execute callback
|
||||
queryDataPreparingCallback(resultsList);
|
||||
break;
|
||||
case 'query-data-recieving':
|
||||
console.info('Recieved notification:', caseIdentifier);
|
||||
// execute callback
|
||||
break;
|
||||
case 'query-data-recieved':
|
||||
console.info('Recieved notification:', caseIdentifier);
|
||||
// execute callback
|
||||
break;
|
||||
default:
|
||||
console.error('Recieved unkown notification case identifier');
|
||||
// do something to not crash the analysis session?
|
||||
// maybe unnecessary
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// export listeners
|
||||
export { recieveNotification };
|
@ -41,8 +41,7 @@
|
||||
<div class="col s12" id="query-display">
|
||||
<div class="card">
|
||||
<div class="card-content" id="result-list" style="overflow: hidden;">
|
||||
<div class="error-container hide show-on-error"></div>
|
||||
<div class=" row hide show-on-success">
|
||||
<div id="interactions-menu" class="row hide">
|
||||
{% include 'interactions/infos.html.j2' %}
|
||||
{% include 'interactions/export.html.j2' %}
|
||||
{% include 'interactions/create.html.j2' %}
|
||||
@ -90,6 +89,13 @@ import {
|
||||
saveQueryData,
|
||||
saveMetaData,
|
||||
} from '../../static/js/modules/corpus_analysis/client/callbacks.js';
|
||||
import {
|
||||
NotificationListener,
|
||||
ResultsList,
|
||||
} from '../../static/js/modules/corpus_analysis/view/ResultsView.js';
|
||||
import {
|
||||
recieveNotification,
|
||||
} from '../../static/js/modules/corpus_analysis/view/listeners.js';
|
||||
|
||||
/**
|
||||
* Second Phase:
|
||||
@ -104,9 +110,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
'dynamicMode': true});
|
||||
/**
|
||||
* Initializing the results object as a model holding all the data of a query.
|
||||
* Also holds the metadata of one query.
|
||||
* Also holds the metadata of one query. After that initialize the ResultsList
|
||||
* object as the View handeling the represnetation of the data.
|
||||
*/
|
||||
let results = new Results();
|
||||
let resultsView = new ResultsList('result-list', ResultsList.options);
|
||||
/**
|
||||
* Register listeners listening to socket.io events and their callbacks
|
||||
* Afterwards load them.
|
||||
@ -136,8 +144,17 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
listenForQueryData,
|
||||
listenForMetaData]);
|
||||
client.loadSocketEventListeners();
|
||||
/**
|
||||
* Register resultsView listeners listening to nitification events.
|
||||
*/
|
||||
const listenForNotification = new NotificationListener('notify',
|
||||
recieveNotification);
|
||||
resultsView.setNotificationListeners([listenForNotification]);
|
||||
resultsView.loadNotificationListeners();
|
||||
// Connect client to server
|
||||
client.notifyView('connecting');
|
||||
client.connect();
|
||||
|
||||
// Send a query and recieve its answer data
|
||||
let queryFormElement = document.getElementById('query-form');
|
||||
queryFormElement.addEventListener('submit', (event) => {
|
||||
|
@ -1,12 +1,17 @@
|
||||
<!-- Analysis init modal. User feedback showing that the analysis session is
|
||||
loading. -->
|
||||
|
||||
<div class="modal no-autoinit" id="init-display">
|
||||
<div class="modal no-autoinit" id="analysis-init-modal">
|
||||
<div class="modal-content">
|
||||
<h4>Initializing your corpus analysis session...</h4>
|
||||
<div class="error-container hide show-on-error"></div>
|
||||
<div class="hide progress show-while-waiting">
|
||||
<p>If the loading takes to long or an error occured,
|
||||
<a onclick="window.location.reload()" href="#">click here</a>
|
||||
to refresh your session or
|
||||
<a href="{{ url_for('corpora.corpus', corpus_id=corpus_id) }}">go back</a>!
|
||||
</p>
|
||||
<div id="analysis-init-progress" class="progress">
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
<p id="analysis-init-error" class="hide red-text"></p>
|
||||
</div>
|
||||
</div>
|
@ -34,7 +34,7 @@
|
||||
<div class="col s12" id="query-display">
|
||||
<div class="card">
|
||||
<div class="card-content" id="result-list" style="overflow: hidden;">
|
||||
<div class=" row show-on-success">
|
||||
<div class="row">
|
||||
{% include 'interactions/infos.html.j2' %}
|
||||
{% include 'interactions/display.html.j2' %}
|
||||
{% include 'interactions/analysis.html.j2' %}
|
||||
|
Loading…
Reference in New Issue
Block a user