diff --git a/web/app/static/js/modules/corpus_analysis/client/Client.js b/web/app/static/js/modules/corpus_analysis/client/Client.js index 5e2c626c..bd4f92bc 100644 --- a/web/app/static/js/modules/corpus_analysis/client/Client.js +++ b/web/app/static/js/modules/corpus_analysis/client/Client.js @@ -69,11 +69,14 @@ class Client { * The detail object can hold any type of data the View needs to know about * to represent those to the user. */ - notifyView(caseIdentifier, detailObject={}) { + notifyView(caseIdentifier, detailObject={}, notificationType='info', + raiseModalFeedback=true) { detailObject.caseIdentifier = caseIdentifier; detailObject.client = this; + detailObject.notificationType = notificationType; + detailObject.raiseModalFeedback = raiseModalFeedback; const event = new CustomEvent('notify-view', { detail: detailObject }); - console.info('Client dispatching Notification with detail object in details:', + console[notificationType]('Client dispatching Notification with detail object in details:', detailObject); document.dispatchEvent(event); } diff --git a/web/app/static/js/modules/corpus_analysis/client/listeners.js b/web/app/static/js/modules/corpus_analysis/client/listeners.js index 32aefce0..ceae01ba 100644 --- a/web/app/static/js/modules/corpus_analysis/client/listeners.js +++ b/web/app/static/js/modules/corpus_analysis/client/listeners.js @@ -31,9 +31,9 @@ function recieveConnected(type, client) { client.getMetaData(); } else { let errorText = `Error ${response.code} - ${response.msg}`; - console.group('Connection failed!') + console.group('Connection failed!'); console.error(`corpus_analysis_init: ${errorText}`); - client.notifyView('connecting-failed', { msg: errorText }); + client.notifyView('client-failed', { msg: errorText }, 'error'); console.groupEnd(); } }); @@ -58,11 +58,12 @@ function recieveMetaData(type, client) { client.eventListeners[type].executeCallbacks([response.payload]); console.groupEnd(); } else { + let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; console.group('Failed to recieve meta data.'); console.error('corpus_analysis_meta_data: Client failed to recieve', 'meta data via socket.on'); - let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; console.error(`corpus_analysis_meta_data: ${errorText}`); + client.notifyView('client-failed', { msg: errorText }, 'error'); console.groupEnd(); } }); @@ -89,13 +90,17 @@ function recieveQueryStatus(type, client) { client.eventListeners[type].executeCallbacks([response.payload]); console.groupEnd(); } else { + let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; console.group('corpus_analysis_query: Client failed recieving', 'query process status via socket.on'); - let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; if (response.payload.code == 1281) { errorText += ' - Invalid Query'; + console.error(`corpus_analysis_query: ${errorText}`); + client.notifyView('client-failed', { msg: errorText }, 'error', false); + } else { + console.error(`corpus_analysis_query: ${errorText}`); + client.notifyView('client-failed', { msg: errorText }, 'error'); } - console.error(`corpus_analysis_query: ${errorText}`); console.groupEnd(); } }); @@ -121,10 +126,11 @@ function recieveQueryData(type, client) { console.info('Added chunk data to results.data.'); console.groupEnd(); } else { + let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; console.group('corpus_analysis_query_results: Client failed recieving', 'the results via socket.on'); - let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; console.error(`corpus_analysis_query: ${errorText}`); + client.notifyView('client-failed', { msg: errorText }, 'error'); console.groupEnd(); } }); @@ -150,11 +156,12 @@ function recieveResultsData(type, client) { response.type]); console.groupEnd(); } else { + let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; console.group('Failed to recieve results data.'); console.error('corpus_analysis_inspect_match: Client failed to recieve', 'results data via socket.on'); - let errorText = `Error ${response.payload.code} - ${response.payload.msg}`; console.error(`corpus_analysis_inspect_match: ${errorText}`); + client.notifyView('client-failed', { msg: errorText }, 'error'); console.groupEnd(); } }); @@ -178,7 +185,7 @@ function recieveViewNotification(type, client) { default: console.error('Recieved unkown notification case identifier from View'); // do something to not crash the analysis session? - // maybe unnecessary + // maybe unnecessary? } }); } diff --git a/web/app/static/js/modules/corpus_analysis/view/ResultsView.js b/web/app/static/js/modules/corpus_analysis/view/ResultsView.js index ffedce8b..3981716e 100644 --- a/web/app/static/js/modules/corpus_analysis/view/ResultsView.js +++ b/web/app/static/js/modules/corpus_analysis/view/ResultsView.js @@ -54,6 +54,7 @@ class ResultsList extends List { 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 = {}; + this.knownHTMLElements = new Set(); } /** @@ -84,23 +85,44 @@ class ResultsList extends List { */ getHTMLElements(arrayOfSelectors) { for (let selector of arrayOfSelectors) { - let element; - let elements; - if (selector.startsWith('#')) { - element = document.querySelector(selector); - } else { - elements = document.querySelectorAll(selector); - elements = [...elements]; + // Check if identified Element should be initialized as a modal. + let modalInit = false; + let options; + if (Array.isArray(selector)) { + selector = selector[0]; + modalInit = true; + options = selector[1]; } - let cleanKey = []; - 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 ? element: elements; + // Check if the current selector has already been used. + if (this.knownHTMLElements.has(selector)) { + continue; + } else { + // Get element or elements. + let element; + let elements; + if (selector.startsWith('#')) { + element = document.querySelector(selector); + } else { + elements = document.querySelectorAll(selector); + elements = [...elements]; + } + // Create valid javascript instance field name. + let cleanKey = []; + 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 ? element: elements; + // Initialize current element as modal if true. + if (modalInit) { + this[cleanKey] = M.Modal.init(this[cleanKey], options); + } + } + // Add current selector to knwonHTMLElements. + this.knownHTMLElements.add(selector); } } @@ -294,59 +316,16 @@ class ResultsList extends List { } // ### functions to inspect imported Matches - // This function creates an object that is similar to the object that is - // being recieved as an answere to the getMatchWithContext Method, which is - // triggering an socket.io event. - // It is used as an input for show match context in the context of imported - // results to be able to inspect matches. - createFakeResponse() { - contextModal.open(); - // match nr for user to display derived from data_index - let contextMatchNrElement = document.getElementById("context-match-nr"); - contextMatchNrElement.textContent = this.contextId + 1; - let cpos_lookup; - let fake_response = {}; - let contextResultsElement; - // function to create one match object from entire imported results - // that is passed into the results.jsList.showMatchContext() function - fake_response["payload"] = {}; - let dataIndex = event.target.closest("tr").dataset.index; - this.contextId = dataIndex; - fake_response.payload["matches"] = [results.data.matches[dataIndex]]; - contextResultsElement = document.getElementById("context-results"); - contextResultsElement.innerHTML = ""; - let {lc, c, rc} = this.helperCreateCpos(results.data.cpos_ranges, - fake_response.payload.matches[0]); - cpos_lookup = {}; - for (let cpos of lc) { - cpos_lookup[cpos] = results.data.cpos_lookup[cpos]; - } - for (let cpos of c) { - cpos_lookup[cpos] = results.data.cpos_lookup[cpos]; - } - for (let cpos of rc) { - cpos_lookup[cpos] = results.data.cpos_lookup[cpos]; - } - fake_response.payload["cpos_lookup"] = cpos_lookup - fake_response.payload["cpos_ranges"] = results.data.cpos_ranges; - fake_response.payload["query"] = results.data.query; - fake_response.payload["context_id"] = dataIndex + 1; - fake_response.payload["match_count"] = fake_response.payload.matches.length - fake_response.payload["corpus_type"] = "inspect-result" - return fake_response - } - // gets result cpos infos for dataIndexes (use list of length 1 for one match) to send back to // the server inspect(client, results, dataIndex, type) { // initialize context modal this.getHTMLElements([ - '#context-modal', + ['#context-modal', true], '#context-results', '#create-inspect-menu', '#create-from-inspect', ]); - this.contextModal = M.Modal.init(this.contextModal); // get result infos from server and show them in context modal this.contextId = dataIndex[0]; this.contextResults.innerHTML = ""; // clear it from old inspects @@ -552,9 +531,6 @@ class ResultsList extends List { toHideArray = []; toShowArray = array; } - // console.log(array); - // console.log("#######"); - // console.log(toHideArray); for (let s of toHideArray) { s.classList.add("hide"); } @@ -786,7 +762,7 @@ class ResultsList extends List { - + diff --git a/web/app/static/js/modules/corpus_analysis/view/callbacks.js b/web/app/static/js/modules/corpus_analysis/view/callbacks.js index 2df7a5ae..b7f1fc87 100644 --- a/web/app/static/js/modules/corpus_analysis/view/callbacks.js +++ b/web/app/static/js/modules/corpus_analysis/view/callbacks.js @@ -33,14 +33,20 @@ function connectedCallback(resultsList, detail) { resultsList.analysisInitModal.close(); } -function connectingFaildeCallback(resultsList, detail) { +function clientFailedCallback(resultsList, detail) { resultsList.getHTMLElements([ '#analysis-init-progress', - '#analysis-init-error' + '#analysis-init-error', + '#user-feedback', ]); - resultsList.analysisInitProgress.classList.toggle('hide'); - resultsList.analysisInitError.classList.toggle('hide'); - resultsList.analysisInitError.textContent = detail.msg; + if (detail.raiseModalFeedback) { + resultsList.analysisInitModal.open(); + resultsList.analysisInitProgress.classList.toggle('hide'); + resultsList.analysisInitError.classList.toggle('hide'); + resultsList.analysisInitError.textContent = detail.msg; + } else { + nopaque.flash(detail.msg, 'error') + } } function queryDataPreparingCallback(resultsList, detail) { @@ -114,10 +120,12 @@ function queryDataRecievingCallback(resultsList, detail) { } else if (!client.dynamicMode) { resultsList.add(resultItems, (items) => { for (let item of items) { + console.log(item); item.elm = resultsList.createResultRowElement(item, results.data, client, true); + console.log(item); } }); // update user feedback about query status @@ -183,7 +191,7 @@ function resultsDataRecievedCallback(resultsList, detail) { export { connectingCallback, connectedCallback, - connectingFaildeCallback, + clientFailedCallback, queryDataPreparingCallback, queryDataRecievingCallback, queryDataRecievedCallback, diff --git a/web/app/static/js/modules/corpus_analysis/view/listeners.js b/web/app/static/js/modules/corpus_analysis/view/listeners.js index ee3612fd..00ff8bc7 100644 --- a/web/app/static/js/modules/corpus_analysis/view/listeners.js +++ b/web/app/static/js/modules/corpus_analysis/view/listeners.js @@ -10,7 +10,7 @@ import { connectingCallback, connectedCallback, - connectingFaildeCallback, + clientFailedCallback, queryDataPreparingCallback, queryDataRecievingCallback, queryDataRecievedCallback, @@ -24,6 +24,11 @@ function recieveClientNotification(eventType, resultsList) { document.addEventListener(eventType, (event) => { let caseIdentifier = event.detail.caseIdentifier; switch (caseIdentifier) { + case 'client-failed': + console.error('View recieved notification:', caseIdentifier); + // execute callbacks + clientFailedCallback(resultsList, event.detail); + break; case 'connecting': console.info('View recieved notification:', caseIdentifier); connectingCallback(resultsList, event.detail); @@ -33,11 +38,6 @@ function recieveClientNotification(eventType, resultsList) { console.info('View recieved notification:', caseIdentifier); connectedCallback(resultsList, event.detail); break; - case 'connecting-failed': - console.info('View recieved notification:', caseIdentifier); - // execute callbacks - connectingFaildeCallback(resultsList, event.detail); - break; case 'query-data-prepareing': console.info('View recieved notification:', caseIdentifier); // execute callbacks diff --git a/web/app/templates/corpora/analyse_corpus.html.j2 b/web/app/templates/corpora/analyse_corpus.html.j2 index 61132d65..f0a5e312 100644 --- a/web/app/templates/corpora/analyse_corpus.html.j2 +++ b/web/app/templates/corpora/analyse_corpus.html.j2 @@ -12,27 +12,27 @@ padding-bottom: 0px;">
-
-
-
- search - {{ query_form.query() }} - {{ query_form.query.label }} - - - help - - CQP query language tutorial - - + +
+
+ search + {{ query_form.query() }} + {{ query_form.query.label }} + + + help + + CQP query language tutorial + + +
+
+ {{ M.render_field(query_form.submit, material_icon='send', + style='width:100%;') }} +
-
- {{ M.render_field(query_form.submit, material_icon='send', - style='width:100%;') }} -
-
- -
+ +
@@ -233,8 +233,14 @@ document.addEventListener("DOMContentLoaded", () => { '#full-results-export', '#inspect-results-export', '#meta-data-modal-content', - '#meta-data-modal', - '#query-results-download-modal', + ['#meta-data-modal', { + 'preventScrolling': false, + 'opacity': 0.0, + 'dismissible': false, + 'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()}) + } + ], + ['#query-results-download-modal', {}], '#query-results-table', '#show-meta-data', '#sub-results-create', @@ -299,14 +305,8 @@ document.addEventListener("DOMContentLoaded", () => { /** * The following event listener handles the show metadata button and its - * functionality. Before the needed modal is initialized. + * functionality. */ - resultsList.metaDataModal= M.Modal.init(resultsList.metaDataModal, { - 'preventScrolling': false, - 'opacity': 0.0, - 'dismissible': false, - 'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()}) - }); resultsList.showMetaData.onclick = () => { resultsList.metaDataModalContent.textContent = ''; let table = resultsList.createMetaDataForModal(results.metaData); @@ -353,8 +353,6 @@ document.addEventListener("DOMContentLoaded", () => { resultsList.notifyClient('get-results', { resultsType: 'sub-results', dataIndexes: dataIndexes}); } - // Before the download events are added the needed modal is initialized. - resultsList.queryResultsDownloadModal = M.Modal.init(resultsList.queryResultsDownloadModal); // 3. Open download modal when full results export button is pressed resultsList.fullResultsExport.onclick = (event) => { resultsList.queryResultsDownloadModal.open(); diff --git a/web/app/templates/query_results/inspect.html.j2 b/web/app/templates/query_results/inspect.html.j2 index 998dbba6..abe65194 100644 --- a/web/app/templates/query_results/inspect.html.j2 +++ b/web/app/templates/query_results/inspect.html.j2 @@ -163,7 +163,13 @@ document.addEventListener("DOMContentLoaded", () => { '#full-results-create', '#inspect-results-export', '#meta-data-modal-content', - '#meta-data-modal', + ['#meta-data-modal', { + 'preventScrolling': false, + 'opacity': 0.0, + 'dismissible': false, + 'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()}) + } + ], '#query-results-table', '#show-meta-data', '#sub-results-create', @@ -171,10 +177,10 @@ document.addEventListener("DOMContentLoaded", () => { // Hide buttons which are not needed when just inspecting results resultsList.inspectResultsExport.classList.add('hide'); // Execute client event listener callbacks manually because dynamicMode is false - client.eventListeners['corpus_analysis_query'].executeCallbacks([resultsJson]) + client.eventListeners['corpus_analysis_query'].executeCallbacks([resultsJson]); // Save meta data to results after the init callback from line above results.metaData = metaDataJson; - client.eventListeners['corpus_analysis_query_results'].executeCallbacks([resultsJson]) + client.eventListeners['corpus_analysis_query_results'].executeCallbacks([resultsJson]); /** * The following listener handles what functions are called when the user * does use the page navigation to navigate to a new page. @@ -233,14 +239,8 @@ document.addEventListener("DOMContentLoaded", () => { /** * The following event listener handles the show metadata button and its - * functionality. Before the needed modal is initialized. + * functionality. */ - resultsList.metaDataModal= M.Modal.init(resultsList.metaDataModal, { - 'preventScrolling': false, - 'opacity': 0.0, - 'dismissible': false, - 'onOpenEnd': (() => {document.querySelector(".modal-overlay").remove()}) - }); resultsList.showMetaData.onclick = () => { resultsList.metaDataModalContent.textContent = ''; let table = resultsList.createMetaDataForModal(results.metaData);
Meta data DescriptionMeta Data Description Value