mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-04 12:22:47 +00:00 
			
		
		
		
	Add logic for data export etc.
This commit is contained in:
		@@ -16,7 +16,7 @@ class Client {
 | 
			
		||||
    this.logging = logging;
 | 
			
		||||
    this.requestQueryProgress = 0;
 | 
			
		||||
    this.socket = socket;
 | 
			
		||||
    this.socketEventListeners = {};
 | 
			
		||||
    this.eventListeners = {};
 | 
			
		||||
    this.connected = false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -44,9 +44,9 @@ class Client {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Registers one or more SocketEventListeners to the Client.
 | 
			
		||||
  setSocketEventListeners(socketEventListeners) {
 | 
			
		||||
    for (let socketEventListener of socketEventListeners) {
 | 
			
		||||
      this.socketEventListeners[socketEventListener.type] = socketEventListener;
 | 
			
		||||
  setSocketEventListeners(eventListeners) {
 | 
			
		||||
    for (let eventListener of eventListeners) {
 | 
			
		||||
      this.eventListeners[eventListener.type] = eventListener;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -55,7 +55,7 @@ class Client {
 | 
			
		||||
   * type strings because they double as the socket event event names.
 | 
			
		||||
   */
 | 
			
		||||
  loadSocketEventListeners() {
 | 
			
		||||
    for (let [type, listener] of Object.entries(this.socketEventListeners)) {
 | 
			
		||||
    for (let [type, listener] of Object.entries(this.eventListeners)) {
 | 
			
		||||
      listener.listenerFunction(type, this);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -66,8 +66,8 @@ class Client {
 | 
			
		||||
   */
 | 
			
		||||
  notifyView(caseIdentifier, detailObject={}) {
 | 
			
		||||
    detailObject.caseIdentifier = caseIdentifier;
 | 
			
		||||
    const event = new CustomEvent('notify', { detail: detailObject });
 | 
			
		||||
    console.info('Dispatching Notification:', caseIdentifier);
 | 
			
		||||
    const event = new CustomEvent('notify-view', { detail: detailObject });
 | 
			
		||||
    console.info('Client dispatching Notification:', caseIdentifier);
 | 
			
		||||
    document.dispatchEvent(event);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -105,16 +105,38 @@ class Client {
 | 
			
		||||
                 'socket.emit for the query', queryStr);
 | 
			
		||||
    this.socket.emit('corpus_analysis_query', queryStr);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // create results data either from all results or from all marked sub results
 | 
			
		||||
  getResultsData(resultsType, dataIndexes, results) {
 | 
			
		||||
    // TODO: where to put all the stuff that deactivates all the buttons because cqp server cannot handle mutliple requests?
 | 
			
		||||
    // Triggers emit to get full match context from server for a number of
 | 
			
		||||
    // matches identified by their data_index.
 | 
			
		||||
    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: resultsType,
 | 
			
		||||
                          data_indexes: dataIndexes,
 | 
			
		||||
                          first_cpos: tmp_first_cpos,
 | 
			
		||||
                          last_cpos: tmp_last_cpos,
 | 
			
		||||
                        });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is used to create an SocketEventListener.
 | 
			
		||||
 * Input are an identifying type string, the listener function and callbacks
 | 
			
		||||
 * which will be executed as part of the listener function. The identifying
 | 
			
		||||
 * type string is also used as the socket event event identifier.
 | 
			
		||||
 */
 | 
			
		||||
class SocketEventListener {
 | 
			
		||||
  constructor(type, listenerFunction, args=null) {
 | 
			
		||||
class ClientEventListener {
 | 
			
		||||
  constructor(type, listenerFunction) {
 | 
			
		||||
    this.listenerCallbacks = {};
 | 
			
		||||
    this.listenerFunction = listenerFunction;
 | 
			
		||||
    this.type = type;
 | 
			
		||||
@@ -127,8 +149,8 @@ class SocketEventListener {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Shorthand to execute all registered callbacks with same args in insertion
 | 
			
		||||
   * order.
 | 
			
		||||
  /** Shorthand to execute all registered callbacks with same defaultArgs
 | 
			
		||||
   * in insertion order.
 | 
			
		||||
   * NOTE:
 | 
			
		||||
   * Since ECMAScript 2015, objects do preserve creation order for
 | 
			
		||||
   * string and Symbol keys. In JavaScript engines that comply with the
 | 
			
		||||
@@ -136,11 +158,18 @@ class SocketEventListener {
 | 
			
		||||
   * yield the keys in order of insertion.
 | 
			
		||||
   * So all modern Browsers.
 | 
			
		||||
   */
 | 
			
		||||
  executeCallbacks(payload) {
 | 
			
		||||
  executeCallbacks(defaultArgs) {
 | 
			
		||||
    for (let [type, listenerCallback] of Object.entries(this.listenerCallbacks)) {
 | 
			
		||||
      listenerCallback.callbackFunction(payload, ...listenerCallback.args);
 | 
			
		||||
      listenerCallback.callbackFunction(...defaultArgs,
 | 
			
		||||
                                        ...listenerCallback.args);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // use this if you only want to execute a specific registered callback
 | 
			
		||||
  executeCallback(defaultArgs, type) {
 | 
			
		||||
    let listenerCallback = this.listenerCallbacks[type];
 | 
			
		||||
    listenerCallback.callbackFunction(...defaultArgs,
 | 
			
		||||
                                      ...listenerCallback.args);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -159,6 +188,6 @@ class ListenerCallback {
 | 
			
		||||
// export Classes from this module
 | 
			
		||||
export {
 | 
			
		||||
  Client,
 | 
			
		||||
  SocketEventListener,
 | 
			
		||||
  ClientEventListener,
 | 
			
		||||
  ListenerCallback,
 | 
			
		||||
};
 | 
			
		||||
@@ -46,116 +46,24 @@ function saveQueryData(args) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function querySetup(payload, client) {
 | 
			
		||||
  // deletes old data from query issued before this new query
 | 
			
		||||
  client.results.clearAll();
 | 
			
		||||
  // load necessary HTMLElements with selectory syntax and save them as fields
 | 
			
		||||
  client.getHTMLElements(['#query-progress-bar', '#query-results-user-feedback',
 | 
			
		||||
                          '#recieved-match-count', '#total-match-count',
 | 
			
		||||
                          '#text-lookup-count', '#text-lookup-titles',
 | 
			
		||||
                          '#query-results-create', '#add-to-sub-results']);
 | 
			
		||||
  client.recievedMatchCount.textContent = 0;
 | 
			
		||||
  client.totalMatchCount.textContent = `${payload.match_count}`;
 | 
			
		||||
  client.queryResultsUserFeedback.classList.toggle('hide');
 | 
			
		||||
  client.queryProgressBar.classList.toggle('hide');
 | 
			
		||||
  client.queryProgressBar.lastElementChild.style.width = '0%';
 | 
			
		||||
  if (client.dynamicMode) {
 | 
			
		||||
    client.addToSubResults.toggleAttribute('disabled');
 | 
			
		||||
    client.queryResultsCreate.classList.toggle('disabled');
 | 
			
		||||
  }
 | 
			
		||||
function getResultsData(args) {
 | 
			
		||||
  let [resultsType, dataIndexes, client, results, rest] = arguments;
 | 
			
		||||
  client.notifyView('results-data-recieving');
 | 
			
		||||
  client.getResultsData(resultsType, dataIndexes, results);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This callback should be registered to the SocketEventListener 'recieveQueryData'
 | 
			
		||||
 * It takes the incoming chunk and renders the results using the
 | 
			
		||||
 * results.jsList object. It can either handle live incoming data chunks or
 | 
			
		||||
 * already loaded/imported results data.
 | 
			
		||||
 */
 | 
			
		||||
function queryRenderResults(payload, client) {
 | 
			
		||||
  client.getHTMLElements(['#recieved-match-count', '#match-count',
 | 
			
		||||
                          '#display-options-form-expert_mode']);
 | 
			
		||||
  const renderResults = (data) => {
 | 
			
		||||
    /**
 | 
			
		||||
     * resultItem saves the incoming chunk matches as objects to add those later
 | 
			
		||||
     * to the client.results.jsList
 | 
			
		||||
     */
 | 
			
		||||
   let resultItems = [];
 | 
			
		||||
   // get infos for full match row
 | 
			
		||||
   for (let [index, match] of data.matches.entries()) {
 | 
			
		||||
     resultItems.push({...match, ...{'index': index + client.results.data.matches.length}});
 | 
			
		||||
   }
 | 
			
		||||
     client.results.jsList.add(resultItems, (items) => {
 | 
			
		||||
       for (let item of items) {
 | 
			
		||||
         item.elm = client.results.jsList.createResultRowElement(item, data);
 | 
			
		||||
       }
 | 
			
		||||
     });
 | 
			
		||||
  }
 | 
			
		||||
  if (client.dynamicMode) {
 | 
			
		||||
    if (payload.chunk.cpos_ranges == true) {
 | 
			
		||||
      client.results.data['cpos_ranges'] = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      client.results.data['cpos_ranges'] = false;
 | 
			
		||||
    }
 | 
			
		||||
    renderResults(payload.chunk);
 | 
			
		||||
    helperQueryRenderResults(payload, client);
 | 
			
		||||
    console.info('Result progress is:', client.requestQueryProgress);
 | 
			
		||||
    if (client.requestQueryProgress === 100) {
 | 
			
		||||
      /**
 | 
			
		||||
       * activate, hide or show elements if all reults have been recieved
 | 
			
		||||
       * also load some new elements taht have not ben loaded before
 | 
			
		||||
       */
 | 
			
		||||
      client.queryProgressBar.classList.toggle('hide');
 | 
			
		||||
      client.queryResultsUserFeedback.classList.toggle('hide');
 | 
			
		||||
      client.queryResultsCreate.classList.toggle('disabled');
 | 
			
		||||
      client.addToSubResults.toggleAttribute('disabled');
 | 
			
		||||
    //   addToSubResultsElement.removeAttribute("disabled");
 | 
			
		||||
    //   // inital expert mode check and sub results activation
 | 
			
		||||
    //   client.results.jsList.activateInspect();
 | 
			
		||||
    //   if (addToSubResultsElement.checked) {
 | 
			
		||||
    //     client.results.jsList.activateAddToSubResults();
 | 
			
		||||
    //   }
 | 
			
		||||
    //   if (expertModeSwitchElement.checked) {
 | 
			
		||||
    //     client.results.jsList.expertModeOn("query-display");
 | 
			
		||||
    //   }
 | 
			
		||||
    }
 | 
			
		||||
  } else if (!client.dynamicMode) {
 | 
			
		||||
    renderResults(payload);
 | 
			
		||||
    helperQueryRenderResults({'chunk': payload}, client);
 | 
			
		||||
    client.queryProgressBar.classList.toggle('hide');
 | 
			
		||||
    client.queryResultsUserFeedback.classList.toggle('hide');
 | 
			
		||||
    client.results.jsList.activateInspect();
 | 
			
		||||
    if (client.displayOptionsFormExpertMode.checked) {
 | 
			
		||||
      client.results.jsList.expertModeOn("query-display");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper function that saves result data into the client.results.data object.
 | 
			
		||||
 * Also does some showing and hiding of Elements and user feedback text.
 | 
			
		||||
 */
 | 
			
		||||
function helperQueryRenderResults (payload, client) {
 | 
			
		||||
  // updating table on finished item creation callback via createResultRowElement
 | 
			
		||||
  client.results.jsList.update();
 | 
			
		||||
  client.results.jsList.changeContext(); // sets lr context on first result load
 | 
			
		||||
  // incorporating new chunk results into full results
 | 
			
		||||
  client.results.data.matches.push(...payload.chunk.matches);
 | 
			
		||||
  client.results.data.addData(payload.chunk.cpos_lookup, 'cpos_lookup');
 | 
			
		||||
  client.results.data.addData(payload.chunk.text_lookup, 'text_lookup');
 | 
			
		||||
  // complete metaData
 | 
			
		||||
  // client.results.metaData.add();
 | 
			
		||||
  // show user current and total match count
 | 
			
		||||
  client.recievedMatchCount.textContent = `${client.results.data.matches.length}`;
 | 
			
		||||
  client.textLookupCount.textContent = `${Object.keys(client.results.data.text_lookup).length}`;
 | 
			
		||||
  let titles = new Array();
 | 
			
		||||
  for (let [key, value] of Object.entries(client.results.data.text_lookup)) {
 | 
			
		||||
    titles.push(`${value.title} (${value.publishing_year})`);
 | 
			
		||||
  };
 | 
			
		||||
  client.textLookupTitles.textContent = `${titles.join(", ")}`;
 | 
			
		||||
  // update progress bar and requestQueryProgress
 | 
			
		||||
  client.queryProgressBar.lastElementChild.style.width =  `${payload.progress}%`;
 | 
			
		||||
  client.requestQueryProgress = payload.progress;
 | 
			
		||||
function saveResultsData(args) {
 | 
			
		||||
  let [payload, client, results, rest] = arguments;
 | 
			
		||||
  // code to save results data depending on type
 | 
			
		||||
  console.info('Results data has been saved.');
 | 
			
		||||
  client.notifyView('results-data-recieved');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// export callbacks
 | 
			
		||||
export { prepareQueryData, saveMetaData, saveQueryData };
 | 
			
		||||
export {
 | 
			
		||||
  prepareQueryData,
 | 
			
		||||
  saveMetaData,
 | 
			
		||||
  saveQueryData,
 | 
			
		||||
  getResultsData,
 | 
			
		||||
  saveResultsData,
 | 
			
		||||
};
 | 
			
		||||
@@ -1,9 +1,14 @@
 | 
			
		||||
/**
 | 
			
		||||
 * This file contains the listener functions which can be assigned to the
 | 
			
		||||
 * coprus_analysis client. So that the incoming data/status informations will
 | 
			
		||||
 * be handled.
 | 
			
		||||
 * be handled. There are several listeners listening for socket .io events.
 | 
			
		||||
 * Further below one javascript custom event listener is specified. This
 | 
			
		||||
 * listener listens for javascript custom events which are being dispatched by
 | 
			
		||||
 * the View (resultsList).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// Listeners for socket io events
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Recieves a corpus analysis connected signal via socket.io.
 | 
			
		||||
 */
 | 
			
		||||
@@ -50,7 +55,7 @@ function recieveMetaData(type, client) {
 | 
			
		||||
      console.info(`corpus_analysis_meta_data: ${response.code} - ${response.msg}`);
 | 
			
		||||
      console.info(response);
 | 
			
		||||
      // executing the registered callbacks
 | 
			
		||||
      client.socketEventListeners[type].executeCallbacks(response.payload);
 | 
			
		||||
      client.eventListeners[type].executeCallbacks([response.payload]);
 | 
			
		||||
      console.groupEnd();
 | 
			
		||||
    } else {
 | 
			
		||||
      console.group('Failed to recieve meta data.');
 | 
			
		||||
@@ -81,7 +86,7 @@ function recieveQueryStatus(type, client) {
 | 
			
		||||
      console.info(`corpus_analysis_query: ${response.code} - ${response.msg}`);
 | 
			
		||||
      console.info(response);
 | 
			
		||||
      // executing the registered callbacks
 | 
			
		||||
      client.socketEventListeners[type].executeCallbacks(response.payload);
 | 
			
		||||
      client.eventListeners[type].executeCallbacks([response.payload]);
 | 
			
		||||
      console.groupEnd();
 | 
			
		||||
    } else {
 | 
			
		||||
      console.group('corpus_analysis_query: Client failed recieving',
 | 
			
		||||
@@ -113,7 +118,7 @@ function recieveQueryData(type, client) {
 | 
			
		||||
      /**
 | 
			
		||||
       * Execute registered callbacks and notify View.
 | 
			
		||||
       */
 | 
			
		||||
      client.socketEventListeners[type].executeCallbacks(response.payload);
 | 
			
		||||
      client.eventListeners[type].executeCallbacks([response.payload]);
 | 
			
		||||
      console.info('Added chunk data to results.data.');
 | 
			
		||||
      console.groupEnd();
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -125,18 +130,72 @@ function recieveQueryData(type, client) {
 | 
			
		||||
    }
 | 
			
		||||
    });
 | 
			
		||||
  } else {
 | 
			
		||||
    console.group('corpus_analysis_query_results: Loading query data.')
 | 
			
		||||
    console.group('corpus_analysis_query_results: Loading query data.');
 | 
			
		||||
    console.info('Client loading imported query data from database.');
 | 
			
		||||
    // executing the registered callbacks
 | 
			
		||||
    client.socketEventListeners[type].executeCallbacks();
 | 
			
		||||
    client.eventListeners[type].executeCallbacks();
 | 
			
		||||
    console.groupEnd();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Recieves the data requested by the create Results or sub results button
 | 
			
		||||
 */
 | 
			
		||||
function recieveResultsData(type, client) {
 | 
			
		||||
  client.socket.on(type, (response) => {
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if request for session was OK.
 | 
			
		||||
     * If OK execute registered callbacks and notify View.
 | 
			
		||||
     */
 | 
			
		||||
    if (response.code === 200) {
 | 
			
		||||
      console.group('Client recieving results data')
 | 
			
		||||
      console.info('corpus_analysis_inspect_match: Client recieving results data',
 | 
			
		||||
      'via socket.on');
 | 
			
		||||
      console.info(`corpus_analysis_inspect_match: ${response.code} - ${response.msg}`);
 | 
			
		||||
      console.info(response);
 | 
			
		||||
      // executing the registered callbacks
 | 
			
		||||
      client.eventListeners[type].executeCallbacks([response.payload]);
 | 
			
		||||
      console.groupEnd();
 | 
			
		||||
    } else {
 | 
			
		||||
      console.group('Failed to recieve results data.');
 | 
			
		||||
      console.error('corpus_analysis_inspect_match: Client failed to recieve',
 | 
			
		||||
                    'results data via socket.on');
 | 
			
		||||
      let errorText = `Error ${response.payload.code} - ${response.payload.msg}`;
 | 
			
		||||
      console.error(`corpus_analysis_inspect_match: ${errorText}`);
 | 
			
		||||
      console.groupEnd();
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is the javascript custom event listener, listening for events
 | 
			
		||||
 * dispatched by the View.
 | 
			
		||||
 */
 | 
			
		||||
function recieveViewNotification(type, client) {
 | 
			
		||||
  document.addEventListener(type, (event) => {
 | 
			
		||||
    let caseIdentifier = event.detail.caseIdentifier;
 | 
			
		||||
    switch(caseIdentifier) {
 | 
			
		||||
      case 'get-results':
 | 
			
		||||
        console.info('Client getting full results for export.');
 | 
			
		||||
        // execute callback or functions
 | 
			
		||||
        client.eventListeners[type].executeCallback([event.detail.resultsType,
 | 
			
		||||
                                                     event.detail.dataIndexes],
 | 
			
		||||
                                                     caseIdentifier);
 | 
			
		||||
        break
 | 
			
		||||
        default:
 | 
			
		||||
          console.error('Recieved unkown notification case identifier from View');
 | 
			
		||||
          // do something to not crash the analysis session?
 | 
			
		||||
          // maybe unnecessary
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// export listeners from this module
 | 
			
		||||
export {
 | 
			
		||||
  recieveConnected,
 | 
			
		||||
  recieveMetaData,
 | 
			
		||||
  recieveQueryStatus,
 | 
			
		||||
  recieveQueryData
 | 
			
		||||
  recieveQueryData,
 | 
			
		||||
  recieveViewNotification,
 | 
			
		||||
  recieveResultsData,
 | 
			
		||||
};
 | 
			
		||||
@@ -8,6 +8,7 @@ class Results {
 | 
			
		||||
  constructor() {
 | 
			
		||||
  this.data = new Data();
 | 
			
		||||
  this.metaData = new MetaData();
 | 
			
		||||
  this.fullResultsData = new Data();
 | 
			
		||||
  this.subResultsData = new Data();
 | 
			
		||||
  console.info('Initialized the Results object.');
 | 
			
		||||
  }
 | 
			
		||||
@@ -15,12 +16,12 @@ class Results {
 | 
			
		||||
  init() {
 | 
			
		||||
    this.data.init();
 | 
			
		||||
    this.metaData.init();
 | 
			
		||||
    this.fullResultsData = new Data();
 | 
			
		||||
    this.subResultsData.init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Data {
 | 
			
		||||
  // Sets empty object structure. Also usefull to delete old results.
 | 
			
		||||
  // matchCount default is 0
 | 
			
		||||
@@ -94,29 +95,6 @@ class Data {
 | 
			
		||||
    this.download(downloadElement, dataStr, resultFilename, "text/json", ".json")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // create results data either from all results or from al lmarked sub results
 | 
			
		||||
  createResultsData(type) {
 | 
			
		||||
    // deactivate inspect, because cqp server cannot handle multiple requests
 | 
			
		||||
    results.jsList.deactivateInspect();
 | 
			
		||||
    activateInspectInteraction.setCallback("noCheck",
 | 
			
		||||
                                            results.jsList.deactivateInspect,
 | 
			
		||||
                                            results.jsList);
 | 
			
		||||
    // set flag that results are being created to avoid reactivation of
 | 
			
		||||
    // sub results creation if marked matches are changed
 | 
			
		||||
    resultCreationRunning = true;
 | 
			
		||||
    console.log(resultCreationRunning);
 | 
			
		||||
    if (type === "sub-results") {
 | 
			
		||||
      resultsCreateElement.classList.add("disabled");  // cqp server cannot handle more than one request at a time. Thus we deactivate the resultsCreateElement
 | 
			
		||||
      let tmp = [...results.jsList.addToSubResultsIdsToShow].sort(function(a, b){return a-b});
 | 
			
		||||
      let dataIndexes = [];
 | 
			
		||||
      tmp.forEach((index) => dataIndexes.push(index - 1));
 | 
			
		||||
      results.jsList.getMatchWithContext(dataIndexes, "sub-results");
 | 
			
		||||
    } else if (type === "results") {
 | 
			
		||||
      subResultsCreateElement.classList.add("disabled");  // cqp server cannot handle more than one request at a time. Thus we deactivate the subResultsCreateElement
 | 
			
		||||
      let dataIndexes = [...Array(results.data.match_count).keys()];
 | 
			
		||||
      results.jsList.getMatchWithContext(dataIndexes, "results");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MetaData {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 * This class implements a NotificationListener that is listening for the
 | 
			
		||||
 * specified
 | 
			
		||||
 */
 | 
			
		||||
class NotificationListener {
 | 
			
		||||
class ViewEventListener {
 | 
			
		||||
  constructor(type, listenerFunction) {
 | 
			
		||||
    this.listenerFunction = listenerFunction;
 | 
			
		||||
    this.type = type;
 | 
			
		||||
@@ -61,7 +61,7 @@ class ResultsList extends List {
 | 
			
		||||
   * class field in the ResultsList object with the query selector
 | 
			
		||||
   * string as the key. The selector will be converted to a valid JavaScript
 | 
			
		||||
   * Field name i. e. #html-id-string -> this.htmlIdString
 | 
			
		||||
   * The value will be the identifed element fetched with the querySelector
 | 
			
		||||
   * The value will be the identifed element or elements fetched with the querySelector
 | 
			
		||||
   * method.
 | 
			
		||||
   */
 | 
			
		||||
  // TODO: multipleResults=false, atattchSomeCallback=false ?
 | 
			
		||||
@@ -73,6 +73,7 @@ class ResultsList extends List {
 | 
			
		||||
        element = document.querySelector(selector);
 | 
			
		||||
      } else {
 | 
			
		||||
        elements = document.querySelectorAll(selector);
 | 
			
		||||
        elements = [...elements];
 | 
			
		||||
      }
 | 
			
		||||
      let cleanKey = [];
 | 
			
		||||
      selector = selector.replace(/_/g, '-');
 | 
			
		||||
@@ -106,6 +107,17 @@ class ResultsList extends List {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * This functions sends events to the Client to trigger specific functions to
 | 
			
		||||
   * trigger new data requests from the server.
 | 
			
		||||
   */
 | 
			
		||||
  notifyClient(caseIdentifier, detailObject={}) {
 | 
			
		||||
    detailObject.caseIdentifier = caseIdentifier;
 | 
			
		||||
    const event = new CustomEvent('notify-client', { detail: detailObject });
 | 
			
		||||
    console.info('Client dispatching Notification:', caseIdentifier);
 | 
			
		||||
    document.dispatchEvent(event);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates cpos either from ranges or not.
 | 
			
		||||
   */
 | 
			
		||||
@@ -255,25 +267,6 @@ class ResultsList extends List {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 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() {
 | 
			
		||||
@@ -786,7 +779,7 @@ class ResultsList extends List {
 | 
			
		||||
    return matchRowElement
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // creates the HTML table code for the metadata vie in the corpus analysis interface
 | 
			
		||||
  // creates the HTML table code for the metadata view in the corpus analysis interface
 | 
			
		||||
  createMetaDataForModal(metaDataObject) {
 | 
			
		||||
    let html = `<div class="col s12">
 | 
			
		||||
                      <table class="highlight">
 | 
			
		||||
@@ -838,12 +831,12 @@ class ResultsList extends List {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Creates the text details for the texts shown in the corpus analysis metadata modal.
 | 
			
		||||
  createTextDetails(metaDataObject) {
 | 
			
		||||
  createTextDetails(metaData) {
 | 
			
		||||
    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 = "";
 | 
			
		||||
    let textData = metaData[metadataKey][textKey];
 | 
			
		||||
    let bibliographicData = document.querySelector(`#bibliographic-data-${metadataKey}-${textKey}`);
 | 
			
		||||
    bibliographicData.textContent = '';
 | 
			
		||||
    for (let [key, value] of Object.entries(textData)) {
 | 
			
		||||
      bibliographicData.insertAdjacentHTML("afterbegin",
 | 
			
		||||
      `
 | 
			
		||||
@@ -854,4 +847,4 @@ class ResultsList extends List {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// export classses
 | 
			
		||||
export { NotificationListener, ResultsList };
 | 
			
		||||
export { ViewEventListener, ResultsList };
 | 
			
		||||
@@ -98,8 +98,14 @@ function queryDataRecievedCallback(resultsList, detail) {
 | 
			
		||||
  // show or enable some things for the user
 | 
			
		||||
  resultsList.queryResultsCreate.classList.toggle('disabled');
 | 
			
		||||
  resultsList.addToSubResults.removeAttribute("disabled");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function resultsDataRecievingCallback(resultsList, detail) {
 | 
			
		||||
  // hide or disable elments taht would trigger another cqp data request
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function resultsDataRecievedCallback(resultsList, detail) {
 | 
			
		||||
  // hide or show the right stuff
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// export the callbacks
 | 
			
		||||
@@ -110,4 +116,6 @@ export {
 | 
			
		||||
  queryDataPreparingCallback,
 | 
			
		||||
  queryDataRecievingCallback,
 | 
			
		||||
  queryDataRecievedCallback,
 | 
			
		||||
  resultsDataRecievingCallback,
 | 
			
		||||
  resultsDataRecievedCallback,
 | 
			
		||||
};
 | 
			
		||||
@@ -14,43 +14,55 @@ import {
 | 
			
		||||
  queryDataPreparingCallback,
 | 
			
		||||
  queryDataRecievingCallback,
 | 
			
		||||
  queryDataRecievedCallback,
 | 
			
		||||
  resultsDataRecievingCallback,
 | 
			
		||||
  resultsDataRecievedCallback,
 | 
			
		||||
} from './callbacks.js';
 | 
			
		||||
 | 
			
		||||
function recieveNotification(eventType, resultsList) {
 | 
			
		||||
function recieveClientNotification(eventType, resultsList) {
 | 
			
		||||
  document.addEventListener(eventType, (event) => {
 | 
			
		||||
    let caseIdentifier = event.detail.caseIdentifier;
 | 
			
		||||
    switch (caseIdentifier) {
 | 
			
		||||
      case 'connecting':
 | 
			
		||||
        console.info('Recieved notification:', caseIdentifier);
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        connectingCallback(resultsList, event.detail);
 | 
			
		||||
        // execute callback
 | 
			
		||||
        break;
 | 
			
		||||
      case 'connected':
 | 
			
		||||
        console.info('Recieved notification:', caseIdentifier);
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        connectedCallback(resultsList, event.detail);
 | 
			
		||||
        break;
 | 
			
		||||
      case 'connecting-failed':
 | 
			
		||||
        console.info('Recieved notification:', caseIdentifier);
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        // execute callback
 | 
			
		||||
        connectingFaildeCallback(resultsList, event.detail);
 | 
			
		||||
        break;
 | 
			
		||||
      case 'query-data-prepareing':
 | 
			
		||||
        console.info('Recieved notification:', caseIdentifier);
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        // execute callback
 | 
			
		||||
        queryDataPreparingCallback(resultsList, event.detail);
 | 
			
		||||
        break;
 | 
			
		||||
      case 'query-data-recieving':
 | 
			
		||||
        console.info('Recieved notification:', caseIdentifier);
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        // execute callback
 | 
			
		||||
        queryDataRecievingCallback(resultsList, event.detail);
 | 
			
		||||
        break;
 | 
			
		||||
      case 'query-data-recieved':
 | 
			
		||||
        console.info('Recieved notification:', caseIdentifier);
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        // execute callback
 | 
			
		||||
        queryDataRecievedCallback(resultsList, event.detail);
 | 
			
		||||
        break;
 | 
			
		||||
      case 'results-data-recieving':
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        // execute callback
 | 
			
		||||
        resultsDataRecievedCallback(resultsList, event.detail);
 | 
			
		||||
        break;
 | 
			
		||||
      case 'results-data-recieved':
 | 
			
		||||
        console.info('View recieved notification:', caseIdentifier);
 | 
			
		||||
        // execute callback
 | 
			
		||||
        resultsDataRecievedCallback(resultsList, event.detail);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        console.error('Recieved unkown notification case identifier');
 | 
			
		||||
        console.error('Recieved unkown notification case identifier from Client');
 | 
			
		||||
        // do something to not crash the analysis session?
 | 
			
		||||
        // maybe unnecessary
 | 
			
		||||
    }
 | 
			
		||||
@@ -58,4 +70,4 @@ function recieveNotification(eventType, resultsList) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// export listeners
 | 
			
		||||
export { recieveNotification };
 | 
			
		||||
export { recieveClientNotification };
 | 
			
		||||
							
								
								
									
										17
									
								
								web/app/static/js/modules/corpus_analysis/view/spinner.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								web/app/static/js/modules/corpus_analysis/view/spinner.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
// loading spinner animation HTML
 | 
			
		||||
const loadingSpinnerHTML = `
 | 
			
		||||
            <div class="preloader-wrapper button-icon-spinner small active">
 | 
			
		||||
              <div class="spinner-layer spinner-green-only">
 | 
			
		||||
                <div class="circle-clipper left">
 | 
			
		||||
                  <div class="circle"></div>
 | 
			
		||||
                  </div><div class="gap-patch">
 | 
			
		||||
                  <div class="circle"></div>
 | 
			
		||||
                  </div><div class="circle-clipper right">
 | 
			
		||||
                  <div class="circle"></div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            `;
 | 
			
		||||
 | 
			
		||||
//export
 | 
			
		||||
export { loadingSpinnerHTML };
 | 
			
		||||
@@ -70,35 +70,45 @@
 | 
			
		||||
 * First Phase:
 | 
			
		||||
 * Document content is loaded and scripts are being imported and executed.
 | 
			
		||||
 */
 | 
			
		||||
 // import Client classes
 | 
			
		||||
import {
 | 
			
		||||
  Client,
 | 
			
		||||
  SocketEventListener,
 | 
			
		||||
  ClientEventListener,
 | 
			
		||||
  ListenerCallback,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/client/Client.js';
 | 
			
		||||
// import client listener functions
 | 
			
		||||
import {
 | 
			
		||||
  recieveConnected,
 | 
			
		||||
  recieveMetaData,
 | 
			
		||||
  recieveQueryStatus,
 | 
			
		||||
  recieveQueryData,
 | 
			
		||||
  recieveViewNotification,
 | 
			
		||||
  recieveResultsData,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/client/listeners.js';
 | 
			
		||||
import {
 | 
			
		||||
  Results,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/model/Results.js';
 | 
			
		||||
// import client listener callbacks
 | 
			
		||||
import {
 | 
			
		||||
  prepareQueryData,
 | 
			
		||||
  saveQueryData,
 | 
			
		||||
  saveMetaData,
 | 
			
		||||
  getResultsData,
 | 
			
		||||
  saveResultsData,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/client/callbacks.js';
 | 
			
		||||
import {
 | 
			
		||||
  NotificationListener,
 | 
			
		||||
  Results,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/model/Results.js';
 | 
			
		||||
import {
 | 
			
		||||
  ViewEventListener,
 | 
			
		||||
  ResultsList,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/view/ResultsView.js';
 | 
			
		||||
import {
 | 
			
		||||
  recieveNotification,
 | 
			
		||||
  recieveClientNotification,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/view/listeners.js';
 | 
			
		||||
import {
 | 
			
		||||
  scrollToTop,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/view/scrollToTop.js'
 | 
			
		||||
import {
 | 
			
		||||
  loadingSpinnerHTML,
 | 
			
		||||
} from '../../static/js/modules/corpus_analysis/view/spinner.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Second Phase:
 | 
			
		||||
@@ -120,44 +130,59 @@ document.addEventListener("DOMContentLoaded", () => {
 | 
			
		||||
  let resultsList = new ResultsList('result-list', ResultsList.options);
 | 
			
		||||
  /**
 | 
			
		||||
  * Register listeners listening to socket.io events and their callbacks
 | 
			
		||||
  * Afterwards load them.
 | 
			
		||||
  * Afterwards load them. Also registers listeners listening for custom
 | 
			
		||||
  * javascript events.
 | 
			
		||||
  */
 | 
			
		||||
  const listenForConnected = new SocketEventListener('corpus_analysis_init',
 | 
			
		||||
  const listenForConnected = new ClientEventListener('corpus_analysis_init',
 | 
			
		||||
                                                     recieveConnected);
 | 
			
		||||
  const listenForMetaData = new SocketEventListener('corpus_analysis_meta_data',
 | 
			
		||||
  const listenForMetaData = new ClientEventListener('corpus_analysis_meta_data',
 | 
			
		||||
                                                    recieveMetaData);
 | 
			
		||||
  const metaDataCallback = new ListenerCallback('corpus_analysis_meta_data',
 | 
			
		||||
                                                saveMetaData,
 | 
			
		||||
                                                [client, results]);
 | 
			
		||||
  listenForMetaData.setCallbacks([metaDataCallback]);
 | 
			
		||||
  const listenForQueryStatus = new SocketEventListener('corpus_analysis_query',
 | 
			
		||||
  const listenForQueryStatus = new ClientEventListener('corpus_analysis_query',
 | 
			
		||||
                                                       recieveQueryStatus);
 | 
			
		||||
  const queryStatusCallback = new ListenerCallback('corpus_analysis_query',
 | 
			
		||||
                                                   prepareQueryData,
 | 
			
		||||
                                                   [client, results]);
 | 
			
		||||
  listenForQueryStatus.setCallbacks([queryStatusCallback]);
 | 
			
		||||
  const listenForQueryData = new SocketEventListener('corpus_analysis_query_results',
 | 
			
		||||
  const listenForQueryData = new ClientEventListener('corpus_analysis_query_results',
 | 
			
		||||
                                                     recieveQueryData);
 | 
			
		||||
  const queryDataCallback = new ListenerCallback('corpus_analysis_query_results',
 | 
			
		||||
                                                 saveQueryData,
 | 
			
		||||
                                                 [client, results]);
 | 
			
		||||
  listenForQueryData.setCallbacks([queryDataCallback]);
 | 
			
		||||
  const listenForResults = new ClientEventListener('corpus_analysis_inspect_match',
 | 
			
		||||
                                                   recieveResultsData);
 | 
			
		||||
  const resultsDataCallback = new ListenerCallback('corpus_analysis_inspect_match',
 | 
			
		||||
                                                   saveResultsData,
 | 
			
		||||
                                                   [client, results]);
 | 
			
		||||
  listenForResults.setCallbacks([resultsDataCallback]);
 | 
			
		||||
  // listen for javascript custom notifications
 | 
			
		||||
  const listenForViewNotification = new ClientEventListener('notify-client',
 | 
			
		||||
                                                            recieveViewNotification);
 | 
			
		||||
  const getResultsCallback = new ListenerCallback('get-results',
 | 
			
		||||
                                                  getResultsData,
 | 
			
		||||
                                                  [client, results]);
 | 
			
		||||
  listenForViewNotification.setCallbacks([getResultsCallback]);
 | 
			
		||||
  client.setSocketEventListeners([listenForConnected,
 | 
			
		||||
                                  listenForQueryStatus,
 | 
			
		||||
                                  listenForQueryData,
 | 
			
		||||
                                  listenForMetaData]);
 | 
			
		||||
                                  listenForMetaData,
 | 
			
		||||
                                  listenForViewNotification,
 | 
			
		||||
                                  listenForResults]);
 | 
			
		||||
  client.loadSocketEventListeners();
 | 
			
		||||
  /**
 | 
			
		||||
  * Register resultsList listeners listening to nitification events.
 | 
			
		||||
  */
 | 
			
		||||
  const listenForNotification = new NotificationListener('notify',
 | 
			
		||||
                                                         recieveNotification);
 | 
			
		||||
  resultsList.setNotificationListeners([listenForNotification]);
 | 
			
		||||
  const listenForClientNotification = new ViewEventListener('notify-view',
 | 
			
		||||
                                                            recieveClientNotification);
 | 
			
		||||
  resultsList.setNotificationListeners([listenForClientNotification]);
 | 
			
		||||
  resultsList.loadNotificationListeners();
 | 
			
		||||
  // Connect client to server
 | 
			
		||||
  client.notifyView('connecting');
 | 
			
		||||
  client.connect();
 | 
			
		||||
 | 
			
		||||
  // Send a query and recieve its answer data
 | 
			
		||||
  let queryFormElement = document.querySelector('#query-form');
 | 
			
		||||
  queryFormElement.addEventListener('submit', (event) => {
 | 
			
		||||
@@ -181,20 +206,66 @@ document.addEventListener("DOMContentLoaded", () => {
 | 
			
		||||
    results.data.getQueryStr(queryFormElement);
 | 
			
		||||
    client.query(results.data.query);
 | 
			
		||||
  });
 | 
			
		||||
  /**
 | 
			
		||||
   * Display events
 | 
			
		||||
   * 1. live update of hits per page if hits per page value is changed
 | 
			
		||||
   */
 | 
			
		||||
  // Get all needed HTMLElements for the following event listeners
 | 
			
		||||
  resultsList.getHTMLElements([
 | 
			
		||||
    '#display-options-form-results_per_page',
 | 
			
		||||
    '#display-options-form-result_context'
 | 
			
		||||
    '#display-options-form-result_context',
 | 
			
		||||
    '#show-meta-data',
 | 
			
		||||
    '#meta-data-modal',
 | 
			
		||||
    '#meta-data-modal-content',
 | 
			
		||||
    '#query-results-create'
 | 
			
		||||
 | 
			
		||||
  ]);
 | 
			
		||||
  /**
 | 
			
		||||
   * Display events: Following event listeners are handleing the
 | 
			
		||||
   * live update of hits per page if hits per page value is changed and the
 | 
			
		||||
   * context size of every match.
 | 
			
		||||
   */
 | 
			
		||||
  resultsList.displayOptionsFormResultsPerPage.onchange = () => {
 | 
			
		||||
    resultsList.changeHitsPerPage();
 | 
			
		||||
  };
 | 
			
		||||
  resultsList.displayOptionsFormResultContext.onchange = () => {
 | 
			
		||||
    resultsList.changeContext();
 | 
			
		||||
  };
 | 
			
		||||
  /**
 | 
			
		||||
   * The following event listener handel the Show metadata button and its
 | 
			
		||||
   * functionality. Before the needed modal is initialized.
 | 
			
		||||
   */
 | 
			
		||||
  let deleteOverlay = () => {
 | 
			
		||||
    let overlay = document.querySelector(".modal-overlay");
 | 
			
		||||
    overlay.remove();
 | 
			
		||||
  };
 | 
			
		||||
  resultsList.metaDataModal= M.Modal.init(resultsList.metaDataModal, {
 | 
			
		||||
    'preventScrolling': false,
 | 
			
		||||
    'opacity': 0.0,
 | 
			
		||||
    'dismissible': false,
 | 
			
		||||
    'onOpenEnd': deleteOverlay
 | 
			
		||||
  });
 | 
			
		||||
  resultsList.showMetaData.onclick = () => {
 | 
			
		||||
    resultsList.metaDataModalContent.textContent = '';
 | 
			
		||||
    let table = resultsList.createMetaDataForModal(results.metaData);
 | 
			
		||||
    resultsList.metaDataModalContent.insertAdjacentHTML('afterbegin', table);
 | 
			
		||||
    resultsList.metaDataModal.open();
 | 
			
		||||
    let collapsibles = resultsList.metaDataModalContent.querySelectorAll(".text-metadata");
 | 
			
		||||
    for (let collapsible of collapsibles) {
 | 
			
		||||
      collapsible.onclick = () => {
 | 
			
		||||
        let elems = resultsList.metaDataModalContent.querySelectorAll('.collapsible');
 | 
			
		||||
        let instances = M.Collapsible.init(elems, {accordion: false});
 | 
			
		||||
        resultsList.createTextDetails(results.metaData);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  /**
 | 
			
		||||
   * The following event listeners are handeling the data export.
 | 
			
		||||
   */
 | 
			
		||||
  resultsList.queryResultsCreate.onclick = () => {
 | 
			
		||||
    resultsList.queryResultsCreate.querySelector('i').classList.toggle('hide');
 | 
			
		||||
    resultsList.queryResultsCreate.innerText = 'Creating...';
 | 
			
		||||
    resultsList.queryResultsCreate.insertAdjacentHTML('afterbegin',
 | 
			
		||||
                                                      loadingSpinnerHTML);
 | 
			
		||||
    resultsList.notifyClient('get-results', { resultsType: 'full-results',
 | 
			
		||||
                                              dataIndexes: [...Array(results.data.match_count).keys()]});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ result.-->
 | 
			
		||||
  <div class="divider" style="margin-bottom: 10px;"></div>
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col s12">
 | 
			
		||||
      <button id="show-metadata"
 | 
			
		||||
      <button id="show-meta-data"
 | 
			
		||||
              class="waves-effect
 | 
			
		||||
                     waves-light
 | 
			
		||||
                     btn-flat
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user