mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-03 20:02:47 +00:00 
			
		
		
		
	New analysis interface
This commit is contained in:
		@@ -57,7 +57,8 @@ def corpus_analysis_get_meta_data(corpus_id):
 | 
			
		||||
            texts_metadata[text_id][struct_attr.attrs['name'][(len(text_attr.attrs['name']) + 1):]] = struct_attr.values_by_ids(list(range(struct_attr.attrs['size'])))[text_id]
 | 
			
		||||
    metadata['corpus_all_texts'] = texts_metadata
 | 
			
		||||
    metadata['corpus_analysis_date'] = datetime.utcnow().isoformat()
 | 
			
		||||
    metadata['corpus_cqi_py_version'] = cqi.version
 | 
			
		||||
    metadata['corpus_cqi_py_protocol_version'] = client.api.version
 | 
			
		||||
    metadata['corpus_cqi_py_package_version'] = cqi.__version__
 | 
			
		||||
    metadata['corpus_cqpserver_version'] = 'CQPserver v3.4.22'  # TODO: make this dynamically
 | 
			
		||||
 | 
			
		||||
    # write some metadata to the db
 | 
			
		||||
@@ -127,7 +128,6 @@ def corpus_analysis_query(query):
 | 
			
		||||
@socketio.on('corpus_analysis_inspect_match')
 | 
			
		||||
@socketio_login_required
 | 
			
		||||
def corpus_analysis_inspect_match(payload):
 | 
			
		||||
    payload = payload["payload"]
 | 
			
		||||
    client = corpus_analysis_clients.get(request.sid)
 | 
			
		||||
    if client is None:
 | 
			
		||||
        response = {'code': 424, 'desc': 'No client found for this session',
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ class AddCorpusForm(FlaskForm):
 | 
			
		||||
class QueryForm(FlaskForm):
 | 
			
		||||
    query = StringField('Query',
 | 
			
		||||
                        validators=[DataRequired(), Length(1, 1024)])
 | 
			
		||||
    submit = SubmitField('Send query')
 | 
			
		||||
    submit = SubmitField('Search')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DisplayOptionsForm(FlaskForm):
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								web/app/static/js/nopaque.InteractionElement.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								web/app/static/js/nopaque.InteractionElement.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
class InteractionElement {
 | 
			
		||||
  constructor(htmlId="",
 | 
			
		||||
              disabledBefore=true,
 | 
			
		||||
              disabledAfter=false,
 | 
			
		||||
              hideBefore=true,
 | 
			
		||||
              hideAfter=false) {
 | 
			
		||||
  this.htmlId = htmlId;
 | 
			
		||||
  this.callbacks = {};
 | 
			
		||||
  this.disabledBefore = disabledBefore;
 | 
			
		||||
  this.disabledAfter = disabledAfter;
 | 
			
		||||
  this.hideBefore = hideBefore;
 | 
			
		||||
  this.hideAfter = hideAfter;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getElement() {
 | 
			
		||||
    this.interactionStatusElement = document.getElementById(this.htmlId);
 | 
			
		||||
    return this.interactionStatusElement
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setCallback(trigger, callback, bindThis, args=[]) {
 | 
			
		||||
    this.callbacks[trigger] = {
 | 
			
		||||
                                "function": callback,
 | 
			
		||||
                                "bindThis": bindThis,
 | 
			
		||||
                                "args": args
 | 
			
		||||
                              };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bindThisToCallback(trigger) {
 | 
			
		||||
    let callback = this.callbacks[trigger];
 | 
			
		||||
    let boundedCallback = callback["function"].bind(callback.bindThis);
 | 
			
		||||
    return boundedCallback;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -7,6 +7,7 @@ function querySetup(payload) {
 | 
			
		||||
  // This is called when a query was successfull
 | 
			
		||||
  // some hiding and resetting
 | 
			
		||||
  queryResultsExportElement.classList.add("disabled");
 | 
			
		||||
  addToSubSubcorpusElement.setAttribute("disabled", "");
 | 
			
		||||
  queryResultsDeterminateElement.style.width = "0%";
 | 
			
		||||
  queryResultsProgressElement.classList.remove("hide");
 | 
			
		||||
  queryResultsUserFeedbackElement.classList.remove("hide");
 | 
			
		||||
@@ -14,6 +15,7 @@ function querySetup(payload) {
 | 
			
		||||
  receivedMatchCountElement.innerText = "0";
 | 
			
		||||
  textLookupCountElement.innerText = "0";
 | 
			
		||||
  matchCountElement.innerText = payload.match_count;
 | 
			
		||||
  textTitlesElement.innterText = "";
 | 
			
		||||
  // always re initializes results to delete old results from it
 | 
			
		||||
  // this has to be done here again because the last chunk from old results was still being recieved
 | 
			
		||||
  results.clearAll()
 | 
			
		||||
@@ -53,6 +55,11 @@ function queryRenderResults(payload) {
 | 
			
		||||
  // show user current and total match count
 | 
			
		||||
  receivedMatchCountElement.innerText = `${results.data.matches.length}`;
 | 
			
		||||
  textLookupCountElement.innerText = `${Object.keys(results.data.text_lookup).length}`;
 | 
			
		||||
  let titles = new Array();
 | 
			
		||||
  for (let [key, value] of Object.entries(results.data.text_lookup)) {
 | 
			
		||||
    titles.push(`${value.title} (${value.publishing_year})`);
 | 
			
		||||
  };
 | 
			
		||||
  textTitlesElement.innerText = `${titles.join(", ")}`;
 | 
			
		||||
  console.log("Results recieved:", results.data);
 | 
			
		||||
  // upate progress status
 | 
			
		||||
  progress = payload.progress;  // global declaration
 | 
			
		||||
@@ -60,10 +67,14 @@ function queryRenderResults(payload) {
 | 
			
		||||
    queryResultsProgressElement.classList.add("hide");
 | 
			
		||||
    queryResultsUserFeedbackElement.classList.add("hide");
 | 
			
		||||
    queryResultsExportElement.classList.remove("disabled");
 | 
			
		||||
    addToSubSubcorpusElement.removeAttribute("disabled");
 | 
			
		||||
    results.jsList.activateInspect();
 | 
			
		||||
  }
 | 
			
		||||
  // inital expert mode check and activation
 | 
			
		||||
  if (expertModeSwitchElement.checked) {
 | 
			
		||||
    results.jsList.expertModeOn("query-display");
 | 
			
		||||
    // inital expert mode check and sub subcorpus activation
 | 
			
		||||
    if (addToSubSubcorpusElement.checked) {
 | 
			
		||||
      results.jsList.activateAddToSubSubcorpus();
 | 
			
		||||
    }
 | 
			
		||||
    if (expertModeSwitchElement.checked) {
 | 
			
		||||
      results.jsList.expertModeOn("query-display");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -134,8 +134,27 @@ class ResultsList extends List {
 | 
			
		||||
  this.currentExpertTokenElements = {}; // all token elements which have added
 | 
			
		||||
  // classes like chip and hoverable for expert view. Collected
 | 
			
		||||
  //here to delete later on
 | 
			
		||||
  this.addToSubSubcorpuStatus = {};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // handels interactionElements during a pagination navigation
 | 
			
		||||
  pageChangeEventInteractionHandler(interactionElements) {
 | 
			
		||||
    // get elements to check thier status
 | 
			
		||||
    for (let interaction of interactionElements) {
 | 
			
		||||
      let element = interaction.getElement();
 | 
			
		||||
      if (element.checked) {
 | 
			
		||||
        let f_on = interaction.bindThisToCallback("on");
 | 
			
		||||
        let args_on = interaction.callbacks.on.args;
 | 
			
		||||
        f_on(...args_on);
 | 
			
		||||
        console.log("ON TRIGGERED");
 | 
			
		||||
      } else {
 | 
			
		||||
        let f_off = interaction.bindThisToCallback("off");
 | 
			
		||||
        let args_off = interaction.callbacks.off.args;
 | 
			
		||||
        f_off(...args_off);
 | 
			
		||||
        console.log("OFF TRIGGERED");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // get display options from display options form element
 | 
			
		||||
  static getDisplayOptions(displayOptionsFormElement) {
 | 
			
		||||
@@ -152,6 +171,40 @@ class ResultsList extends List {
 | 
			
		||||
    return displayOptionsData
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // ###### Functions to add one match to a sub-subcorpus ######
 | 
			
		||||
  // activate add button
 | 
			
		||||
  activateAddToSubSubcorpus() {
 | 
			
		||||
    if (progress === 100) {
 | 
			
		||||
      let addToSubSubcorpusBtnElements = document.getElementsByClassName("add");
 | 
			
		||||
      for (let addToSubSubcorpusBtn of addToSubSubcorpusBtnElements) {
 | 
			
		||||
        addToSubSubcorpusBtn.classList.remove("hide");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // deactivate add button
 | 
			
		||||
  deactivateAddToSubSubcorpus() {
 | 
			
		||||
    let addToSubSubcorpusBtnElements = document.getElementsByClassName("add");
 | 
			
		||||
    for (let addToSubSubcorpusBtn of addToSubSubcorpusBtnElements) {
 | 
			
		||||
      addToSubSubcorpusBtn.classList.add("hide");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // add match on click to a SubSubcorpus
 | 
			
		||||
  addToSubSubcorpus(dataIndex) {
 | 
			
		||||
    if (!this.addToSubSubcorpuStatus[dataIndex]
 | 
			
		||||
        || this.addToSubSubcorpuStatus === undefined) {
 | 
			
		||||
      event.target.classList.remove("grey");
 | 
			
		||||
      event.target.classList.add("green");
 | 
			
		||||
      event.target.innerText = "check";
 | 
			
		||||
      this.addToSubSubcorpuStatus[dataIndex] = true;
 | 
			
		||||
      console.log(dataIndex);
 | 
			
		||||
    } else if (this.addToSubSubcorpuStatus[dataIndex]) {
 | 
			
		||||
      event.target.classList.remove("green");
 | 
			
		||||
      event.target.classList.add("grey");
 | 
			
		||||
      event.target.innerText = "add";
 | 
			
		||||
      this.addToSubSubcorpuStatus[dataIndex] = false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // ###### Functions to inspect one match, to show more details ######
 | 
			
		||||
  // activate inspect buttons if progress is 100
 | 
			
		||||
  activateInspect() {
 | 
			
		||||
@@ -167,22 +220,21 @@ class ResultsList extends List {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //gets result cpos infos for one dataIndex to send back to the server
 | 
			
		||||
  inspect(dataIndex) {
 | 
			
		||||
  inspect(dataIndex, type) {
 | 
			
		||||
    this.contextId = dataIndex;
 | 
			
		||||
    let contextResultsElement;
 | 
			
		||||
    contextResultsElement = document.getElementById("context-results");
 | 
			
		||||
    contextResultsElement.innerHTML = "";  // clear it from old inspects
 | 
			
		||||
    contextModal.open();
 | 
			
		||||
    nopaque.socket.emit("corpus_analysis_inspect_match",
 | 
			
		||||
            {
 | 
			
		||||
              payload: {
 | 
			
		||||
                      {"type": type,
 | 
			
		||||
                       first_cpos: results.data.matches[dataIndex].c[0],
 | 
			
		||||
                       last_cpos: results.data.matches[dataIndex].c[1],
 | 
			
		||||
                      }
 | 
			
		||||
            }
 | 
			
		||||
          );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 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");
 | 
			
		||||
@@ -432,20 +484,6 @@ class ResultsList extends List {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // ###### Expert view event functions ######
 | 
			
		||||
 | 
			
		||||
  // Event function to check if pagination is used and then look if
 | 
			
		||||
  // expertModeSwitchElement is checked
 | 
			
		||||
  // if checked than expertModeOn is executed
 | 
			
		||||
  // if unchecked expertModeOff is executed
 | 
			
		||||
  eventHandlerCheck(event) {
 | 
			
		||||
    if (expertModeSwitchElement.checked) {
 | 
			
		||||
      this.expertModeOn("query-display");
 | 
			
		||||
    } else if (!expertModeSwitchElement.checked) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      this.expertModeOff("query-display");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // function to create a tooltip for the current hovered token
 | 
			
		||||
  tooltipEventCreate(event) {
 | 
			
		||||
    // console.log("Create Tooltip on mouseover.");
 | 
			
		||||
@@ -465,8 +503,12 @@ class ResultsList extends List {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expertModeOn(htmlId) {
 | 
			
		||||
    // torn the expert mode on for all tokens in the DOM element identified by its htmlID
 | 
			
		||||
    this.currentExpertTokenElements[htmlId] = document.getElementById(htmlId).getElementsByClassName("token");
 | 
			
		||||
    // turn the expert mode on for all tokens in the DOM element identified by its htmlID
 | 
			
		||||
    console.log(this);
 | 
			
		||||
    if (!Array.isArray(this.currentExpertTokenElements[htmlId])) {
 | 
			
		||||
      this.currentExpertTokenElements[htmlId] = [];
 | 
			
		||||
    }
 | 
			
		||||
    this.currentExpertTokenElements[htmlId].push( ...document.getElementById(htmlId).getElementsByClassName("token"));
 | 
			
		||||
    this.tooltipEventCreateBind = this.tooltipEventCreate.bind(this);
 | 
			
		||||
    this.tooltipEventDestroyBind = this.tooltipEventDestroy.bind(this);
 | 
			
		||||
    this.eventTokens[htmlId] = [];
 | 
			
		||||
@@ -511,6 +553,13 @@ class ResultsList extends List {
 | 
			
		||||
  // function to remove extra informations and animations from tokens
 | 
			
		||||
  expertModeOff(htmlId) {
 | 
			
		||||
    // console.log("Expert mode is off.");
 | 
			
		||||
    console.log(this);
 | 
			
		||||
    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");
 | 
			
		||||
    }
 | 
			
		||||
@@ -524,6 +573,7 @@ class ResultsList extends List {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createResultRowElement(item, chunk) {
 | 
			
		||||
    let addToSubSubcorpusBtn;
 | 
			
		||||
    let c;
 | 
			
		||||
    let cCellElement;
 | 
			
		||||
    let cpos;
 | 
			
		||||
@@ -579,16 +629,29 @@ class ResultsList extends List {
 | 
			
		||||
        `<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 button to trigger more context to every match td
 | 
			
		||||
      inspectBtn = document.createElement("a");
 | 
			
		||||
      inspectBtn.setAttribute("class", `btn-floating btn-flat waves-effect` +
 | 
			
		||||
                                       `waves-light grey right inspect disabled`
 | 
			
		||||
                              );
 | 
			
		||||
      inspectBtn.innerHTML = '<i class="material-icons">search</i>';
 | 
			
		||||
      inspectBtn.onclick = () => {this.inspect(values.index)};
 | 
			
		||||
    }
 | 
			
		||||
    // add text titles at front as first td of one row
 | 
			
		||||
    // add some interaction buttons
 | 
			
		||||
    // # some btn css rules and classes
 | 
			
		||||
    let css = `margin-right: 10px;`
 | 
			
		||||
    let classes = `btn-floating btn-flat waves-effect` +
 | 
			
		||||
                  `waves-light grey right`
 | 
			
		||||
    // # add button to trigger more context to every match td
 | 
			
		||||
    inspectBtn = document.createElement("a");
 | 
			
		||||
    inspectBtn.setAttribute("class", classes + ` disabled inspect`
 | 
			
		||||
                            );
 | 
			
		||||
    inspectBtn.setAttribute("style", css)
 | 
			
		||||
    inspectBtn.innerHTML = '<i class="material-icons">search</i>';
 | 
			
		||||
    inspectBtn.onclick = () => {this.inspect(values.index, "inspect")};
 | 
			
		||||
    // # add btn to add matches to sub-subcorpus. hidden per default
 | 
			
		||||
    addToSubSubcorpusBtn = document.createElement("a");
 | 
			
		||||
    addToSubSubcorpusBtn.setAttribute("class", classes + ` hide add`
 | 
			
		||||
                                );
 | 
			
		||||
    addToSubSubcorpusBtn.setAttribute("style", css)
 | 
			
		||||
    addToSubSubcorpusBtn.innerHTML = '<i class="material-icons">add</i>';
 | 
			
		||||
    addToSubSubcorpusBtn.onclick= (event) => {this.addToSubSubcorpus(values.index)}
 | 
			
		||||
    cCellElement.appendChild(inspectBtn);
 | 
			
		||||
    cCellElement.appendChild(addToSubSubcorpusBtn);
 | 
			
		||||
    // add text titles at front as first td of one row
 | 
			
		||||
    textTitlesCellElement.innerText = [...textTitles].join(", ");
 | 
			
		||||
    matchRowElement.insertAdjacentHTML("afterbegin", textTitlesCellElement.outerHTML);
 | 
			
		||||
    matchNrElement.innerText = values.index + 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,114 +1,118 @@
 | 
			
		||||
{% extends "nopaque.html.j2" %}
 | 
			
		||||
 | 
			
		||||
{% set headline = ' ' %}
 | 
			
		||||
 | 
			
		||||
{% set full_width = True %}
 | 
			
		||||
 | 
			
		||||
{% block page_content %}
 | 
			
		||||
<div class="col s12">
 | 
			
		||||
  <ul class="collapsible expandable">
 | 
			
		||||
    <li class="active">
 | 
			
		||||
      <!-- <div class="collapsible-header">
 | 
			
		||||
        <i class="material-icons">search</i>CQP Query
 | 
			
		||||
      </div> -->
 | 
			
		||||
      <!-- Div element above is part of valid materialize collapsible.
 | 
			
		||||
      Commented out to prevent the user from collapsing it and also to save
 | 
			
		||||
      space -->
 | 
			
		||||
      <div class="collapsible-body" style="padding-top: 10px;
 | 
			
		||||
                                           padding-right: 2rem;
 | 
			
		||||
                                           padding-bottom: 0px;
 | 
			
		||||
                                           padding-left: 2rem;">
 | 
			
		||||
        <!-- Query form -->
 | 
			
		||||
        <form id="query-form">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <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">
 | 
			
		||||
              <br class="hide-on-small-only">
 | 
			
		||||
              {{ M.render_field(query_form.submit, material_icon='send') }}
 | 
			
		||||
  <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>
 | 
			
		||||
        </form>
 | 
			
		||||
      </div>
 | 
			
		||||
    </li>
 | 
			
		||||
    <li class="hoverable">
 | 
			
		||||
      <div class="collapsible-header">
 | 
			
		||||
        <i class="material-icons">settings</i>Display Options
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="collapsible-body">
 | 
			
		||||
        <!-- Display options form -->
 | 
			
		||||
        <form id="display-options-form">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col s12 m6">
 | 
			
		||||
              {{ M.render_field(display_options_form.results_per_page,
 | 
			
		||||
                                material_icon='format_list_numbered') }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col s12 m6">
 | 
			
		||||
              {{ M.render_field(display_options_form.result_context,
 | 
			
		||||
                                material_icon='short_text') }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col s12">
 | 
			
		||||
              {{ M.render_field(display_options_form.expert_mode) }}
 | 
			
		||||
            </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>
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
      </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;">
 | 
			
		||||
      <span class="card-title">Query Results</span>
 | 
			
		||||
      <div class="error-container hide show-on-error"></div>
 | 
			
		||||
      <div class="hide show-on-success">
 | 
			
		||||
        <div class="col s12 m6 l6">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <p>
 | 
			
		||||
              <span id="received-match-count">
 | 
			
		||||
              </span> of
 | 
			
		||||
              <span id="match-count"></span>
 | 
			
		||||
              matches loaded.
 | 
			
		||||
              <br>
 | 
			
		||||
              Matches occured in
 | 
			
		||||
              <span id="text-lookup-count"></span>
 | 
			
		||||
              corpus files.
 | 
			
		||||
            </p>
 | 
			
		||||
            <p id="query-results-user-feedback">
 | 
			
		||||
              <i class="material-icons">help</i>
 | 
			
		||||
              The Server is still sending your results.
 | 
			
		||||
              Functions like "Export Results" and "Match Inspect" will be
 | 
			
		||||
              available after all matches have been loaded.
 | 
			
		||||
            </p>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="progress" id="query-results-progress">
 | 
			
		||||
              <div class="determinate" id="query-results-determinate"></div>
 | 
			
		||||
      <div class="hide show-on-success" style="margin-top:-20px;">
 | 
			
		||||
        <div class="row" style="margin-bottom: 0px;">
 | 
			
		||||
          <div class="col s12 m3 l3" id="results-info">
 | 
			
		||||
            <div class="row section">
 | 
			
		||||
              <h6 style="margin-top: 0px;">Infos</h6>
 | 
			
		||||
              <div class="divider" style="margin-bottom: 10px;"></div>
 | 
			
		||||
              <div class="col" id="infos">
 | 
			
		||||
                <p>
 | 
			
		||||
                  <span id="received-match-count">
 | 
			
		||||
                  </span> of
 | 
			
		||||
                  <span id="match-count"></span>
 | 
			
		||||
                  matches loaded.
 | 
			
		||||
                  <br>
 | 
			
		||||
                  Matches occured in
 | 
			
		||||
                  <span id="text-lookup-count"></span>
 | 
			
		||||
                  corpus files:
 | 
			
		||||
                  <br>
 | 
			
		||||
                  <span id=text-titles></span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <p id="query-results-user-feedback">
 | 
			
		||||
                  <i class="material-icons">help</i>
 | 
			
		||||
                  The Server is still sending your results.
 | 
			
		||||
                  Functions like "Export Results" and "Match Inspect" will be
 | 
			
		||||
                  available after all matches have been loaded.
 | 
			
		||||
                </p>
 | 
			
		||||
                <div class="progress" id="query-results-progress">
 | 
			
		||||
                  <div class="determinate" id="query-results-determinate"></div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col s12 m6 l6">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <button id="query-results-export"
 | 
			
		||||
                    class="waves-effect
 | 
			
		||||
                           waves-light
 | 
			
		||||
                           btn-small
 | 
			
		||||
                           right disabled"
 | 
			
		||||
                    type="submit">Export Results
 | 
			
		||||
                    <i class="material-icons right">file_download</i>
 | 
			
		||||
            </button>
 | 
			
		||||
          <div class="col s12 m9 l9" id="actions-and-tools">
 | 
			
		||||
            <div class="row section">
 | 
			
		||||
              <div class="col" id="Export">
 | 
			
		||||
                <h6 style="margin-top: 0px;">Export</h6>
 | 
			
		||||
                <div class="divider" style="margin-bottom: 10px;"></div>
 | 
			
		||||
                <button id="query-results-export"
 | 
			
		||||
                        class="waves-effect
 | 
			
		||||
                        waves-light
 | 
			
		||||
                        btn-flat
 | 
			
		||||
                        disabled"
 | 
			
		||||
                        type="submit">Export Results
 | 
			
		||||
                  <i class="material-icons left">file_download</i>
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col" id="Create">
 | 
			
		||||
                <h6 style="margin-top: 0px;">Create</h6>
 | 
			
		||||
                <div class="divider" style="margin-bottom: 10px;"></div>
 | 
			
		||||
                <div class="switch">
 | 
			
		||||
                  Sub-Subcorpus creation:
 | 
			
		||||
                  <label>
 | 
			
		||||
                    Off
 | 
			
		||||
                    <input disabled
 | 
			
		||||
                           type="checkbox"
 | 
			
		||||
                           id="add-to-sub-subcorpus">
 | 
			
		||||
                    <span class="lever"></span>
 | 
			
		||||
                    On
 | 
			
		||||
                  </label>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col" id="Display">
 | 
			
		||||
                <h6 style="margin-top: 0px;">Display</h6>
 | 
			
		||||
                <div class="divider" style="margin-bottom: 10px;"></div>
 | 
			
		||||
                <form id="display-options-form">
 | 
			
		||||
                  {{ M.render_field(display_options_form.results_per_page,
 | 
			
		||||
                                    material_icon='format_list_numbered') }}
 | 
			
		||||
                  {{ M.render_field(display_options_form.result_context,
 | 
			
		||||
                                    material_icon='short_text') }}
 | 
			
		||||
                  {{ M.render_field(display_options_form.expert_mode) }}
 | 
			
		||||
                </form>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <!-- Table showing the query results -->
 | 
			
		||||
@@ -275,11 +279,15 @@
 | 
			
		||||
</script>
 | 
			
		||||
<script src="{{ url_for('static', filename='js/nopaque.callbacks.js') }}">
 | 
			
		||||
</script>
 | 
			
		||||
<script src="{{ url_for('static', filename='js/nopaque.InteractionElement.js') }}">
 | 
			
		||||
</script>
 | 
			
		||||
<script>
 | 
			
		||||
// ###### Defining global variables used in other functions ######
 | 
			
		||||
  var addToSubSubcorpusElement; // Button to start adding matches to sub-subcorpus
 | 
			
		||||
  var client;  // CorpusAnalysisClient first undefined on DOMContentLoaded defined
 | 
			
		||||
  var collapsibleElements;  // All collapsibleElements on this page
 | 
			
		||||
  var contextModal;  // Modal to open on inspect for further match context
 | 
			
		||||
  var data;  // full JSON object holding match results
 | 
			
		||||
  var expertModeSwitchElement; // Expert mode switch Element
 | 
			
		||||
  var initDisplay;  // CorpusAnalysisDisplay object first undfined on DOMContentLoaded defined
 | 
			
		||||
  var matchCountElement;  // Total nr. of matches will be displayed in this element
 | 
			
		||||
@@ -292,10 +300,11 @@
 | 
			
		||||
  var queryResultsUserFeedbackElement;  // Element showing match count|total etc
 | 
			
		||||
  var receivedMatchCountElement;  // Nr. of loaded matches will be displayed in this element
 | 
			
		||||
  var results;  // results object
 | 
			
		||||
  var data;  // full JSON object holding match results
 | 
			
		||||
  var resultsList;  // resultsList object
 | 
			
		||||
  var resultsListOptions;  // specifies ResultsList options
 | 
			
		||||
  var textLookupCountElement  // Nr of texts the matches occured in will be shown in this element
 | 
			
		||||
  var interactionElements;  // Interaction elements and their parameters
 | 
			
		||||
  var textTitlesElement;  // matched text titles
 | 
			
		||||
 | 
			
		||||
  // ###### Defining local scope variables ######
 | 
			
		||||
  let contextPerItemElement;  // Form Element for display option
 | 
			
		||||
@@ -315,12 +324,15 @@
 | 
			
		||||
 | 
			
		||||
  // ###### Initialize variables ######
 | 
			
		||||
  client = undefined;
 | 
			
		||||
  addToSubSubcorpusElement = document.getElementById("add-to-sub-subcorpus");
 | 
			
		||||
  collapsibleElements = document.querySelector('.collapsible.expandable');
 | 
			
		||||
  contextModal = document.getElementById("context-modal");
 | 
			
		||||
  contextPerItemElement = document.getElementById("display-options-form-result_context");
 | 
			
		||||
  contextSentencesElement = document.getElementById("context-sentences");
 | 
			
		||||
  displayOptionsFormElement = document.getElementById("display-options-form");
 | 
			
		||||
  expertModeSwitchElement = document.getElementById("display-options-form-expert_mode");
 | 
			
		||||
  exportModal = document.getElementById("query-results-download-modal");
 | 
			
		||||
  hitsPerPageInputElement = document.getElementById("display-options-form-results_per_page");
 | 
			
		||||
  initDisplay = undefined;
 | 
			
		||||
  initDisplayElement = document.getElementById("init-display");
 | 
			
		||||
  matchCountElement = document.getElementById("match-count");
 | 
			
		||||
@@ -334,8 +346,7 @@
 | 
			
		||||
  queryResultsUserFeedbackElement = document.getElementById("query-results-user-feedback");
 | 
			
		||||
  receivedMatchCountElement = document.getElementById("received-match-count");
 | 
			
		||||
  textLookupCountElement = document.getElementById("text-lookup-count");
 | 
			
		||||
  hitsPerPageInputElement = document.getElementById("display-options-form-results_per_page");
 | 
			
		||||
  contextPerItemElement = document.getElementById("display-options-form-result_context");
 | 
			
		||||
  textTitlesElement = document.getElementById("text-titles");
 | 
			
		||||
 | 
			
		||||
  // ###### js list options and intialization ######
 | 
			
		||||
  displayOptionsData = ResultsList.getDisplayOptions(displayOptionsFormElement);
 | 
			
		||||
@@ -430,25 +441,74 @@
 | 
			
		||||
    // live update of lr context per item if context value is changed
 | 
			
		||||
    contextPerItemElement.onchange = results.jsList.changeContext;
 | 
			
		||||
 | 
			
		||||
    // stuff that happens in the list table and should also be checked and
 | 
			
		||||
    // updated if the pagination is used
 | 
			
		||||
 | 
			
		||||
    interactionElements = new Array();
 | 
			
		||||
    let expertModeInteraction = new InteractionElement("display-options-form-expert_mode");
 | 
			
		||||
    expertModeInteraction.setCallback("on",
 | 
			
		||||
                                      results.jsList.expertModeOn,
 | 
			
		||||
                                      results.jsList,
 | 
			
		||||
                                      ["query-display"])
 | 
			
		||||
    expertModeInteraction.setCallback("off",
 | 
			
		||||
                                      results.jsList.expertModeOff,
 | 
			
		||||
                                      results.jsList,
 | 
			
		||||
                                      ["query-display"])
 | 
			
		||||
    let subSubcorpusInteraction = new InteractionElement("add-to-sub-subcorpus");
 | 
			
		||||
    subSubcorpusInteraction.setCallback("on",
 | 
			
		||||
                                        results.jsList.activateAddToSubSubcorpus,
 | 
			
		||||
                                        results.jsList);
 | 
			
		||||
    subSubcorpusInteraction.setCallback("off",
 | 
			
		||||
                                        results.jsList.deactivateAddToSubSubcorpus,
 | 
			
		||||
                                        results.jsList);
 | 
			
		||||
    interactionElements.push(expertModeInteraction, subSubcorpusInteraction);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // eventListener if pagination is used to apply new context size to new page
 | 
			
		||||
    // and also activate inspect match if progress is 100
 | 
			
		||||
    // also adds more interaction buttons like add to subcorpus
 | 
			
		||||
    for (let element of paginationElements) {
 | 
			
		||||
      element.addEventListener("click", results.jsList.changeContext);
 | 
			
		||||
      element.addEventListener("click", results.jsList.activateInspect);
 | 
			
		||||
      element.addEventListener("click", results.jsList.activateAddToSubSubcorpus);
 | 
			
		||||
      element.addEventListener("click", (event) => {
 | 
			
		||||
        results.jsList.pageChangeEventInteractionHandler(interactionElements);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    expertModeSwitchElement.addEventListener("change", (event) => {
 | 
			
		||||
      if (event.target.checked) {
 | 
			
		||||
        results.jsList.expertModeOn("query-display");
 | 
			
		||||
        for (let element of paginationElements) {
 | 
			
		||||
          element.onclick = (event) => {
 | 
			
		||||
            results.jsList.eventHandlerCheck(event)
 | 
			
		||||
          }
 | 
			
		||||
    // checks if a change for every interactionElement happens and executes
 | 
			
		||||
    // the callbacks accordingly
 | 
			
		||||
    for (let interaction of interactionElements) {
 | 
			
		||||
      let element = interaction.getElement()
 | 
			
		||||
      element.addEventListener("change", (event) => {
 | 
			
		||||
        if (event.target.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 {
 | 
			
		||||
        results.jsList.expertModeOff("query-display");
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Show add buttons for sub-subcorpus creation if this is pressed
 | 
			
		||||
    // addToSubSubcorpusElement.addEventListener("change", (event) => {
 | 
			
		||||
    //   if (event.target.checked) {
 | 
			
		||||
    //     results.jsList.activateAddToSubSubcorpus();
 | 
			
		||||
    //   } else {
 | 
			
		||||
    //     results.jsList.deActivateAddToSubSubcorpus();
 | 
			
		||||
    //   }
 | 
			
		||||
    // });
 | 
			
		||||
 | 
			
		||||
    // expertModeSwitchElement.addEventListener("change", (event) => {
 | 
			
		||||
    //   if (event.target.checked) {
 | 
			
		||||
    //     results.jsList.expertModeOn("query-display");
 | 
			
		||||
    //   } else {
 | 
			
		||||
    //     results.jsList.expertModeOff("query-display");
 | 
			
		||||
    //   }
 | 
			
		||||
    // });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // Add onclick to open download modal when Export Results button is pressed
 | 
			
		||||
@@ -461,7 +521,7 @@
 | 
			
		||||
    let filename = results.data.createDownloadFilename("matches");
 | 
			
		||||
    results.data.addData(results.metaData);
 | 
			
		||||
    results.data.downloadJSONRessource(filename, results.data,
 | 
			
		||||
                                              downloadResultsJSONElement
 | 
			
		||||
                                       downloadResultsJSONElement
 | 
			
		||||
    )};
 | 
			
		||||
 | 
			
		||||
  // add onclick to download JSON button and download the file
 | 
			
		||||
 
 | 
			
		||||
@@ -86,9 +86,9 @@
 | 
			
		||||
            <td style="word-break: break-word;">{{ file.title }}</td>
 | 
			
		||||
            <td>{{ file.publishing_year }}</td>
 | 
			
		||||
            <td class="right-align">
 | 
			
		||||
              <a class="btn-small waves-effect waves-light" href="{{ url_for('corpora.edit_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">edit</i></a>
 | 
			
		||||
              <a class="btn-small waves-effect waves-light" href="{{ url_for('corpora.download_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">file_download</i></a>
 | 
			
		||||
              <a data-target="delete-corpus-file-{{ file.id }}-modal" class="btn-small modal-trigger red waves-effect waves-light"><i class="material-icons">delete</i></a>
 | 
			
		||||
              <a class="btn-floating waves-effect waves-light" href="{{ url_for('corpora.edit_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">edit</i></a>
 | 
			
		||||
              <a class="btn-floating waves-effect waves-light" href="{{ url_for('corpora.download_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">file_download</i></a>
 | 
			
		||||
              <a data-target="delete-corpus-file-{{ file.id }}-modal" class="btn-floating modal-trigger red waves-effect waves-light"><i class="material-icons">delete</i></a>
 | 
			
		||||
            </td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user