mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-03 20:02:47 +00:00 
			
		
		
		
	New project structure
This commit is contained in:
		@@ -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,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										0
									
								
								web/app/static/js/modules/corpus_analysis/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								web/app/static/js/modules/corpus_analysis/main.js
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
							
								
								
									
										790
									
								
								web/app/static/js/modules/corpus_analysis/view/ResultsView.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										790
									
								
								web/app/static/js/modules/corpus_analysis/view/ResultsView.js
									
									
									
									
									
										Normal file
									
								
							@@ -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: `<span></span>`
 | 
			
		||||
  };
 | 
			
		||||
  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 = '<i class="material-icons">add</i>';
 | 
			
		||||
    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 = `<span class="token"` +
 | 
			
		||||
                           `data-sid="${token.s}"` +
 | 
			
		||||
                           `data-cpos="${cpos}">` +
 | 
			
		||||
                       `${token.word}` +
 | 
			
		||||
                     `</span>`;
 | 
			
		||||
      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 = `<span class="token bold light-green"` +
 | 
			
		||||
                           `data-sid="${token.s}"` +
 | 
			
		||||
                           `data-cpos="${cpos}"` +
 | 
			
		||||
                           `style="text-decoration-line: underline;">` +
 | 
			
		||||
                       `${token.word}` +
 | 
			
		||||
                     `</span>`;
 | 
			
		||||
      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 = `<span class="token"` +
 | 
			
		||||
                           `data-sid="${token.s}"` +
 | 
			
		||||
                           `data-cpos="${cpos}">` +
 | 
			
		||||
                       `${token.word}` +
 | 
			
		||||
                     `</span>`;
 | 
			
		||||
      tokenHTMlElement = this.HTMLTStrToElement(htmlTokenStr)
 | 
			
		||||
      tokenHTMLArray.push(tokenHTMlElement);
 | 
			
		||||
    }
 | 
			
		||||
    for (let sId of uniqueS) {
 | 
			
		||||
      let htmlSentence = `<span class="sentence" data-sid="${sId}"></span>`;
 | 
			
		||||
      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", `<span><br><br></span>`)
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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": `<table>
 | 
			
		||||
                 <tr>
 | 
			
		||||
                   <th>Token information</th>
 | 
			
		||||
                   <th>Source information</th>
 | 
			
		||||
                 </tr>
 | 
			
		||||
                 <tr>
 | 
			
		||||
                   <td class="left-align">
 | 
			
		||||
                     Word: ${token.word}<br>
 | 
			
		||||
                     Lemma: ${token.lemma}<br>
 | 
			
		||||
                     POS: ${token.pos}<br>
 | 
			
		||||
                     Simple POS: ${token.simple_pos}<br>
 | 
			
		||||
                     NER: ${token.ner}
 | 
			
		||||
                   </td>
 | 
			
		||||
                   <td class="left-align">
 | 
			
		||||
                     Title: ${client.results.data.text_lookup[token.text].title}
 | 
			
		||||
                     <br>
 | 
			
		||||
                     Author: ${client.results.data.text_lookup[token.text].author}
 | 
			
		||||
                     <br>
 | 
			
		||||
                     Publishing year: ${client.results.data.text_lookup[token.text].publishing_year}
 | 
			
		||||
                   </td>
 | 
			
		||||
                 </tr>
 | 
			
		||||
               </table>`}
 | 
			
		||||
      );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // function to remove extra informations and animations from tokens
 | 
			
		||||
  expertModeOff(htmlId) {
 | 
			
		||||
    // console.log("Expert mode is off.");
 | 
			
		||||
    if (!Array.isArray(this.currentExpertTokenElements[htmlId])) {
 | 
			
		||||
      this.currentExpertTokenElements[htmlId] = [];
 | 
			
		||||
    }
 | 
			
		||||
    if (!Array.isArray(this.eventTokens[htmlId])) {
 | 
			
		||||
      this.eventTokens[htmlId] = [];
 | 
			
		||||
    }
 | 
			
		||||
    for (let tokenElement of this.currentExpertTokenElements[htmlId]) {
 | 
			
		||||
      tokenElement.classList.remove("chip", "hoverable", "expert-view");
 | 
			
		||||
    }
 | 
			
		||||
    this.currentExpertTokenElements[htmlId] = [];
 | 
			
		||||
 | 
			
		||||
    for (let eventToken of this.eventTokens[htmlId]) {
 | 
			
		||||
      eventToken.onmouseover = "";
 | 
			
		||||
      eventToken.onmouseout = "";
 | 
			
		||||
    }
 | 
			
		||||
  this.eventTokens[htmlId] = [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createResultRowElement(item, chunk, imported=false) {
 | 
			
		||||
    let aCellElement;
 | 
			
		||||
    let addToSubResultsBtn;
 | 
			
		||||
    let cCellElement;
 | 
			
		||||
    let cpos;
 | 
			
		||||
    let fakeResponse;   // used if imported results are being created;
 | 
			
		||||
    let inspectBtn
 | 
			
		||||
    let lcCellElement;
 | 
			
		||||
    let matchNrElement;
 | 
			
		||||
    let matchRowElement;
 | 
			
		||||
    let rcCellElement;
 | 
			
		||||
    let textTitles;
 | 
			
		||||
    let textTitlesCellElement;
 | 
			
		||||
    let token;
 | 
			
		||||
    let values;
 | 
			
		||||
    // gather values from item
 | 
			
		||||
    values = item.values();
 | 
			
		||||
    let {lc, c, rc} = this.helperCreateCpos(chunk.cpos_ranges,
 | 
			
		||||
                                            values)
 | 
			
		||||
    // get infos for full match row
 | 
			
		||||
    matchRowElement = document.createElement("tr");
 | 
			
		||||
    matchRowElement.setAttribute("data-index", values.index)
 | 
			
		||||
    lcCellElement = document.createElement("td");
 | 
			
		||||
    lcCellElement.classList.add("left-context");
 | 
			
		||||
    matchRowElement.appendChild(lcCellElement);
 | 
			
		||||
    for (cpos of lc) {
 | 
			
		||||
      token = chunk.cpos_lookup[cpos];
 | 
			
		||||
      lcCellElement.insertAdjacentHTML("beforeend",
 | 
			
		||||
        `<span class="token" data-cpos="${cpos}">${token.word} </span>`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get infos for hit of match and set actions
 | 
			
		||||
    textTitles = new Set();
 | 
			
		||||
    aCellElement = document.createElement("td");
 | 
			
		||||
    aCellElement.classList.add("actions");
 | 
			
		||||
    cCellElement = document.createElement("td");
 | 
			
		||||
    cCellElement.classList.add("match-hit");
 | 
			
		||||
    textTitlesCellElement = document.createElement("td");
 | 
			
		||||
    textTitlesCellElement.classList.add("titles");
 | 
			
		||||
    matchNrElement = document.createElement("td");
 | 
			
		||||
    matchNrElement.classList.add("match-nr");
 | 
			
		||||
    matchRowElement.appendChild(cCellElement);
 | 
			
		||||
    matchRowElement.appendChild(aCellElement);
 | 
			
		||||
    for (cpos of c) {
 | 
			
		||||
      token = chunk.cpos_lookup[cpos];
 | 
			
		||||
      cCellElement.insertAdjacentHTML("beforeend",
 | 
			
		||||
        `<span class="token" data-cpos="${cpos}">${token.word} </span>`);
 | 
			
		||||
      // get text titles of every hit cpos token
 | 
			
		||||
      textTitles.add(chunk.text_lookup[token.text].title);
 | 
			
		||||
    }
 | 
			
		||||
    // add some interaction buttons
 | 
			
		||||
    // # some btn css rules and classes
 | 
			
		||||
    let css = `margin-right: 5px; margin-bottom: 5px;`
 | 
			
		||||
    let classes = `btn-floating btn waves-effect` +
 | 
			
		||||
                  `waves-light grey`
 | 
			
		||||
    // # add button to trigger more context to every match td
 | 
			
		||||
    inspectBtn = document.createElement("a");
 | 
			
		||||
    inspectBtn.setAttribute("style", css);
 | 
			
		||||
    inspectBtn.setAttribute("class", classes + ` disabled inspect`
 | 
			
		||||
                            );
 | 
			
		||||
    inspectBtn.innerHTML = '<i class="material-icons inspect-btn">search</i>';
 | 
			
		||||
    // # add btn to add matches to sub-results. hidden per default
 | 
			
		||||
    addToSubResultsBtn = document.createElement("a");
 | 
			
		||||
    addToSubResultsBtn.setAttribute("style", css);
 | 
			
		||||
    addToSubResultsBtn.setAttribute("class", classes + ` hide add`
 | 
			
		||||
                                );
 | 
			
		||||
    addToSubResultsBtn.innerHTML = '<i class="material-icons add-btn">add</i>';
 | 
			
		||||
    aCellElement.appendChild(inspectBtn);
 | 
			
		||||
    aCellElement.appendChild(addToSubResultsBtn);
 | 
			
		||||
    // add text titles at front as first td of one row
 | 
			
		||||
    textTitlesCellElement.textContent = [...textTitles].join(", ");
 | 
			
		||||
    matchRowElement.insertAdjacentHTML("afterbegin", textTitlesCellElement.outerHTML);
 | 
			
		||||
    matchNrElement.textContent = values.index + 1;
 | 
			
		||||
    matchRowElement.insertAdjacentHTML("afterbegin", matchNrElement.outerHTML);
 | 
			
		||||
 | 
			
		||||
    // get infos for right context of match
 | 
			
		||||
    rcCellElement = document.createElement("td");
 | 
			
		||||
    rcCellElement.classList.add("right-context");
 | 
			
		||||
    matchRowElement.appendChild(rcCellElement);
 | 
			
		||||
    for (cpos of rc) {
 | 
			
		||||
      token = chunk.cpos_lookup[cpos];
 | 
			
		||||
      rcCellElement.insertAdjacentHTML("beforeend",
 | 
			
		||||
        `<span class="token" data-cpos="${cpos}">${token.word} </span>`);
 | 
			
		||||
    }
 | 
			
		||||
    return matchRowElement
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // creates the HTML table code for the metadata vie in the corpus analysis interface
 | 
			
		||||
  createMetaDataForModal(metaDataObject) {
 | 
			
		||||
    let html = `<div class="col s12">
 | 
			
		||||
                      <table class="highlight">
 | 
			
		||||
                        <thead>
 | 
			
		||||
                          <tr>
 | 
			
		||||
                            <th>Metadata Description</th>
 | 
			
		||||
                            <th>Value</th>
 | 
			
		||||
                          </tr>
 | 
			
		||||
                        </thead>
 | 
			
		||||
                        <tbody>`
 | 
			
		||||
    for (let [outerKey, outerValue] of Object.entries(metaDataObject)) {
 | 
			
		||||
      html += `<tr>
 | 
			
		||||
                  <td style="text-transform: uppercase;">${outerKey.replace(/_/g, " ")}</td>`
 | 
			
		||||
      if (outerKey === "corpus_all_texts" || outerKey === "text_lookup") {
 | 
			
		||||
        html += `<td>
 | 
			
		||||
                  <ul class="collapsible">`
 | 
			
		||||
        for (let [innerKey, innerValue] of Object.entries(outerValue)) {
 | 
			
		||||
          html += `<li class="text-metadata"
 | 
			
		||||
                        data-metadata-key="${outerKey}"
 | 
			
		||||
                        data-text-key="${innerKey}">
 | 
			
		||||
                      <div class="collapsible-header"
 | 
			
		||||
                           data-metadata-key="${outerKey}"
 | 
			
		||||
                           data-text-key="${innerKey}">
 | 
			
		||||
                        <i class="material-icons"
 | 
			
		||||
                           data-metadata-key="${outerKey}"
 | 
			
		||||
                           data-text-key="${innerKey}">info_outline</i>
 | 
			
		||||
                           ${innerValue['author']} - ${innerValue['publishing_year']} -
 | 
			
		||||
                           ${innerValue['title']}
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div class="collapsible-body">
 | 
			
		||||
                        <span>
 | 
			
		||||
                          <ul id="bibliographic-data-${outerKey}-${innerKey}"
 | 
			
		||||
                              style="column-count: 2;">
 | 
			
		||||
                          </ul>
 | 
			
		||||
                        </span>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </li>`
 | 
			
		||||
        }
 | 
			
		||||
        html += `</ul>
 | 
			
		||||
                  </td>`
 | 
			
		||||
      } else {
 | 
			
		||||
        html += `<td>${outerValue}</td>`
 | 
			
		||||
      }
 | 
			
		||||
      html += `</tr>`
 | 
			
		||||
    }
 | 
			
		||||
    html += `</tbody>
 | 
			
		||||
              </table>`
 | 
			
		||||
    return html
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Creates the text details for the texts shown in the corpus analysis metadata modal.
 | 
			
		||||
  createTextDetails(metaDataObject) {
 | 
			
		||||
    let metadataKey = event.target.dataset.metadataKey;
 | 
			
		||||
    let textKey = event.target.dataset.textKey;
 | 
			
		||||
    let textData = metaDataObject[metadataKey][textKey];
 | 
			
		||||
    let bibliographicData = document.getElementById(`bibliographic-data-${metadataKey}-${textKey}`);
 | 
			
		||||
    bibliographicData.innerHTML = "";
 | 
			
		||||
    for (let [key, value] of Object.entries(textData)) {
 | 
			
		||||
      bibliographicData.insertAdjacentHTML("afterbegin",
 | 
			
		||||
      `
 | 
			
		||||
      <li><span style="text-transform: capitalize;">${key}:</span> ${value}</li>
 | 
			
		||||
      `);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Function to show a scrol lto top button if the user has scrolled down
 | 
			
		||||
 * 250 pixels from teh headline element.
 | 
			
		||||
 * Function to show a scroll to top button if the user has scrolled down
 | 
			
		||||
 * 250 pixels from the headline element.
 | 
			
		||||
 */
 | 
			
		||||
function scrollToTop() {
 | 
			
		||||
  let headline = document.querySelector(".headline");
 | 
			
		||||
@@ -423,789 +423,4 @@ RessourceList.options = {
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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: `<span></span>`
 | 
			
		||||
  };
 | 
			
		||||
  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 = '<i class="material-icons">add</i>';
 | 
			
		||||
    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 = `<span class="token"` +
 | 
			
		||||
                           `data-sid="${token.s}"` +
 | 
			
		||||
                           `data-cpos="${cpos}">` +
 | 
			
		||||
                       `${token.word}` +
 | 
			
		||||
                     `</span>`;
 | 
			
		||||
      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 = `<span class="token bold light-green"` +
 | 
			
		||||
                           `data-sid="${token.s}"` +
 | 
			
		||||
                           `data-cpos="${cpos}"` +
 | 
			
		||||
                           `style="text-decoration-line: underline;">` +
 | 
			
		||||
                       `${token.word}` +
 | 
			
		||||
                     `</span>`;
 | 
			
		||||
      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 = `<span class="token"` +
 | 
			
		||||
                           `data-sid="${token.s}"` +
 | 
			
		||||
                           `data-cpos="${cpos}">` +
 | 
			
		||||
                       `${token.word}` +
 | 
			
		||||
                     `</span>`;
 | 
			
		||||
      tokenHTMlElement = this.HTMLTStrToElement(htmlTokenStr)
 | 
			
		||||
      tokenHTMLArray.push(tokenHTMlElement);
 | 
			
		||||
    }
 | 
			
		||||
    for (let sId of uniqueS) {
 | 
			
		||||
      let htmlSentence = `<span class="sentence" data-sid="${sId}"></span>`;
 | 
			
		||||
      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", `<span><br><br></span>`)
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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": `<table>
 | 
			
		||||
                 <tr>
 | 
			
		||||
                   <th>Token information</th>
 | 
			
		||||
                   <th>Source information</th>
 | 
			
		||||
                 </tr>
 | 
			
		||||
                 <tr>
 | 
			
		||||
                   <td class="left-align">
 | 
			
		||||
                     Word: ${token.word}<br>
 | 
			
		||||
                     Lemma: ${token.lemma}<br>
 | 
			
		||||
                     POS: ${token.pos}<br>
 | 
			
		||||
                     Simple POS: ${token.simple_pos}<br>
 | 
			
		||||
                     NER: ${token.ner}
 | 
			
		||||
                   </td>
 | 
			
		||||
                   <td class="left-align">
 | 
			
		||||
                     Title: ${client.results.data.text_lookup[token.text].title}
 | 
			
		||||
                     <br>
 | 
			
		||||
                     Author: ${client.results.data.text_lookup[token.text].author}
 | 
			
		||||
                     <br>
 | 
			
		||||
                     Publishing year: ${client.results.data.text_lookup[token.text].publishing_year}
 | 
			
		||||
                   </td>
 | 
			
		||||
                 </tr>
 | 
			
		||||
               </table>`}
 | 
			
		||||
      );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // function to remove extra informations and animations from tokens
 | 
			
		||||
  expertModeOff(htmlId) {
 | 
			
		||||
    // console.log("Expert mode is off.");
 | 
			
		||||
    if (!Array.isArray(this.currentExpertTokenElements[htmlId])) {
 | 
			
		||||
      this.currentExpertTokenElements[htmlId] = [];
 | 
			
		||||
    }
 | 
			
		||||
    if (!Array.isArray(this.eventTokens[htmlId])) {
 | 
			
		||||
      this.eventTokens[htmlId] = [];
 | 
			
		||||
    }
 | 
			
		||||
    for (let tokenElement of this.currentExpertTokenElements[htmlId]) {
 | 
			
		||||
      tokenElement.classList.remove("chip", "hoverable", "expert-view");
 | 
			
		||||
    }
 | 
			
		||||
    this.currentExpertTokenElements[htmlId] = [];
 | 
			
		||||
 | 
			
		||||
    for (let eventToken of this.eventTokens[htmlId]) {
 | 
			
		||||
      eventToken.onmouseover = "";
 | 
			
		||||
      eventToken.onmouseout = "";
 | 
			
		||||
    }
 | 
			
		||||
  this.eventTokens[htmlId] = [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createResultRowElement(item, chunk, imported=false) {
 | 
			
		||||
    let aCellElement;
 | 
			
		||||
    let addToSubResultsBtn;
 | 
			
		||||
    let cCellElement;
 | 
			
		||||
    let cpos;
 | 
			
		||||
    let fakeResponse;   // used if imported results are being created;
 | 
			
		||||
    let inspectBtn
 | 
			
		||||
    let lcCellElement;
 | 
			
		||||
    let matchNrElement;
 | 
			
		||||
    let matchRowElement;
 | 
			
		||||
    let rcCellElement;
 | 
			
		||||
    let textTitles;
 | 
			
		||||
    let textTitlesCellElement;
 | 
			
		||||
    let token;
 | 
			
		||||
    let values;
 | 
			
		||||
    // gather values from item
 | 
			
		||||
    values = item.values();
 | 
			
		||||
    let {lc, c, rc} = this.helperCreateCpos(chunk.cpos_ranges,
 | 
			
		||||
                                            values)
 | 
			
		||||
    // get infos for full match row
 | 
			
		||||
    matchRowElement = document.createElement("tr");
 | 
			
		||||
    matchRowElement.setAttribute("data-index", values.index)
 | 
			
		||||
    lcCellElement = document.createElement("td");
 | 
			
		||||
    lcCellElement.classList.add("left-context");
 | 
			
		||||
    matchRowElement.appendChild(lcCellElement);
 | 
			
		||||
    for (cpos of lc) {
 | 
			
		||||
      token = chunk.cpos_lookup[cpos];
 | 
			
		||||
      lcCellElement.insertAdjacentHTML("beforeend",
 | 
			
		||||
        `<span class="token" data-cpos="${cpos}">${token.word} </span>`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get infos for hit of match and set actions
 | 
			
		||||
    textTitles = new Set();
 | 
			
		||||
    aCellElement = document.createElement("td");
 | 
			
		||||
    aCellElement.classList.add("actions");
 | 
			
		||||
    cCellElement = document.createElement("td");
 | 
			
		||||
    cCellElement.classList.add("match-hit");
 | 
			
		||||
    textTitlesCellElement = document.createElement("td");
 | 
			
		||||
    textTitlesCellElement.classList.add("titles");
 | 
			
		||||
    matchNrElement = document.createElement("td");
 | 
			
		||||
    matchNrElement.classList.add("match-nr");
 | 
			
		||||
    matchRowElement.appendChild(cCellElement);
 | 
			
		||||
    matchRowElement.appendChild(aCellElement);
 | 
			
		||||
    for (cpos of c) {
 | 
			
		||||
      token = chunk.cpos_lookup[cpos];
 | 
			
		||||
      cCellElement.insertAdjacentHTML("beforeend",
 | 
			
		||||
        `<span class="token" data-cpos="${cpos}">${token.word} </span>`);
 | 
			
		||||
      // get text titles of every hit cpos token
 | 
			
		||||
      textTitles.add(chunk.text_lookup[token.text].title);
 | 
			
		||||
    }
 | 
			
		||||
    // add some interaction buttons
 | 
			
		||||
    // # some btn css rules and classes
 | 
			
		||||
    let css = `margin-right: 5px; margin-bottom: 5px;`
 | 
			
		||||
    let classes = `btn-floating btn waves-effect` +
 | 
			
		||||
                  `waves-light grey`
 | 
			
		||||
    // # add button to trigger more context to every match td
 | 
			
		||||
    inspectBtn = document.createElement("a");
 | 
			
		||||
    inspectBtn.setAttribute("style", css);
 | 
			
		||||
    inspectBtn.setAttribute("class", classes + ` disabled inspect`
 | 
			
		||||
                            );
 | 
			
		||||
    inspectBtn.innerHTML = '<i class="material-icons inspect-btn">search</i>';
 | 
			
		||||
    // # add btn to add matches to sub-results. hidden per default
 | 
			
		||||
    addToSubResultsBtn = document.createElement("a");
 | 
			
		||||
    addToSubResultsBtn.setAttribute("style", css);
 | 
			
		||||
    addToSubResultsBtn.setAttribute("class", classes + ` hide add`
 | 
			
		||||
                                );
 | 
			
		||||
    addToSubResultsBtn.innerHTML = '<i class="material-icons add-btn">add</i>';
 | 
			
		||||
    aCellElement.appendChild(inspectBtn);
 | 
			
		||||
    aCellElement.appendChild(addToSubResultsBtn);
 | 
			
		||||
    // add text titles at front as first td of one row
 | 
			
		||||
    textTitlesCellElement.textContent = [...textTitles].join(", ");
 | 
			
		||||
    matchRowElement.insertAdjacentHTML("afterbegin", textTitlesCellElement.outerHTML);
 | 
			
		||||
    matchNrElement.textContent = values.index + 1;
 | 
			
		||||
    matchRowElement.insertAdjacentHTML("afterbegin", matchNrElement.outerHTML);
 | 
			
		||||
 | 
			
		||||
    // get infos for right context of match
 | 
			
		||||
    rcCellElement = document.createElement("td");
 | 
			
		||||
    rcCellElement.classList.add("right-context");
 | 
			
		||||
    matchRowElement.appendChild(rcCellElement);
 | 
			
		||||
    for (cpos of rc) {
 | 
			
		||||
      token = chunk.cpos_lookup[cpos];
 | 
			
		||||
      rcCellElement.insertAdjacentHTML("beforeend",
 | 
			
		||||
        `<span class="token" data-cpos="${cpos}">${token.word} </span>`);
 | 
			
		||||
    }
 | 
			
		||||
    return matchRowElement
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // creates the HTML table code for the metadata vie in the corpus analysis interface
 | 
			
		||||
  createMetaDataForModal(metaDataObject) {
 | 
			
		||||
    let html = `<div class="col s12">
 | 
			
		||||
                      <table class="highlight">
 | 
			
		||||
                        <thead>
 | 
			
		||||
                          <tr>
 | 
			
		||||
                            <th>Metadata Description</th>
 | 
			
		||||
                            <th>Value</th>
 | 
			
		||||
                          </tr>
 | 
			
		||||
                        </thead>
 | 
			
		||||
                        <tbody>`
 | 
			
		||||
    for (let [outerKey, outerValue] of Object.entries(metaDataObject)) {
 | 
			
		||||
      html += `<tr>
 | 
			
		||||
                  <td style="text-transform: uppercase;">${outerKey.replace(/_/g, " ")}</td>`
 | 
			
		||||
      if (outerKey === "corpus_all_texts" || outerKey === "text_lookup") {
 | 
			
		||||
        html += `<td>
 | 
			
		||||
                  <ul class="collapsible">`
 | 
			
		||||
        for (let [innerKey, innerValue] of Object.entries(outerValue)) {
 | 
			
		||||
          html += `<li class="text-metadata"
 | 
			
		||||
                        data-metadata-key="${outerKey}"
 | 
			
		||||
                        data-text-key="${innerKey}">
 | 
			
		||||
                      <div class="collapsible-header"
 | 
			
		||||
                           data-metadata-key="${outerKey}"
 | 
			
		||||
                           data-text-key="${innerKey}">
 | 
			
		||||
                        <i class="material-icons"
 | 
			
		||||
                           data-metadata-key="${outerKey}"
 | 
			
		||||
                           data-text-key="${innerKey}">info_outline</i>
 | 
			
		||||
                           ${innerValue['author']} - ${innerValue['publishing_year']} -
 | 
			
		||||
                           ${innerValue['title']}
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div class="collapsible-body">
 | 
			
		||||
                        <span>
 | 
			
		||||
                          <ul id="bibliographic-data-${outerKey}-${innerKey}"
 | 
			
		||||
                              style="column-count: 2;">
 | 
			
		||||
                          </ul>
 | 
			
		||||
                        </span>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </li>`
 | 
			
		||||
        }
 | 
			
		||||
        html += `</ul>
 | 
			
		||||
                  </td>`
 | 
			
		||||
      } else {
 | 
			
		||||
        html += `<td>${outerValue}</td>`
 | 
			
		||||
      }
 | 
			
		||||
      html += `</tr>`
 | 
			
		||||
    }
 | 
			
		||||
    html += `</tbody>
 | 
			
		||||
              </table>`
 | 
			
		||||
    return html
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Creates the text details for the texts shown in the corpus analysis metadata modal.
 | 
			
		||||
  createTextDetails(metaDataObject) {
 | 
			
		||||
    let metadataKey = event.target.dataset.metadataKey;
 | 
			
		||||
    let textKey = event.target.dataset.textKey;
 | 
			
		||||
    let textData = metaDataObject[metadataKey][textKey];
 | 
			
		||||
    let bibliographicData = document.getElementById(`bibliographic-data-${metadataKey}-${textKey}`);
 | 
			
		||||
    bibliographicData.innerHTML = "";
 | 
			
		||||
    for (let [key, value] of Object.entries(textData)) {
 | 
			
		||||
      bibliographicData.insertAdjacentHTML("afterbegin",
 | 
			
		||||
      `
 | 
			
		||||
      <li><span style="text-transform: capitalize;">${key}:</span> ${value}</li>
 | 
			
		||||
      `);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export {RessourceList, ResultsList};
 | 
			
		||||
export { RessourceList, };
 | 
			
		||||
 
 | 
			
		||||
@@ -65,173 +65,7 @@
 | 
			
		||||
{% include 'modals/export_query_results.html.j2' %}
 | 
			
		||||
{% include 'modals/context_modal.html.j2' %}
 | 
			
		||||
 | 
			
		||||
<!-- import modules -->
 | 
			
		||||
<script type="module">
 | 
			
		||||
/**
 | 
			
		||||
 * First Phase:
 | 
			
		||||
 * Document content is loaded and scripts are being imported and executed.
 | 
			
		||||
 */
 | 
			
		||||
import {
 | 
			
		||||
  CorpusAnalysisClient,
 | 
			
		||||
  CorpusAnalysisDisplay,
 | 
			
		||||
  SocketEventListener,
 | 
			
		||||
  ListenerCallback,
 | 
			
		||||
} from '../../static/js/modules/nopaque.CorpusAnalysisClient.js';
 | 
			
		||||
import {
 | 
			
		||||
  recieveSession,
 | 
			
		||||
  recieveQueryStatus,
 | 
			
		||||
  recieveQueryData,
 | 
			
		||||
} from '../../static/js/modules/nopaque.listenerFunctions.js';
 | 
			
		||||
import {
 | 
			
		||||
  querySetup,
 | 
			
		||||
  queryRenderResults,
 | 
			
		||||
} from '../../static/js/modules/nopaque.listenerCallbacks.js'
 | 
			
		||||
import {
 | 
			
		||||
  Results,
 | 
			
		||||
  Data,
 | 
			
		||||
  MetaData,
 | 
			
		||||
} from '../../static/js/nopaque.Results.js';
 | 
			
		||||
import {
 | 
			
		||||
  ResultsList,
 | 
			
		||||
} from '../../static/js/nopaque.lists.js';
 | 
			
		||||
import {
 | 
			
		||||
  scrollToTop,
 | 
			
		||||
} from '../../static/js/modules/nopaque.scrollToTop.js';
 | 
			
		||||
import {
 | 
			
		||||
  InteractionElement,
 | 
			
		||||
  InteractionElements,
 | 
			
		||||
} from '../../static/js/modules/nopaque.InteractionElement.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Second Phase:
 | 
			
		||||
 * Asynchronus and event driven code
 | 
			
		||||
 */
 | 
			
		||||
document.addEventListener("DOMContentLoaded", () => {
 | 
			
		||||
  // Initialize the CorpusAnalysisClient dynamic mode
 | 
			
		||||
  let corpusId = {{ corpus_id}}
 | 
			
		||||
  const client = new CorpusAnalysisClient({'corpusId': corpusId,
 | 
			
		||||
                                           'socket': nopaque.socket,
 | 
			
		||||
                                           'logging': true,
 | 
			
		||||
                                           'dynamicMode': true});
 | 
			
		||||
  console.info("CorpusAnalysisClient created as client:", client);
 | 
			
		||||
  // Initialize modals which are shown depending on events or client status
 | 
			
		||||
  const initLoadingElement = document.getElementById("init-display");
 | 
			
		||||
  const initLoadingModal = M.Modal.init(initLoadingElement,
 | 
			
		||||
                                        {"dismissible": false});
 | 
			
		||||
  // Set up display elements which are shown depending on the client status
 | 
			
		||||
  const initLoadingDisplay = new CorpusAnalysisDisplay(initLoadingModal);
 | 
			
		||||
  client.getHTMLElements(['#query-display']);
 | 
			
		||||
  const queryDisplay = new CorpusAnalysisDisplay(client.queryDisplay);
 | 
			
		||||
  // Register those display elements to client
 | 
			
		||||
  client.setDisplay("init", initLoadingDisplay);
 | 
			
		||||
  client.setDisplay("query", queryDisplay);
 | 
			
		||||
  /**
 | 
			
		||||
   * Initializing the results object holding all the data of a query.
 | 
			
		||||
   * Also holds the metadata of one query.
 | 
			
		||||
   * Lastly it contains the object ResultsList which is a list.js
 | 
			
		||||
   * subclass which handles the visual representation of the query data.
 | 
			
		||||
   */
 | 
			
		||||
  let displayOptionsData = ResultsList.getDisplayOptions('display-options-form');
 | 
			
		||||
  ResultsList.options.page = displayOptionsData["resultsPerPage"];
 | 
			
		||||
  let data = new Data();
 | 
			
		||||
  let resultsList = new ResultsList("result-list", ResultsList.options);
 | 
			
		||||
  let resultsMetaData = new MetaData();
 | 
			
		||||
  let results = new Results(data, resultsList, resultsMetaData);
 | 
			
		||||
  // Make results part of the client
 | 
			
		||||
  client.results = results;
 | 
			
		||||
  console.info('Initialized the Results object.')
 | 
			
		||||
  /**
 | 
			
		||||
   * Initialization of interactionElemnts
 | 
			
		||||
   * An interactionElement is an object identifing a switch or button via
 | 
			
		||||
   * htmlID. Callbacks are set for these elements which will be triggered on
 | 
			
		||||
   * a pagination interaction by the user or if the status of the element has
 | 
			
		||||
   * been altered. (Like the switche has ben turned on or off).
 | 
			
		||||
   */
 | 
			
		||||
  let interactionElements = new InteractionElements();
 | 
			
		||||
  const expertModeInteraction = new InteractionElement("display-options-form-expert_mode");
 | 
			
		||||
  expertModeInteraction.setCallback('on',
 | 
			
		||||
                                  results.jsList.expertModeOn,
 | 
			
		||||
                                  results.jsList,
 | 
			
		||||
                                  ['query-display', client]);
 | 
			
		||||
  expertModeInteraction.setCallback('off',
 | 
			
		||||
                                    results.jsList.expertModeOff,
 | 
			
		||||
                                    results.jsList,
 | 
			
		||||
                                    ['query-display', client]);
 | 
			
		||||
  const subResultsInteraction = new InteractionElement("add-to-sub-results");
 | 
			
		||||
  subResultsInteraction.setCallback('on',
 | 
			
		||||
                                     results.jsList.activateAddToSubResults,
 | 
			
		||||
                                     results.jsList);
 | 
			
		||||
  subResultsInteraction.setCallback('off',
 | 
			
		||||
                                     results.jsList.deactivateAddToSubResults,
 | 
			
		||||
                                     results.jsList);
 | 
			
		||||
 | 
			
		||||
  const activateInspectInteraction = new InteractionElement('inspect',
 | 
			
		||||
                                                            false);
 | 
			
		||||
  activateInspectInteraction.setCallback('noCheck',
 | 
			
		||||
                                         results.jsList.activateInspect,
 | 
			
		||||
                                         results.jsList);
 | 
			
		||||
  const changeContextInteraction = new InteractionElement('display-options-form-results_per_page',
 | 
			
		||||
                                                          false);
 | 
			
		||||
  changeContextInteraction.setCallback('noCheck',
 | 
			
		||||
                                       results.jsList.changeContext,
 | 
			
		||||
                                       results.jsList)
 | 
			
		||||
  interactionElements.addInteractions([expertModeInteraction,
 | 
			
		||||
                                       subResultsInteraction,
 | 
			
		||||
                                       activateInspectInteraction,
 | 
			
		||||
                                       changeContextInteraction]);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
  * Checks if a change for every interactionElement happens and executes
 | 
			
		||||
  * the callbacks accordingly.
 | 
			
		||||
  */
 | 
			
		||||
  interactionElements.onChangeExecute();
 | 
			
		||||
  /**
 | 
			
		||||
   * Register listeners listening to socket.io events and their callbacks
 | 
			
		||||
   * Afterwards load them.
 | 
			
		||||
   */
 | 
			
		||||
  const listenForSession = new SocketEventListener('corpus_analysis_init',
 | 
			
		||||
                                                  recieveSession);
 | 
			
		||||
  const listenForQueryStatus = new SocketEventListener('corpus_analysis_query',
 | 
			
		||||
                                                       recieveQueryStatus);
 | 
			
		||||
  const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
 | 
			
		||||
                                                   querySetup);
 | 
			
		||||
  listenForQueryStatus.setCallbacks([queryStatusCallback]);
 | 
			
		||||
  const listenForQueryData = new SocketEventListener('corpus_analysis_query_results',
 | 
			
		||||
                                                  recieveQueryData);
 | 
			
		||||
  const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
 | 
			
		||||
                                                 queryRenderResults);
 | 
			
		||||
  listenForQueryData.setCallbacks([queryDataCallback]);
 | 
			
		||||
  client.setSocketEventListeners([listenForSession, listenForQueryStatus,
 | 
			
		||||
                                  listenForQueryData]);
 | 
			
		||||
  client.loadSocketEventListeners();
 | 
			
		||||
  // Session initialization
 | 
			
		||||
  client.requestSession();
 | 
			
		||||
  // Send a query and recieve its answer data
 | 
			
		||||
  let queryFormElement = document.getElementById("query-form");
 | 
			
		||||
  queryFormElement.addEventListener("submit", (event) => {
 | 
			
		||||
    try {
 | 
			
		||||
      /**
 | 
			
		||||
       * Selects first page of result list if pagination is already available
 | 
			
		||||
       * from an query submitted before.
 | 
			
		||||
       * This avoids confusion for the user e.g.: The user was on page 24
 | 
			
		||||
       * reviewing the results and issues a new query. He would not see any
 | 
			
		||||
       * results until the new results reach page 24 or he clicks on another
 | 
			
		||||
       * valid result page element from the new pagination.
 | 
			
		||||
       */
 | 
			
		||||
      let firstPageElement = document.querySelector('a.page');
 | 
			
		||||
      firstPageElement.click();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      // No page element is present if first query is submitted.
 | 
			
		||||
    }
 | 
			
		||||
    // Prevent page from reloading on submit
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
    // Get query string and send query to server
 | 
			
		||||
    results.data.getQueryStr(queryFormElement);
 | 
			
		||||
    client.requestQueryData(results.data.query);
 | 
			
		||||
 | 
			
		||||
    // Add scrollToTop functionality
 | 
			
		||||
    scrollToTop();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
<script type="text/javascript"
 | 
			
		||||
        src="web/app/static/js/modules/corpus_analysis/main.js">
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										237
									
								
								web/app/templates/corpora/analyse_corpus.html.j2.new.bak
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								web/app/templates/corpora/analyse_corpus.html.j2.new.bak
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,237 @@
 | 
			
		||||
{% extends "nopaque.html.j2" %}
 | 
			
		||||
 | 
			
		||||
{% set headline = ' ' %}
 | 
			
		||||
 | 
			
		||||
{% set full_width = True %}
 | 
			
		||||
{% set imported = False %}
 | 
			
		||||
 | 
			
		||||
{% block page_content %}
 | 
			
		||||
<div class="col s12">
 | 
			
		||||
  <div class="card">
 | 
			
		||||
    <div class="card-content" style="padding-top: 5px;
 | 
			
		||||
                             padding-bottom: 0px;">
 | 
			
		||||
      <!-- Query form -->
 | 
			
		||||
      <div class="row">
 | 
			
		||||
      <form id="query-form">
 | 
			
		||||
          <div class="col s12 m10">
 | 
			
		||||
            <div class="input-field">
 | 
			
		||||
              <i class="material-icons prefix">search</i>
 | 
			
		||||
              {{ query_form.query() }}
 | 
			
		||||
              {{ query_form.query.label }}
 | 
			
		||||
              <span class="helper-text">
 | 
			
		||||
                <a href="http://cwb.sourceforge.net/files/CQP_Tutorial/">
 | 
			
		||||
                  <i class="material-icons" style="font-size: inherit;">help
 | 
			
		||||
                  </i>
 | 
			
		||||
                  CQP query language tutorial
 | 
			
		||||
                </a>
 | 
			
		||||
              </span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="col s12 m2 right-align">
 | 
			
		||||
            <br class="hide-on-small-only">
 | 
			
		||||
            {{ M.render_field(query_form.submit, material_icon='send') }}
 | 
			
		||||
          </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<!-- entire results div/card -->
 | 
			
		||||
<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">
 | 
			
		||||
        {% include 'interactions/infos.html.j2' %}
 | 
			
		||||
        {% include 'interactions/export.html.j2' %}
 | 
			
		||||
        {% include 'interactions/create.html.j2' %}
 | 
			
		||||
        {% include 'interactions/display.html.j2' %}
 | 
			
		||||
        {% include 'interactions/analysis.html.j2' %}
 | 
			
		||||
        {% include 'interactions/cite.html.j2' %}
 | 
			
		||||
      </div>
 | 
			
		||||
      {% include 'tables/query_results.html.j2' %}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<!-- Scroll to top element -->
 | 
			
		||||
{% include 'interactions/scroll_to_top.html.j2' %}
 | 
			
		||||
 | 
			
		||||
<!-- Modals -->
 | 
			
		||||
{% include 'modals/show_metadata.html.j2' %}
 | 
			
		||||
{% include 'modals/show_text_details.html.j2' %}
 | 
			
		||||
{% include 'modals/analysis_init.html.j2' %}
 | 
			
		||||
{% include 'modals/export_query_results.html.j2' %}
 | 
			
		||||
{% include 'modals/context_modal.html.j2' %}
 | 
			
		||||
 | 
			
		||||
<!-- import modules -->
 | 
			
		||||
<script type="module">
 | 
			
		||||
/**
 | 
			
		||||
 * First Phase:
 | 
			
		||||
 * Document content is loaded and scripts are being imported and executed.
 | 
			
		||||
 */
 | 
			
		||||
import {
 | 
			
		||||
  CorpusAnalysisClient,
 | 
			
		||||
  CorpusAnalysisDisplay,
 | 
			
		||||
  SocketEventListener,
 | 
			
		||||
  ListenerCallback,
 | 
			
		||||
} from '../../static/js/modules/nopaque.CorpusAnalysisClient.js';
 | 
			
		||||
import {
 | 
			
		||||
  recieveSession,
 | 
			
		||||
  recieveQueryStatus,
 | 
			
		||||
  recieveQueryData,
 | 
			
		||||
} from '../../static/js/modules/nopaque.listenerFunctions.js';
 | 
			
		||||
import {
 | 
			
		||||
  querySetup,
 | 
			
		||||
  queryRenderResults,
 | 
			
		||||
} from '../../static/js/modules/nopaque.listenerCallbacks.js'
 | 
			
		||||
import {
 | 
			
		||||
  Results,
 | 
			
		||||
  Data,
 | 
			
		||||
  MetaData,
 | 
			
		||||
} from '../../static/js/nopaque.Results.js';
 | 
			
		||||
import {
 | 
			
		||||
  ResultsList,
 | 
			
		||||
} from '../../static/js/nopaque.lists.js';
 | 
			
		||||
import {
 | 
			
		||||
  scrollToTop,
 | 
			
		||||
} from '../../static/js/modules/nopaque.scrollToTop.js';
 | 
			
		||||
import {
 | 
			
		||||
  InteractionElement,
 | 
			
		||||
  InteractionElements,
 | 
			
		||||
} from '../../static/js/modules/nopaque.InteractionElement.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Second Phase:
 | 
			
		||||
 * Asynchronus and event driven code
 | 
			
		||||
 */
 | 
			
		||||
document.addEventListener("DOMContentLoaded", () => {
 | 
			
		||||
  // Initialize the CorpusAnalysisClient dynamic mode
 | 
			
		||||
  let corpusId = {{ corpus_id}}
 | 
			
		||||
  const client = new CorpusAnalysisClient({'corpusId': corpusId,
 | 
			
		||||
                                           'socket': nopaque.socket,
 | 
			
		||||
                                           'logging': true,
 | 
			
		||||
                                           'dynamicMode': true});
 | 
			
		||||
  console.info("CorpusAnalysisClient created as client:", client);
 | 
			
		||||
  // Initialize modals which are shown depending on events or client status
 | 
			
		||||
  const initLoadingElement = document.getElementById("init-display");
 | 
			
		||||
  const initLoadingModal = M.Modal.init(initLoadingElement,
 | 
			
		||||
                                        {"dismissible": false});
 | 
			
		||||
  // Set up display elements which are shown depending on the client status
 | 
			
		||||
  const initLoadingDisplay = new CorpusAnalysisDisplay(initLoadingModal);
 | 
			
		||||
  client.getHTMLElements(['#query-display']);
 | 
			
		||||
  const queryDisplay = new CorpusAnalysisDisplay(client.queryDisplay);
 | 
			
		||||
  // Register those display elements to client
 | 
			
		||||
  client.setDisplay("init", initLoadingDisplay);
 | 
			
		||||
  client.setDisplay("query", queryDisplay);
 | 
			
		||||
  /**
 | 
			
		||||
   * Initializing the results object holding all the data of a query.
 | 
			
		||||
   * Also holds the metadata of one query.
 | 
			
		||||
   * Lastly it contains the object ResultsList which is a list.js
 | 
			
		||||
   * subclass which handles the visual representation of the query data.
 | 
			
		||||
   */
 | 
			
		||||
  let displayOptionsData = ResultsList.getDisplayOptions('display-options-form');
 | 
			
		||||
  ResultsList.options.page = displayOptionsData["resultsPerPage"];
 | 
			
		||||
  let data = new Data();
 | 
			
		||||
  let resultsList = new ResultsList("result-list", ResultsList.options);
 | 
			
		||||
  let resultsMetaData = new MetaData();
 | 
			
		||||
  let results = new Results(data, resultsList, resultsMetaData);
 | 
			
		||||
  // Make results part of the client
 | 
			
		||||
  client.results = results;
 | 
			
		||||
  console.info('Initialized the Results object.')
 | 
			
		||||
  /**
 | 
			
		||||
   * Initialization of interactionElemnts
 | 
			
		||||
   * An interactionElement is an object identifing a switch or button via
 | 
			
		||||
   * htmlID. Callbacks are set for these elements which will be triggered on
 | 
			
		||||
   * a pagination interaction by the user or if the status of the element has
 | 
			
		||||
   * been altered. (Like the switche has ben turned on or off).
 | 
			
		||||
   */
 | 
			
		||||
  let interactionElements = new InteractionElements();
 | 
			
		||||
  const expertModeInteraction = new InteractionElement("display-options-form-expert_mode");
 | 
			
		||||
  expertModeInteraction.setCallback('on',
 | 
			
		||||
                                  results.jsList.expertModeOn,
 | 
			
		||||
                                  results.jsList,
 | 
			
		||||
                                  ['query-display', client]);
 | 
			
		||||
  expertModeInteraction.setCallback('off',
 | 
			
		||||
                                    results.jsList.expertModeOff,
 | 
			
		||||
                                    results.jsList,
 | 
			
		||||
                                    ['query-display', client]);
 | 
			
		||||
  const subResultsInteraction = new InteractionElement("add-to-sub-results");
 | 
			
		||||
  subResultsInteraction.setCallback('on',
 | 
			
		||||
                                     results.jsList.activateAddToSubResults,
 | 
			
		||||
                                     results.jsList);
 | 
			
		||||
  subResultsInteraction.setCallback('off',
 | 
			
		||||
                                     results.jsList.deactivateAddToSubResults,
 | 
			
		||||
                                     results.jsList);
 | 
			
		||||
 | 
			
		||||
  const activateInspectInteraction = new InteractionElement('inspect',
 | 
			
		||||
                                                            false);
 | 
			
		||||
  activateInspectInteraction.setCallback('noCheck',
 | 
			
		||||
                                         results.jsList.activateInspect,
 | 
			
		||||
                                         results.jsList);
 | 
			
		||||
  const changeContextInteraction = new InteractionElement('display-options-form-results_per_page',
 | 
			
		||||
                                                          false);
 | 
			
		||||
  changeContextInteraction.setCallback('noCheck',
 | 
			
		||||
                                       results.jsList.changeContext,
 | 
			
		||||
                                       results.jsList)
 | 
			
		||||
  interactionElements.addInteractions([expertModeInteraction,
 | 
			
		||||
                                       subResultsInteraction,
 | 
			
		||||
                                       activateInspectInteraction,
 | 
			
		||||
                                       changeContextInteraction]);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
  * Checks if a change for every interactionElement happens and executes
 | 
			
		||||
  * the callbacks accordingly.
 | 
			
		||||
  */
 | 
			
		||||
  interactionElements.onChangeExecute();
 | 
			
		||||
  /**
 | 
			
		||||
   * Register listeners listening to socket.io events and their callbacks
 | 
			
		||||
   * Afterwards load them.
 | 
			
		||||
   */
 | 
			
		||||
  const listenForSession = new SocketEventListener('corpus_analysis_init',
 | 
			
		||||
                                                  recieveSession);
 | 
			
		||||
  const listenForQueryStatus = new SocketEventListener('corpus_analysis_query',
 | 
			
		||||
                                                       recieveQueryStatus);
 | 
			
		||||
  const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
 | 
			
		||||
                                                   querySetup);
 | 
			
		||||
  listenForQueryStatus.setCallbacks([queryStatusCallback]);
 | 
			
		||||
  const listenForQueryData = new SocketEventListener('corpus_analysis_query_results',
 | 
			
		||||
                                                  recieveQueryData);
 | 
			
		||||
  const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
 | 
			
		||||
                                                 queryRenderResults);
 | 
			
		||||
  listenForQueryData.setCallbacks([queryDataCallback]);
 | 
			
		||||
  client.setSocketEventListeners([listenForSession, listenForQueryStatus,
 | 
			
		||||
                                  listenForQueryData]);
 | 
			
		||||
  client.loadSocketEventListeners();
 | 
			
		||||
  // Session initialization
 | 
			
		||||
  client.requestSession();
 | 
			
		||||
  // Send a query and recieve its answer data
 | 
			
		||||
  let queryFormElement = document.getElementById("query-form");
 | 
			
		||||
  queryFormElement.addEventListener("submit", (event) => {
 | 
			
		||||
    try {
 | 
			
		||||
      /**
 | 
			
		||||
       * Selects first page of result list if pagination is already available
 | 
			
		||||
       * from an query submitted before.
 | 
			
		||||
       * This avoids confusion for the user e.g.: The user was on page 24
 | 
			
		||||
       * reviewing the results and issues a new query. He would not see any
 | 
			
		||||
       * results until the new results reach page 24 or he clicks on another
 | 
			
		||||
       * valid result page element from the new pagination.
 | 
			
		||||
       */
 | 
			
		||||
      let firstPageElement = document.querySelector('a.page');
 | 
			
		||||
      firstPageElement.click();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      // No page element is present if first query is submitted.
 | 
			
		||||
    }
 | 
			
		||||
    // Prevent page from reloading on submit
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
    // Get query string and send query to server
 | 
			
		||||
    results.data.getQueryStr(queryFormElement);
 | 
			
		||||
    client.requestQueryData(results.data.query);
 | 
			
		||||
 | 
			
		||||
    // Add scrollToTop functionality
 | 
			
		||||
    scrollToTop();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user