// ### corpus analysis client status functions function sendAbortSignal() { console.log(`Sending status "abort signal" from client side.`); message = {'status': "abort"}; nopaque.socket.emit("send_analysis_status_cli", message); setAnalysisStatus("abort"); } function setAnalysisStatus(statusStr) { analysisClientStatus[sessionId] = statusStr; console.log(`Set new status "${statusStr}" for "${sessionId}" on client side.`); console.log("Object with status is:", analysisClientStatus); } function checkAnalysisStatus(sessionId) { let status = analysisClientStatus[sessionId]; console.log(`Check status on client side for ${sessionId}.`, analysisClientStatus); return status; } // ### Send query functions ### //function to get current queryData from a given queryFormElement function getQueryData(queryFormElement) { let formData let queryData formData = new FormData(queryFormElement); queryData = {"context": formData.get("context"), // global declaration "hits_per_page": formData.get("hits_per_page"), "query": formData.get("query")}; return queryData } // Function to send a query to the CQP server using queryData gatherd with getQueryData async function sendQuery(event) { const delay = ms => new Promise(res => setTimeout(res, ms)); result; // global declaration, holds query results as JSON resultList; // global declaration, list.js object displaying the results let queryData; // holds data of query form let resultListOptions; // holding the options for the ResultList object let analysisStatus; // checks if one query has been finished before // if true, result download will be disabled again until query is finished // also shows progress bar again if (queryFinished) { exportQueryResultsElement.classList.add("disabled"); queryResultsDeterminateElement.parentNode.parentNode.classList.remove("hide"); } console.log("Sending query."); console.log("Session status are: ", analysisClientStatus); event.preventDefault(); analysisStatus = checkAnalysisStatus(sessionId); queryData = getQueryData(queryFormElement); if (analysisStatus === "idle") { nopaque.toast("Query has been sent!"); nopaque.socket.emit("corpus_analysis_query", queryData.query); helperSendQuery(queryData); analysisStatus = checkAnalysisStatus(sessionId); } else if (analysisStatus === "running" ) { sendAbortSignal(); analysisStatus = checkAnalysisStatus(sessionId); while (analysisStatus === "abort") { queryResultsTableElement.classList.add("hide"); queryLoadingElement.classList.remove("hide"); analysisStatus = checkAnalysisStatus(sessionId); await delay(100); } sendQuery(event) } } function helperSendQuery(queryData) { // full results object declaration, global declaration! // will always be reset if a query is sent, so that only the chunks of the // current query will be saved in it result = {}; // full JSON object holding match results result["matches"] = []; // list of all amtches with lc and rc result["cpos_lookup"] = {}; // object contains all cpos as key value pair result["text_lookup"] = {}; // same as above for all text ids result["loaded_match_count"] = 0; // how many matches have been recieved result["num_matches_total"]; // how many should have been recieved/total nr result["query"] = ""; // the query as a string // some hiding/showing for loading animation queryLoadingElement.classList.remove("hide"); queryResultsTableElement.classList.add("hide"); resultListOptions = {page: queryData["hits_per_page"], pagination: [{ name: "paginationTop", paginationClass: "paginationTop", innerWindow: 8, outerWindow: 1 }, { paginationClass: "paginationBottom", innerWindow: 8, outerWindow: 1 }], valueNames: ["titles", "lc", "hit", "rc", {data: ["index"]}], item: ``}; resultList = new ResultList('result-list', resultListOptions); resultList.clear(); // empty list for new query } // ### Recieve results from sent query and display them in a list etc. ### // Function used when CQP server sends back the query results using socketio function recieveResults(response) { let toolTipInfoElement; let chunk; let countCorpusFiles; let queryData; let queryResultsElement; let resultItems; let queryResultsMetadataElement; let queryResultsInteractionElement; let queryResultsHeadElement; let queryStatus; queryFinished = false; console.log(response); // ERROR code checking if (response["code"] === 0) { console.log("[SUCCESS] corpus_analysis_init"); console.log("Code:" + response["code"]); // further code execution of this code block starting in line 342 } else if (response["code"] === 1) { queryResultsTableElement.classList.add("hide"); queryLoadingElement.classList.add("hide"); nopaque.toast("Invalid query entered!", "red"); console.log("[ERROR] corpus_analysis_init"); console.log("Code:" + response["code"]); return; // no further code execution of this code block } else { console.log("[ERROR] corpus_analysis_init"); console.log("Code:" + response["code"]); return; // no further code execution of this code block } // logs the current recieved chunk chunk = response["chunk"]; //chunk = response["chunk"]; console.log("### corpus_analysis chunk ###"); console.log(chunk); // logs and extends/push/update the current recieved chunk to the // result Object console.log("### corpus analysis updated result json ###"); result["matches"].push(...chunk["matches"]); Object.assign(result["cpos_lookup"], chunk["cpos_lookup"]); Object.assign(result["text_lookup"], chunk["text_lookup"]); result["num_matches_total"] = response["num_matches_total"]; //result["match_count"] = response["match_count"]; console.log("Before Current match count", result["loaded_match_count"]); queryData = getQueryData(queryFormElement); result["query"] = queryData["query"]; console.log(result); // Some hiding and showing of loading animations analysisStatus = checkAnalysisStatus(); if (analysisStatus === "abort") { queryResultsTableElement.classList.add("hide"); queryLoadingElement.classList.remove("hide"); } else { queryResultsTableElement.classList.remove("hide"); queryLoadingElement.classList.add("hide"); queryResultsElement = document.getElementById("query-results"); queryResultsElement.innerHTML = ""; } // check if query has any results if (chunk["matches"].length === 0) { queryResultsTableElement.classList.add("hide"); nopaque.toast("No results for this query!"); return; } // List building/appending the chunks when query had results countCorpusFiles = Object.keys(result["text_lookup"]).length; resultItems = []; // list for holding every row item // get infos for full match row for (let [index, match] of chunk["matches"].entries()) { resultItems.push({...match, ...{"index": index + result["loaded_match_count"]}}); } resultList.add(resultItems, items => { for (let item of items) { item.elm = resultList.createResultRowElement(item, chunk); } resultList.update(); changeContext(); // sets lr context on first result load }); result["loaded_match_count"] += Object.keys(chunk["matches"]).length; console.log("After current match count", result["loaded_match_count"]); queryResultsMetadataElement = document.getElementById("query-results-metadata"); queryResultsMetadataElement.innerHTML = `
The query resulted in a total of ${result["num_matches_total"]} matches.
${result["loaded_match_count"]} of ${result["num_matches_total"]} matches in ${countCorpusFiles} corpus files have been loaded.
helpThe Server is still sending your results. Functions like "Export Results" and "Match Inspect" will be available after all matches have been loaded.
`; queryResultsInteractionElement = document.getElementById("interaction-elements"); queryResultsInteractionElement.appendChild(exportQueryResultsElement); queryResultsHeadElement = document.getElementById("query-results-head"); queryResultsHeadElement.classList.remove("hide"); queryStatus = response["progress"]; console.log("QUERY STATUS:", queryStatus); queryResultsDeterminateElement.style["width"] = `${queryStatus}%`; console.log(queryResultsDeterminateElement.style["width"]); // enable download and inspect when query is finished // also sets queryFinished to true if (queryStatus === 100) { queryFinished = true; // global declaration to set downlaod button and inspects buttons back to disabled for new queries queryResultsDeterminateElement.parentNode.parentNode.classList.add("hide"); exportQueryResultsElement.classList.remove("disabled"); queryResultsMetadataElement.innerHTML = `The query resulted in a total of ${result["num_matches_total"]} matches.
${result["loaded_match_count"]} of ${result["num_matches_total"]} matches in ${countCorpusFiles} corpus files have been loaded.check_circle
`; activateInspect(); } } // ### Functions to inspect one match, to show more details ### // activate inspect buttons if queryFinished is true function activateInspect() { let inspectBtnElements; if (queryFinished) { inspectBtnElements = document.getElementsByClassName("inspect"); for (let inspectBtn of inspectBtnElements) { inspectBtn.classList.remove("disabled"); } } } //gets result cpos infos for one dataIndex to send back to the server function inspect(dataIndex) { console.log("Inspect!"); console.log(result["matches"][dataIndex]["hit"]); contextModal.open(); nopaque.socket.emit("inspect_match", {"cpos": result["matches"][dataIndex]["hit"]}); } function showMatchContext(message) { let contextResultsElement; let sentenceElement let token; let tokenElement; console.log("### match_context ###"); console.log("Incoming data:", message); contextResultsElement = document.getElementById("context-results"); contextResultsElement.innerHTML = ""; document.getElementById("context-modal-loading").classList.add("hide"); document.getElementById("context-modal-ready").classList.remove("hide"); for (let [key, value] of Object.entries(message['context_s_cpos'])) { sentenceElement = document.createElement("p"); for (let cpos of value) { token = message["cpos_lookup"][cpos]; tokenElement = document.createElement("span"); tokenElement.classList.add("token"); if (message["match_cpos_list"].includes(cpos)) { tokenElement.classList.add("bold"); tokenElement.classList.add("light-green"); } tokenElement.dataset.cpos = cpos; tokenElement.innerText = token["word"]; var expertModeSwitchElement = document.getElementById("expert-mode-switch"); if (expertModeSwitchElement.checked) { expertModeOn([tokenElement], message); } sentenceElement.append(tokenElement); sentenceElement.append(document.createTextNode(" ")); } contextResultsElement.append(sentenceElement); } } // ### Display options changing live how the matches are being displayed ### // Event function that changes the shown hits per page. // Just alters the resultList.page property function changeHitsPerPage(event) { try { resultList.page = event.target.value; resultList.update(); nopaque.toast("Updated matches per page.") } catch (e) { console.log("resultList has no results right now. Live update of items per page is useless for now."); } } // Event function triggered on context select change and also if pagination is clicked function changeContext(event) { let newContextValue; let lc; let rc; let array; try { if (event.type === "change") { nopaque.toast("Updated context per match!"); } } catch (e) { console.log(e); console.log("This error is expected."); } finally { newContextValue = document.getElementById("context").value; console.log("Context value is:", newContextValue); lc = document.getElementsByClassName("left-context"); rc = document.getElementsByClassName("right-context"); for (let element of lc) { array = Array.from(element.childNodes); for (let element of array.slice(newContextValue)) { element.classList.add("hide"); } for (let element of array.slice(0, newContextValue)) { element.classList.remove("hide"); } } for (let element of rc) { array = Array.from(element.childNodes); for (let element of array.slice(newContextValue)) { element.classList.add("hide"); } for (let element of array.slice(0, newContextValue)) { element.classList.remove("hide"); } } } } // ### Expert view event functions ### // Event function to check if pagination is used and then look if // expertModeSwitchElement is checked // if checked than expertModeOn is executed // if unchecked expertModeOff is executed function eventHandlerCheck(event) { console.log("pagination used!"); console.log(expertModeSwitchElement.checked); if (expertModeSwitchElement.checked) { expertModeOn(event.currentTarget.tokenElements, result); } else if (!expertModeSwitchElement.checked) { event.preventDefault(); console.log("prevented! Destroy"); expertModeOff(event.currentTarget.tokenElements); } } // function to apply extra information and animation to every token function expertModeOn(tokenElements, result_lookup) { let token; console.log("expertModeOn!"); for (let tokenElement of tokenElements) { tokenElement.classList.add("chip"); tokenElement.classList.add("hoverable"); tokenElement.classList.add("expert-view"); token = result_lookup["cpos_lookup"][tokenElement.dataset.cpos]; tokenElement.addEventListener("mouseover", function(event) { console.log("Mouseover!"); console.log(event.target); token = result_lookup["cpos_lookup"][event.target.dataset.cpos]; addToolTipToTokenElement(event.target, token); }); } } // fuction that creates Tooltip for one token and extracts the corresponding // infos from the result JSON function addToolTipToTokenElement(tokenElement, token) { M.Tooltip.init(tokenElement, {"html": `
Token information | Source information |
---|---|
Word: ${token["word"]} Lemma: ${token["lemma"]} POS: ${token["pos"]} Simple POS: ${token["simple_pos"]} NER: ${token["ner"]} |
Title: ${result["text_lookup"][token["text"]]["title"]} Author: ${result["text_lookup"][token["text"]]["author"]} Publishing year: ${result["text_lookup"][token["text"]]["publishing_year"]} |