diff --git a/web/app/static/js/modules/nopaque.CorpusAnalysisClient.js b/web/app/static/js/modules/corpus_analysis/client/Client.js
similarity index 88%
rename from web/app/static/js/modules/nopaque.CorpusAnalysisClient.js
rename to web/app/static/js/modules/corpus_analysis/client/Client.js
index b64c24d8..990c6851 100644
--- a/web/app/static/js/modules/nopaque.CorpusAnalysisClient.js
+++ b/web/app/static/js/modules/corpus_analysis/client/Client.js
@@ -1,12 +1,12 @@
/**
- * This class is used to create a CorpusAnalysisClient object.
+ * This class is used to create a Client 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, 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 Client {
constructor({corpusId = null,
socket = null,
logging = true,
@@ -39,7 +39,7 @@ class CorpusAnalysisClient {
}
}
- // Registers one or more SocketEventListeners to the CorpusAnalysisClient.
+ // Registers one or more SocketEventListeners to the Client.
setSocketEventListeners(socketEventListeners) {
for (let socketEventListener of socketEventListeners) {
this.socketEventListeners[socketEventListener.type] = socketEventListener;
@@ -56,7 +56,15 @@ class CorpusAnalysisClient {
}
}
- // Registers a CorpusAnalysisDisplay object to the CorpusAnalysisClient.
+
+ // TODO: get rid of this disply stuff and send commands to the viewer
+ // on what to do/show/hide etc
+
+ notifyView(SendWhatToDo) {
+
+ }
+
+ // Registers a CorpusAnalysisDisplay object to the Client.
setDisplay(type, corpusAnalysisDisplay) {
this.displays[type] = corpusAnalysisDisplay;
}
@@ -87,27 +95,26 @@ class CorpusAnalysisClient {
}
/**
- * Requests a corpus analysis session via socket.io.
- * Opens a loading modal at the start of the request.
- * Will be closed if session has been successfully recieved.
+ * Connects to the corpus analysis session for the specified corpus via
+ * socket.io.
*/
- requestSession() {
- console.info('corpus_analysis_init: Client requesting session via',
+ connect() {
+ console.info('corpus_analysis_init: Client connecting to session via',
'socket.emit');
- if (this.displays.init != undefined) {
- this.displays.init.element.M_Modal.open();
- this.displays.init.setVisibilityByStatus('waiting');
- }
+ // if (this.displays.init != undefined) {
+ // this.displays.init.element.M_Modal.open();
+ // this.displays.init.setVisibilityByStatus('waiting');
+ // }
this.socket.emit('corpus_analysis_init', this.corpusId);
}
/**
- * Request query data for the query string that has been sent to the server.
+ * Emits query to the server via socket.io. Server will send the results
+ * back.
*/
- requestQueryData(queryStr) {
- console.info('corpus_analysis_query: Client requesting query data via',
+ query(queryStr) {
+ console.info('corpus_analysis_query: Client sending query via',
'socket.emit for the query', queryStr);
- // TODO: Display stuff ?
this.socket.emit('corpus_analysis_query', queryStr);
}
}
@@ -236,8 +243,8 @@ class ListenerCallback {
// export Classes from this module
export {
- CorpusAnalysisClient,
- CorpusAnalysisDisplay,
+ Client,
SocketEventListener,
+ CorpusAnalysisDisplay,
ListenerCallback,
};
\ No newline at end of file
diff --git a/web/app/static/js/modules/nopaque.listenerCallbacks.js b/web/app/static/js/modules/corpus_analysis/client/callbacks.js
similarity index 100%
rename from web/app/static/js/modules/nopaque.listenerCallbacks.js
rename to web/app/static/js/modules/corpus_analysis/client/callbacks.js
diff --git a/web/app/static/js/modules/nopaque.listenerFunctions.js b/web/app/static/js/modules/corpus_analysis/client/listeners.js
similarity index 100%
rename from web/app/static/js/modules/nopaque.listenerFunctions.js
rename to web/app/static/js/modules/corpus_analysis/client/listeners.js
diff --git a/web/app/static/js/modules/corpus_analysis/main.js b/web/app/static/js/modules/corpus_analysis/main.js
new file mode 100644
index 00000000..e69de29b
diff --git a/web/app/static/js/nopaque.Results.js b/web/app/static/js/modules/corpus_analysis/model/Results.js
similarity index 95%
rename from web/app/static/js/nopaque.Results.js
rename to web/app/static/js/modules/corpus_analysis/model/Results.js
index 2f7778f1..37435531 100644
--- a/web/app/static/js/nopaque.Results.js
+++ b/web/app/static/js/modules/corpus_analysis/model/Results.js
@@ -1,3 +1,9 @@
+/**
+ * These classes are implementing the data store of the corpus_analysis
+ * package. If we follow the idea of the Model View Controller Pattern these
+ * classes combined in the Results class define the Model.
+ */
+
class Results {
constructor(data, jsList , metaData) {
this.data = data;
diff --git a/web/app/static/js/modules/nopaque.InteractionElement.js b/web/app/static/js/modules/corpus_analysis/view/InteractionElement.js
similarity index 100%
rename from web/app/static/js/modules/nopaque.InteractionElement.js
rename to web/app/static/js/modules/corpus_analysis/view/InteractionElement.js
diff --git a/web/app/static/js/modules/corpus_analysis/view/ResultsView.js b/web/app/static/js/modules/corpus_analysis/view/ResultsView.js
new file mode 100644
index 00000000..fa0e8b36
--- /dev/null
+++ b/web/app/static/js/modules/corpus_analysis/view/ResultsView.js
@@ -0,0 +1,790 @@
+/**
+ * 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
+ * the options below are used.
+ */
+ static options = {
+ page: 10,
+ pagination: [{
+ name: "paginationTop",
+ paginationClass: "paginationTop",
+ innerWindow: 8,
+ outerWindow: 1
+ }, {
+ paginationClass: "paginationBottom",
+ innerWindow: 8,
+ outerWindow: 1
+ }],
+ valueNames: ["titles", "lc", "c", "rc", {data: ["index"]}],
+ item: ``
+ };
+ constructor(idOrElement, options) {
+ super(idOrElement, options);
+ this.options = options;
+ /**
+ * All span tokens which are holding events if expert
+ * mode is on. Collected here to delete later on.
+ */
+ this.eventTokens = {};
+ /**
+ * 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.
+ }
+
+ helperCreateCpos(cpos_ranges, cpos_values) {
+ let lc;
+ let c;
+ let rc;
+ if (cpos_ranges) {
+ // python range like function from MDN
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Sequence_generator_(range)
+ const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
+ lc = range(cpos_values.lc[0], cpos_values.lc[1], 1)
+ c = range(cpos_values.c[0], cpos_values.c[1], 1)
+ rc = range(cpos_values.rc[0], cpos_values.rc[1], 1)
+ } else {
+ lc = cpos_values.lc;
+ c = cpos_values.c;
+ rc = cpos_values.rc;
+ }
+ return {lc: lc, c: c, rc: rc};
+ }
+
+ // handels interactionElements during a pagination navigation
+ // loops over interactionElements and executes callback functions accordingly
+ pageChangeEventInteractionHandler(interactionElements) {
+ // get elements to check thier status
+ for (let interaction of interactionElements.interactions) {
+ if (interaction.checkStatus) {
+ if (interaction.element.checked) {
+ let f_on = interaction.bindThisToCallback("on");
+ let args_on = interaction.callbacks.on.args;
+ f_on(...args_on);
+ } else {
+ let f_off = interaction.bindThisToCallback("off");
+ let args_off = interaction.callbacks.off.args;
+ f_off(...args_off);
+ }
+ } else {
+ let f = interaction.bindThisToCallback("noCheck");
+ let args = interaction.callbacks.noCheck.args;
+ f(...args);
+ }
+ }
+ }
+
+ // get display options from display options form element
+ static getDisplayOptions(htmlId) {
+ // gets display options parameters
+ let displayOptionsFormElement = document.getElementById(htmlId);
+ let displayOptionsFormData = new FormData(displayOptionsFormElement);
+ let displayOptionsData =
+ {
+ "resultsPerPage": displayOptionsFormData.get("display-options-form-results_per_page"),
+ "resultsContex": displayOptionsFormData.get("display-options-form-result_context"),
+ "expertMode": displayOptionsFormData.get("display-options-form-expert_mode")
+ };
+ return displayOptionsData
+ }
+
+ // ###### Functions to add one match to a sub-results ######
+ // activate the add buttons
+ activateAddToSubResults() {
+ subResultsIdListElement.classList.remove("hide");
+ if (subResultsExportElement.classList.contains("hide")) {
+ subResultsCreateElement.classList.remove("hide");
+ }
+ let addToSubResultsBtnElements = document.getElementsByClassName("add");
+ for (let addToSubResultsBtn of addToSubResultsBtnElements) {
+ addToSubResultsBtn.classList.remove("hide");
+ }
+ }
+ // deactivate the add buttons
+ deactivateAddToSubResults() {
+ subResultsIdListElement.classList.add("hide");
+ subResultsCreateElement.classList.add("hide");
+ let addToSubResultsBtnElements = document.getElementsByClassName("add");
+ for (let addToSubResultsBtn of addToSubResultsBtnElements) {
+ addToSubResultsBtn.classList.add("hide");
+ }
+ }
+
+ // Used in addToSubResults and inspect to toggle the design of the check
+ // buttons according to its checked unchecked status.
+ helperActivateBtn(btn) {
+ btn.classList.remove("grey");
+ btn.classList.add("green");
+ btn.textContent = "check";
+ }
+
+ // Used in addToSubResults and inspect to toggle the design of the check
+ // buttons according to its checked unchecked status.
+ helperDeactivateBtn(btn) {
+ btn.classList.remove("green");
+ btn.classList.add("grey");
+ btn.textContent = "add";
+ }
+
+ // Either adds or removes a match to the sub-results. For this it checks
+ // onclick if the current button has been checked or not. For this the
+ // function checks if its status in addToSubResultsStatus is either flase or
+ // true. Adds match to sub-results if status is false if status is true it
+ // removes it.
+ addToSubResults(dataIndex, tableCall=true) {
+ let textarea = subResultsIdListElement.getElementsByTagName("textarea")[0];
+ if (!this.addToSubResultsStatus[dataIndex]
+ || this.addToSubResultsStatus === undefined) {
+ // add button is activated because status is either false or undefined
+ this.helperActivateBtn(event.target);
+ this.addToSubResultsStatus[dataIndex] = true; // sets status to true
+ this.addToSubResultsIdsToShow.add(dataIndex + 1); // + 1 because user does not see zero indexd data indexes
+ textarea.textContent = [...this.addToSubResultsIdsToShow].sort(function(a, b){return a-b}).join(", "); // automaticalle sorts ids into the textarea in ascending order
+ M.textareaAutoResize(textarea); // after an insert textarea has to be resized manually
+ nrMarkedMatches.textContent = [...this.addToSubResultsIdsToShow].length;
+ } else if (this.addToSubResultsStatus[dataIndex]) {
+ // add button is deactivated because status is true
+ this.helperDeactivateBtn(event.target);
+ this.addToSubResultsStatus[dataIndex] = false; // sets status to false
+ this.addToSubResultsIdsToShow.delete(dataIndex + 1); // + 1 because user does not see zero indexd data indexes
+ textarea.textContent = [...this.addToSubResultsIdsToShow].sort(function(a, b){return a-b}).join(", "); // automaticalle sorts ids into the textarea in ascending order
+ nrMarkedMatches.textContent = [...this.addToSubResultsIdsToShow].length;
+ M.textareaAutoResize(textarea); // after an insert textarea has to be resized manually
+ }
+ // Toggles the create button according to the number of ids in addToSubResultsIdsToShow
+ if ([...this.addToSubResultsIdsToShow].length > 0) {
+ subResultsCreateElement.classList.remove("disabled");
+ } else if ([...this.addToSubResultsIdsToShow].length === 0) {
+ subResultsCreateElement.classList.add("disabled");
+ }
+ if (resultCreationRunning) {
+ subResultsCreateElement.classList.add("disabled");
+ }
+ // After a match as been added or removed the export button will be
+ // hidden because the sub-results have been altered and have to be built
+ // again. Thus subResultsCreateElement has to be shown again.
+ subResultsExportElement.classList.add("hide");
+ subResultsCreateElement.classList.remove("hide");
+ // Also activate/deactivate buttons in the table/jsList results accordingly
+ //if button in inspect was activated/deactivated.
+ // This part only runs if tableCall is false.
+ if (!tableCall) {
+ let tableAddBtn = document.getElementById("query-results").querySelectorAll(`[data-index="${dataIndex}"]`)[0].getElementsByClassName('add')[0].firstElementChild; // gets the add button from the list view
+ if (this.addToSubResultsStatus[dataIndex]) {
+ this.helperActivateBtn(tableAddBtn);
+ } else {
+ this.helperDeactivateBtn(tableAddBtn);
+ }
+ }
+ }
+
+ // Triggers emit to get full match context from server for a number of
+ // matches identified by their data_index.
+ getMatchWithContext(dataIndexes, type) {
+ let tmp_first_cpos = [];
+ let tmp_last_cpos = [];
+ for (let dataIndex of dataIndexes) {
+ tmp_first_cpos.push(results.data.matches[dataIndex].c[0]);
+ tmp_last_cpos.push(results.data.matches[dataIndex].c[1]);
+ }
+ nopaque.socket.emit("corpus_analysis_inspect_match",
+ {
+ type: type,
+ data_indexes: dataIndexes,
+ first_cpos: tmp_first_cpos,
+ last_cpos: tmp_last_cpos,
+ }
+ );
+ }
+
+ // ###### Functions to inspect one match, to show more details ######
+ // activate inspect buttons if progress is 100
+ activateInspect() {
+ if (this.requestQueryProgress === 100) {
+ let inspectBtnElements;
+ inspectBtnElements = document.getElementsByClassName("inspect");
+ for (let inspectBtn of inspectBtnElements) {
+ inspectBtn.classList.remove("disabled");
+ }
+ } else {
+ return
+ }
+ }
+
+ // deactivate inspect buttons
+ deactivateInspect() {
+ let inspectBtnElements;
+ inspectBtnElements = document.getElementsByClassName("inspect");
+ for (let inspectBtn of inspectBtnElements) {
+ inspectBtn.classList.add("disabled");
+ }
+ }
+
+ // ### 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 one dataIndex (list of length 1) to send back to
+ // the server
+ inspect(dataIndex, type) {
+ let contextResultsElement;
+ // get result infos from server and show them in context modal
+ this.contextId = dataIndex[0];
+ contextResultsElement = document.getElementById("context-results");
+ contextResultsElement.innerHTML = ""; // clear it from old inspects
+ this.getMatchWithContext(dataIndex, type);
+ // match nr for user to display derived from data_index
+ let contextMatchNrElement = document.getElementById("context-match-nr");
+ contextMatchNrElement.textContent = this.contextId + 1;
+ contextModal.open();
+ // add a button to add this match to sub results with onclick event
+ let classes = `btn-floating btn waves-effect` +
+ `waves-light grey right`
+ let addToSubResultsIdsBtn = document.createElement("a");
+ addToSubResultsIdsBtn.setAttribute("class", classes + ` add`);
+ addToSubResultsIdsBtn.innerHTML = 'add';
+ addToSubResultsIdsBtn.onclick= () => {this.addToSubResults(dataIndex[0], false)};
+ // checks if a button has already been added to the inspect modal and removes it
+ if (addToSubResultsFromInspectElement.children.length > 0) {
+ addToSubResultsFromInspectElement.firstElementChild.remove();
+ }
+ // Changes the design of the add button according to its checked status
+ // upon opening the inspect modal.
+ if (this.addToSubResultsStatus[dataIndex[0]]) {
+ this.helperActivateBtn(addToSubResultsIdsBtn.firstElementChild);
+ } else if (!this.addToSubResultsStatus[dataIndex[0]]) {
+ this.helperDeactivateBtn(addToSubResultsIdsBtn.firstElementChild);
+ }
+ addToSubResultsFromInspectElement.appendChild(addToSubResultsIdsBtn);
+ }
+
+ // create Element from HTML String helper function
+ HTMLTStrToElement(htmlStr) {
+ // https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
+ let template = document.createElement("template");
+ htmlStr = htmlStr.trim();
+ template.innerHTML = htmlStr;
+ return template.content.firstChild;
+ }
+
+ // Used as a callback to handle incoming match context results when inspect
+ // has been used.
+ showMatchContext(response) {
+ this.contextData;
+ let contextModalLoading;
+ let contextModalReady;
+ let contextResultsElement;
+ let highlightSentencesSwitchElement;
+ let htmlTokenStr;
+ let modalExpertModeSwitchElement;
+ let modalTokenElements;
+ let nrOfContextSentences;
+ let partElement;
+ let token;
+ let tokenHTMLArray;
+ let tokenHTMlElement;
+ let uniqueContextS;
+ let uniqueS;
+
+ this.contextData = response.payload;
+ console.log(this.contextData);
+ this.contextData["cpos_ranges"] = response.payload.cpos_ranges;
+ this.contextData["query"] = results.data.query;
+ this.contextData["context_id"] = this.contextId;
+ this.contextData["match_count"] = this.contextData.matches.length
+ this.contextData["corpus_type"] = "inspect-result"
+ Object.assign(this.contextData, results.metaData);
+ contextResultsElement = document.getElementById("context-results");
+ modalExpertModeSwitchElement = document.getElementById("inspect-display-options-form-expert_mode_inspect");
+ highlightSentencesSwitchElement = document.getElementById("inspect-display-options-form-highlight_sentences");
+ nrOfContextSentences = document.getElementById("context-sentences");
+ uniqueS = new Set();
+ uniqueContextS = new Set();
+ let {lc, c, rc} = this.helperCreateCpos(this.contextData.cpos_ranges,
+ this.contextData.matches[0])
+ // create sentence strings as tokens
+ tokenHTMLArray = [];
+ for (let cpos of lc) {
+ token = this.contextData.cpos_lookup[cpos];
+ uniqueS.add(token.s)
+ htmlTokenStr = `` +
+ `${token.word}` +
+ ``;
+ tokenHTMlElement = this.HTMLTStrToElement(htmlTokenStr)
+ tokenHTMLArray.push(tokenHTMlElement);
+ }
+ for (let cpos of c) {
+ token = this.contextData.cpos_lookup[cpos];
+ uniqueContextS.add(token.s);
+ uniqueS.add(token.s);
+ htmlTokenStr = `` +
+ `${token.word}` +
+ ``;
+ tokenHTMlElement = this.HTMLTStrToElement(htmlTokenStr)
+ tokenHTMLArray.push(tokenHTMlElement);
+ }
+ this.contextData["context_s_ids"] = Array.from(uniqueContextS);
+ for (let cpos of rc) {
+ token = this.contextData.cpos_lookup[cpos];
+ uniqueS.add(token.s)
+ htmlTokenStr = `` +
+ `${token.word}` +
+ ``;
+ tokenHTMlElement = this.HTMLTStrToElement(htmlTokenStr)
+ tokenHTMLArray.push(tokenHTMlElement);
+ }
+ for (let sId of uniqueS) {
+ let htmlSentence = ``;
+ let sentenceElement = this.HTMLTStrToElement(htmlSentence);
+ for (let tokenElement of tokenHTMLArray) {
+ if (tokenElement.dataset.sid == sId) {
+ sentenceElement.appendChild(tokenElement);
+ sentenceElement.insertAdjacentHTML("beforeend", ` `);
+ } else {
+ continue;
+ }
+ }
+ contextResultsElement.appendChild(sentenceElement);
+ }
+
+
+ // add inspect display options events
+ modalExpertModeSwitchElement.onchange = (event) => {
+ if (event.target.checked) {
+ this.expertModeOn("context-results");
+ } else {
+ this.expertModeOff("context-results")
+ }
+ };
+
+ highlightSentencesSwitchElement.onchange = (event) => {
+ if (event.target.checked) {
+ this.higlightContextSentences();
+ } else {
+ this.unhighlightContextSentences();
+ }
+ };
+
+ nrOfContextSentences.onchange = (event) => {
+ // console.log(event.target.value);
+ this.changeSentenceContext(event.target.value);
+ }
+
+ // checks on new modal opening if switches are checked
+ // if switches are checked functions are executed
+ if (modalExpertModeSwitchElement.checked) {
+ this.expertModeOn("context-results");
+ }
+
+ if (highlightSentencesSwitchElement.checked) {
+ this.higlightContextSentences();
+ }
+
+ // checks the value of the number of sentences to show on modal opening
+ // sets context sentences accordingly
+ this.changeSentenceContext(nrOfContextSentences.value)
+ }
+
+ // splits context text into sentences based on spacy sentence split
+ higlightContextSentences() {
+ let sentences;
+ sentences = document.getElementById("context-results").getElementsByClassName("sentence");
+ for (let s of sentences) {
+ s.insertAdjacentHTML("beforeend", `
`)
+ }
+ }
+
+ unhighlightContextSentences() {
+ let sentences;
+ let br;
+ sentences = document.getElementById("context-results").getElementsByClassName("sentence");
+ for (let s of sentences) {
+ br = s.lastChild;
+ br.remove();
+ }
+ }
+
+ // changes how many context sentences in inspect view are shown
+ changeSentenceContext(sValue, maxSValue=10) {
+ let array;
+ let sentences;
+ let toHideArray;
+ let toShowArray;
+ sValue = maxSValue - sValue;
+ // console.log(sValue);
+ sentences = document.getElementById("context-results").getElementsByClassName("sentence");
+ array = Array.from(sentences);
+ if (sValue != 0) {
+ toHideArray = array.slice(0, sValue).concat(array.slice(-(sValue)));
+ toShowArray = array.slice(sValue, 9).concat(array.slice(9, -(sValue)))
+ } else {
+ toHideArray = [];
+ toShowArray = array;
+ }
+ // console.log(array);
+ // console.log("#######");
+ // console.log(toHideArray);
+ for (let s of toHideArray) {
+ s.classList.add("hide");
+ }
+ for (let s of toShowArray) {
+ s.classList.remove("hide");
+ }
+ }
+
+ // ###### Display options changing live how the matches are being displayed ######
+
+ // Event function that changes the shown hits per page.
+ // Just alters the resultsList.page property
+ changeHitsPerPage(event) {
+ try {
+ // console.log(this);
+ this.page = event.target.value;
+ this.update();
+ this.activateInspect();
+ this.pageChangeEventInteractionHandler(interactionElements);
+ if (expertModeSwitchElement.checked) {
+ this.expertModeOn("query-display"); // page holds new result rows, so add new tooltips
+ }
+ nopaque.flash("Updated matches per page.", "corpus")
+ } catch (e) {
+ // console.log(e);
+ // console.log("resultsList has no results right now.");
+ }
+ }
+
+ // Event function triggered on context select change
+ // also if pagination is clicked
+ changeContext(event) {
+ let array;
+ let lc;
+ let newContextValue;
+ let rc;
+ try {
+ if (event.type === "change") {
+ nopaque.flash("Updated context per match!", "corpus");
+ }
+ } catch (e) {
+ } finally {
+ newContextValue = document.getElementById("display-options-form-result_context").value;
+ 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.reverse().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 ######
+ // function to create a tooltip for the current hovered token
+ tooltipEventCreate(event, client) {
+ // console.log("Create Tooltip on mouseover.");
+ let token = client.results.data.cpos_lookup[event.target.dataset.cpos];
+ if (!token) {
+ token = this.contextData.cpos_lookup[event.target.dataset.cpos];
+ }
+ this.addToolTipToTokenElement(event.target, token, client);
+ }
+
+ // Function to destroy the current Tooltip for the current hovered tooltip
+ // on mouse leave
+ tooltipEventDestroy() {
+ // console.log("Tooltip destroy on leave.");
+ this.currentTooltipElement.destroy();
+ }
+
+ // 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])) {
+ this.currentExpertTokenElements[htmlId] = [];
+ }
+ let container = document.getElementById(htmlId);
+ let tokens = container.querySelectorAll("span.token");
+ this.currentExpertTokenElements[htmlId].push(...tokens);
+ this.eventTokens[htmlId] = [];
+ for (let tokenElement of this.currentExpertTokenElements[htmlId]) {
+ tokenElement.classList.add("chip", "hoverable", "expert-view");
+ const eventCreate = (event, arg) => this.tooltipEventCreate(event, arg);
+ tokenElement.onmouseover = (event) => eventCreate(event, client);
+ tokenElement.onmouseout = () => this.tooltipEventDestroy();
+ this.eventTokens[htmlId].push(tokenElement);
+ }
+ }
+
+ // fuction that creates Tooltip for one token and extracts the corresponding
+ // infos from the result JSON
+ addToolTipToTokenElement(tokenElement, token, client) {
+ this.currentTooltipElement;
+ this.currentTooltipElement = 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: ${client.results.data.text_lookup[token.text].title}
+ + Author: ${client.results.data.text_lookup[token.text].author} + + Publishing year: ${client.results.data.text_lookup[token.text].publishing_year} + |
+
Metadata Description | +Value | +|
---|---|---|
${outerKey.replace(/_/g, " ")} | ` + if (outerKey === "corpus_all_texts" || outerKey === "text_lookup") { + html += `
+
| `
+ } else {
+ html += `${outerValue} | ` + } + html += `
Token information | -Source information | -
---|---|
- Word: ${token.word} - Lemma: ${token.lemma} - POS: ${token.pos} - Simple POS: ${token.simple_pos} - NER: ${token.ner} - |
-
- Title: ${client.results.data.text_lookup[token.text].title}
- - Author: ${client.results.data.text_lookup[token.text].author} - - Publishing year: ${client.results.data.text_lookup[token.text].publishing_year} - |
-
Metadata Description | -Value | -|
---|---|---|
${outerKey.replace(/_/g, " ")} | ` - if (outerKey === "corpus_all_texts" || outerKey === "text_lookup") { - html += `
-
| `
- } else {
- html += `${outerValue} | ` - } - html += `