mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-03 20:02:47 +00:00 
			
		
		
		
	JS codestyle enhancements
This commit is contained in:
		@@ -6,36 +6,46 @@ class App {
 | 
			
		||||
    this.socket.on('users.patch', patch => this.usersPatchHandler(patch));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get users() {return this.data.users;}
 | 
			
		||||
  get users() {
 | 
			
		||||
    return this.data.users;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  addEventListener(type, listener) {
 | 
			
		||||
    if (!(type in this.eventListeners)) {throw `Unknown event type: ${type}`;}
 | 
			
		||||
    if (!(type in this.eventListeners)) {
 | 
			
		||||
      throw `Unknown event type: ${type}`;
 | 
			
		||||
    }
 | 
			
		||||
    this.eventListeners[type].push(listener);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  flash(message, category) {
 | 
			
		||||
    let toast, toastCloseActionElement;
 | 
			
		||||
    let iconPrefix;
 | 
			
		||||
    let toast;
 | 
			
		||||
    let toastCloseActionElement;
 | 
			
		||||
 | 
			
		||||
    switch (category) {
 | 
			
		||||
      case "corpus":
 | 
			
		||||
        message = `<i class="left material-icons">book</i>${message}`;
 | 
			
		||||
      case 'corpus':
 | 
			
		||||
        iconPrefix = '<i class="left material-icons">book</i>';
 | 
			
		||||
        break;
 | 
			
		||||
      case "error":
 | 
			
		||||
        message = `<i class="left material-icons error-color-text">error</i>${message}`;
 | 
			
		||||
      case 'error':
 | 
			
		||||
        iconPrefix = '<i class="error-color-text left material-icons">error</i>';
 | 
			
		||||
        break;
 | 
			
		||||
      case "job":
 | 
			
		||||
        message = `<i class="left nopaque-icons">J</i>${message}`;
 | 
			
		||||
      case 'job':
 | 
			
		||||
        iconPrefix = '<i class="left nopaque-icons">J</i>';
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        message = `<i class="left material-icons">notifications</i>${message}`;
 | 
			
		||||
        iconPrefix = '<i class="left material-icons">notifications</i>';
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    toast = M.toast({
 | 
			
		||||
      html: `
 | 
			
		||||
        <span>${message}</span>
 | 
			
		||||
        <button class="btn-flat toast-action white-text" data-action="close">
 | 
			
		||||
          <i class="material-icons">close</i>
 | 
			
		||||
        </button>
 | 
			
		||||
      `.trim()
 | 
			
		||||
    });
 | 
			
		||||
    toast = M.toast(
 | 
			
		||||
      {
 | 
			
		||||
        html: `
 | 
			
		||||
          <span>${iconPrefix}${message}</span>
 | 
			
		||||
          <button class="btn-flat toast-action white-text" data-action="close">
 | 
			
		||||
            <i class="material-icons">close</i>
 | 
			
		||||
          </button>
 | 
			
		||||
        `.trim()
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
    toastCloseActionElement = toast.el.querySelector('.toast-action[data-action="close"]');
 | 
			
		||||
    toastCloseActionElement.addEventListener('click', () => {toast.dismiss();});
 | 
			
		||||
  }
 | 
			
		||||
@@ -55,8 +65,16 @@ class App {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re, match, userId, ressourceId, jobId, relationship;
 | 
			
		||||
    for (let operation of patch.filter(operation => operation.op === 'add')) {
 | 
			
		||||
    let jobId;
 | 
			
		||||
    let listener;
 | 
			
		||||
    let match;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let re;
 | 
			
		||||
    let relationship;
 | 
			
		||||
    let ressourceId;
 | 
			
		||||
    let userId;
 | 
			
		||||
 | 
			
		||||
    for (operation of patch.filter(operation => operation.op === 'add')) {
 | 
			
		||||
      re = new RegExp(`^/users/([A-Za-z0-9]*)/corpora/([A-Za-z0-9]*)/(files)`);
 | 
			
		||||
      if (re.test(operation.path)) {
 | 
			
		||||
        [match, userId, ressourceId, relationship] = operation.path.match(re);
 | 
			
		||||
@@ -75,6 +93,6 @@ class App {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this.data = jsonpatch.apply_patch(this.data, patch);
 | 
			
		||||
    for (let listener of this.eventListeners['users.patch']) {listener(patch);}
 | 
			
		||||
    for (listener of this.eventListeners['users.patch']) {listener(patch);}
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,11 @@ class JobStatusNotifier {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re, filteredPatch, match, jobId;
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let jobId;
 | 
			
		||||
    let match;
 | 
			
		||||
    let re;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)/status$`)
 | 
			
		||||
    filteredPatch = patch
 | 
			
		||||
      .filter(operation => operation.op === 'replace')
 | 
			
		||||
 
 | 
			
		||||
@@ -2,34 +2,45 @@ class CorpusDisplay extends RessourceDisplay {
 | 
			
		||||
  constructor(displayElement) {
 | 
			
		||||
    super(displayElement);
 | 
			
		||||
    this.corpusId = displayElement.dataset.corpusId;
 | 
			
		||||
    for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) {
 | 
			
		||||
      exportCorpusTriggerElement.addEventListener('click', () => this.requestCorpusExport());
 | 
			
		||||
    }
 | 
			
		||||
    app.socket.on(`export_corpus_${this.corpusId}`, () => this.downloadCorpus());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {
 | 
			
		||||
    let corpus;
 | 
			
		||||
 | 
			
		||||
    corpus = user.corpora[this.corpusId];
 | 
			
		||||
    this.setCreationDate(corpus.creation_date);
 | 
			
		||||
    this.setDescription(corpus.description);
 | 
			
		||||
    this.setLastEditedDate(corpus.last_edited_date);
 | 
			
		||||
    this.setStatus(corpus.status);
 | 
			
		||||
    this.setTitle(corpus.title);
 | 
			
		||||
    this.setTokenRatio(corpus.num_tokens, corpus.max_num_tokens);
 | 
			
		||||
    this.setNumTokens(corpus.num_tokens);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  patch(patch) {
 | 
			
		||||
    let re, filteredPatch;
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let re;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}`);
 | 
			
		||||
    filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (let operation of filteredPatch) {
 | 
			
		||||
    for (operation of filteredPatch) {
 | 
			
		||||
      switch(operation.op) {
 | 
			
		||||
        case 'replace':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/last_edited_date$`);
 | 
			
		||||
          if (re.test(operation.path)) {this.setLastEditedDate(operation.value); break;}
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            this.setLastEditedDate(operation.value);
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/num_tokens`);
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            this.numTokens(operation.value);
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/status$`);
 | 
			
		||||
          if (re.test(operation.path)) {this.status$(operation.value); break;}
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            this.status(operation.value);
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
@@ -37,55 +48,48 @@ class CorpusDisplay extends RessourceDisplay {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  requestCorpusExport() {
 | 
			
		||||
    app.socket.emit('export_corpus', app.users[this.userId].corpora[this.corpusId]);
 | 
			
		||||
    app.flash('Preparing your corpus export...', 'corpus');
 | 
			
		||||
    for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) {exportCorpusTriggerElement.classList.toggle('disabled', true);}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  downloadCorpus() {
 | 
			
		||||
    let downloadButton;
 | 
			
		||||
    app.flash('Corpus download is ready!', 'corpus');
 | 
			
		||||
    for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) {exportCorpusTriggerElement.classList.toggle('disabled', false);}
 | 
			
		||||
    // Little trick to call the download view after ziping has finished
 | 
			
		||||
    downloadButton = document.createElement('a');
 | 
			
		||||
    downloadButton.href = `/corpora/${app.users[this.userId].corpora[this.corpusId]}/download`;
 | 
			
		||||
    downloadButton.click();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setTitle(title) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.corpus-title')) {this.setElement(element, title);}
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.corpus-title'), title);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setTokenRatio(numTokens, maxNumTokens) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.corpus-token-ratio')) {this.setElement(element, `${numTokens}/${maxNumTokens}`);}
 | 
			
		||||
  setNumTokens(numTokens) {
 | 
			
		||||
    this.setElements(
 | 
			
		||||
      this.displayElement.querySelectorAll('.corpus-token-ratio'),
 | 
			
		||||
      `${numTokens}/${app.users[this.userId].corpora[this.corpusId].max_num_tokens}`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setDescription(description) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.corpus-description')) {this.setElement(element, description);}
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.corpus-description'), description);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setStatus(status) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.analyse-corpus-trigger')) {
 | 
			
		||||
    let element;
 | 
			
		||||
    let elements;
 | 
			
		||||
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.corpus-status'), status);
 | 
			
		||||
    elements = this.displayElement.querySelectorAll('.analyse-corpus-trigger')
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      if (['analysing', 'prepared', 'start analysis'].includes(status)) {
 | 
			
		||||
        element.classList.remove('disabled');
 | 
			
		||||
      } else {
 | 
			
		||||
        element.classList.add('disabled');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.build-corpus-trigger')) {
 | 
			
		||||
    elements = this.displayElement.querySelectorAll('.build-corpus-trigger');
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      if (status === 'unprepared' && Object.values(app.users[this.userId].corpora[this.corpusId].files).length > 0) {
 | 
			
		||||
        element.classList.remove('disabled');
 | 
			
		||||
      } else {
 | 
			
		||||
        element.classList.add('disabled');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.corpus-status')) {this.setElement(element, status);}
 | 
			
		||||
    for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) {
 | 
			
		||||
      exportCorpusTriggerElement.classList.toggle('disabled', !['prepared', 'start analysis', 'stop analysis'].includes(status));
 | 
			
		||||
    elements = this.displayElement.querySelectorAll('.status');
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      element.dataset.status = status;
 | 
			
		||||
    }
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.status')) {element.dataset.status = status;}
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.status-spinner')) {
 | 
			
		||||
    elements = this.displayElement.querySelectorAll('.status-spinner');
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      if (['submitted', 'queued', 'running', 'canceling', 'start analysis', 'stop analysis'].includes(status)) {
 | 
			
		||||
        element.classList.remove('hide');
 | 
			
		||||
      } else {
 | 
			
		||||
@@ -95,14 +99,16 @@ class CorpusDisplay extends RessourceDisplay {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setCreationDate(creationDate) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.corpus-creation-date')) {
 | 
			
		||||
      this.setElement(element, creationDate.toLocaleString("en-US"));
 | 
			
		||||
    }
 | 
			
		||||
    this.setElements(
 | 
			
		||||
      this.displayElement.querySelectorAll('.corpus-creation-date'),
 | 
			
		||||
      new Date(creationDate).toLocaleString("en-US")
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setLastEditedDate(lastEditedDate) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.corpus-end-date')) {
 | 
			
		||||
      this.setElement(element, lastEditedDate.toLocaleString("en-US"));
 | 
			
		||||
    }
 | 
			
		||||
    this.setElements(
 | 
			
		||||
      this.displayElement.querySelectorAll('.corpus-end-date'),
 | 
			
		||||
      new Date(lastEditedDate).toLocaleString("en-US")
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,9 @@ class JobDisplay extends RessourceDisplay {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {
 | 
			
		||||
    let job = user.jobs[this.jobId];
 | 
			
		||||
    let job;
 | 
			
		||||
 | 
			
		||||
    job = user.jobs[this.jobId];
 | 
			
		||||
    this.setCreationDate(job.creation_date);
 | 
			
		||||
    this.setEndDate(job.creation_date);
 | 
			
		||||
    this.setDescription(job.description);
 | 
			
		||||
@@ -17,9 +19,13 @@ class JobDisplay extends RessourceDisplay {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}`);
 | 
			
		||||
    let filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (let operation of filteredPatch) {
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let re;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}`);
 | 
			
		||||
    filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (operation of filteredPatch) {
 | 
			
		||||
      switch(operation.op) {
 | 
			
		||||
        case 'replace':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/end_date$`);
 | 
			
		||||
@@ -40,26 +46,33 @@ class JobDisplay extends RessourceDisplay {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setTitle(title) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-title')) {this.setElement(element, title);}
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.job-title'), title);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setDescription(description) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-description')) {this.setElement(element, description);}
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.job-description'), description);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setStatus(status) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-status')) {
 | 
			
		||||
      this.setElement(element, status);
 | 
			
		||||
    let element;
 | 
			
		||||
    let elements;
 | 
			
		||||
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.job-status'), status);
 | 
			
		||||
 | 
			
		||||
    elements = this.displayElement.querySelectorAll('.status');
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      element.dataset.status = status;
 | 
			
		||||
    }
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.status')) {element.dataset.status = status;}
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.status-spinner')) {
 | 
			
		||||
    elements = this.displayElement.querySelectorAll('.status-spinner');
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      if (['complete', 'failed'].includes(status)) {
 | 
			
		||||
        element.classList.add('hide');
 | 
			
		||||
      } else {
 | 
			
		||||
        element.classList.remove('hide');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.restart-job-trigger')) {
 | 
			
		||||
    elements = this.displayElement.querySelectorAll('.restart-job-trigger');
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      if (['complete', 'failed'].includes(status)) {
 | 
			
		||||
        element.classList.remove('hide');
 | 
			
		||||
      } else {
 | 
			
		||||
@@ -69,26 +82,28 @@ class JobDisplay extends RessourceDisplay {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setCreationDate(creationDate) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-creation-date')) {
 | 
			
		||||
      this.setElement(element, creationDate.toLocaleString('en-US'));
 | 
			
		||||
    }
 | 
			
		||||
    this.setElements(
 | 
			
		||||
      this.displayElement.querySelectorAll('.job-creation-date'),
 | 
			
		||||
      new Date(creationDate).toLocaleString('en-US')
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setEndDate(endDate) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-end-date')) {
 | 
			
		||||
      this.setElement(element, endDate.toLocaleString('en-US'));
 | 
			
		||||
    }
 | 
			
		||||
    this.setElements(
 | 
			
		||||
      this.displayElement.querySelectorAll('.job-end-date'),
 | 
			
		||||
      new Date(endDate).toLocaleString('en-US')
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setService(service) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-service')) {this.setElement(element, service);}
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.job-service'), service);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setServiceArgs(serviceArgs) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-service-args')) {this.setElement(element, serviceArgs);}
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.job-service-args'), serviceArgs);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setServiceVersion(serviceVersion) {
 | 
			
		||||
    for (let element of this.displayElement.querySelectorAll('.job-service-version')) {this.setElement(element, serviceVersion);}
 | 
			
		||||
    this.setElements(this.displayElement.querySelectorAll('.job-service-version'), serviceVersion);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ class RessourceDisplay {
 | 
			
		||||
    this.displayElement = displayElement;
 | 
			
		||||
    this.userId = this.displayElement.dataset.userId;
 | 
			
		||||
    app.addEventListener('users.patch', patch => this.usersPatchHandler(patch));
 | 
			
		||||
    app.getUserById(this.userId).then(user => this.init(user), error => {throw JSON.stringify(error);});
 | 
			
		||||
    app.getUserById(this.userId).then(user => this.init(user));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {throw 'Not implemented';}
 | 
			
		||||
@@ -21,4 +21,12 @@ class RessourceDisplay {
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setElements(elements, value) {
 | 
			
		||||
    let element;
 | 
			
		||||
 | 
			
		||||
    for (element of elements) {
 | 
			
		||||
      this.setElement(element, value);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,14 +9,23 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onclick(event) {
 | 
			
		||||
    let corpusFileElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (corpusFileElement === null) {throw 'Could not locate corpus file element';}
 | 
			
		||||
    let corpusFileId = corpusFileElement.dataset.id;
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    let action;
 | 
			
		||||
    let actionButtonElement;
 | 
			
		||||
    let corpusFileElement;
 | 
			
		||||
    let corpusFileId;
 | 
			
		||||
    let deleteModal;
 | 
			
		||||
    let deleteModalElement;
 | 
			
		||||
    let tmp;
 | 
			
		||||
 | 
			
		||||
    corpusFileElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (corpusFileElement === null) {return;}
 | 
			
		||||
    corpusFileId = corpusFileElement.dataset.id;
 | 
			
		||||
    actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete':
 | 
			
		||||
        let deleteModalHTML = `
 | 
			
		||||
        tmp = document.createElement('div');
 | 
			
		||||
        tmp.innerHTML = `
 | 
			
		||||
          <div class="modal">
 | 
			
		||||
            <div class="modal-content">
 | 
			
		||||
              <h4>Confirm corpus deletion</h4>
 | 
			
		||||
@@ -28,10 +37,16 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        `.trim();
 | 
			
		||||
        let deleteModalParentElement = document.querySelector('#modals');
 | 
			
		||||
        deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML);
 | 
			
		||||
        let deleteModalElement = deleteModalParentElement.lastChild;
 | 
			
		||||
        let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}});
 | 
			
		||||
        deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
 | 
			
		||||
        deleteModal = M.Modal.init(
 | 
			
		||||
          deleteModalElement,
 | 
			
		||||
          {
 | 
			
		||||
            onCloseEnd: () => {
 | 
			
		||||
              deleteModal.destroy();
 | 
			
		||||
              deleteModalElement.remove();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        );
 | 
			
		||||
        deleteModal.open();
 | 
			
		||||
        break;
 | 
			
		||||
      case 'download':
 | 
			
		||||
@@ -46,13 +61,22 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)`);
 | 
			
		||||
    let filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (let operation of filteredPatch) {
 | 
			
		||||
    let corpusFileId;
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let match;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let re;
 | 
			
		||||
    let valueName;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)`);
 | 
			
		||||
    filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (operation of filteredPatch) {
 | 
			
		||||
      switch(operation.op) {
 | 
			
		||||
        case 'add':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)$`);
 | 
			
		||||
          if (re.test(operation.path)) {this.add(operation.value);}
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            this.add(operation.value);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 'remove':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)$`);
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,23 @@ class CorpusList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onclick(event) {
 | 
			
		||||
    let corpusElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (corpusElement === null) {throw 'Could not locate corpus element';}
 | 
			
		||||
    let corpusId = corpusElement.dataset.id;
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    let action;
 | 
			
		||||
    let actionButtonElement;
 | 
			
		||||
    let corpusElement;
 | 
			
		||||
    let corpusId;
 | 
			
		||||
    let deleteModal;
 | 
			
		||||
    let deleteModalElement;
 | 
			
		||||
    let tmp;
 | 
			
		||||
 | 
			
		||||
    corpusElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (corpusElement === null) {return;}
 | 
			
		||||
    corpusId = corpusElement.dataset.id;
 | 
			
		||||
    actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete':
 | 
			
		||||
        let deleteModalHTML = `
 | 
			
		||||
        tmp = document.createElement('div');
 | 
			
		||||
        tmp.innerHTML = `
 | 
			
		||||
          <div class="modal">
 | 
			
		||||
            <div class="modal-content">
 | 
			
		||||
              <h4>Confirm corpus deletion</h4>
 | 
			
		||||
@@ -27,10 +36,16 @@ class CorpusList extends RessourceList {
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        `.trim();
 | 
			
		||||
        let deleteModalParentElement = document.querySelector('#modals');
 | 
			
		||||
        deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML);
 | 
			
		||||
        let deleteModalElement = deleteModalParentElement.lastChild;
 | 
			
		||||
        let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}});
 | 
			
		||||
        deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
 | 
			
		||||
        deleteModal = M.Modal.init(
 | 
			
		||||
          deleteModalElement,
 | 
			
		||||
          {
 | 
			
		||||
            onCloseEnd: () => {
 | 
			
		||||
              deleteModal.destroy();
 | 
			
		||||
              deleteModalElement.remove();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        );
 | 
			
		||||
        deleteModal.open();
 | 
			
		||||
        break;
 | 
			
		||||
      case 'view':
 | 
			
		||||
@@ -42,9 +57,16 @@ class CorpusList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)`);
 | 
			
		||||
    let filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (let operation of filteredPatch) {
 | 
			
		||||
    let corpusId;
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let match;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let re;
 | 
			
		||||
    let valueName;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)`);
 | 
			
		||||
    filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (operation of filteredPatch) {
 | 
			
		||||
      switch(operation.op) {
 | 
			
		||||
        case 'add':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)$`);
 | 
			
		||||
@@ -53,14 +75,14 @@ class CorpusList extends RessourceList {
 | 
			
		||||
        case 'remove':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)$`);
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            let [match, corpusId] = operation.path.match(re);
 | 
			
		||||
            [match, corpusId] = operation.path.match(re);
 | 
			
		||||
            this.remove(corpusId);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 'replace':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)/(status|description|title)$`);
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            let [match, corpusId, valueName] = operation.path.match(re);
 | 
			
		||||
            [match, corpusId, valueName] = operation.path.match(re);
 | 
			
		||||
            this.replace(corpusId, valueName, operation.value);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,17 @@ class JobInputList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onclick(event) {
 | 
			
		||||
    let jobInputElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    let jobInputElement;
 | 
			
		||||
    let jobInputId;
 | 
			
		||||
    let action;
 | 
			
		||||
    let actionButtonElement;
 | 
			
		||||
 | 
			
		||||
    jobInputElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (jobInputElement === null) {return;}
 | 
			
		||||
    let jobInputId = jobInputElement.dataset.id;
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    jobInputId = jobInputElement.dataset.id;
 | 
			
		||||
    actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    if (actionButtonElement === null) {return;}
 | 
			
		||||
    let action = actionButtonElement.dataset.action;
 | 
			
		||||
    action = actionButtonElement.dataset.action;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'download':
 | 
			
		||||
        window.location.href = `/jobs/${this.jobId}/inputs/${jobInputId}/download`;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,23 @@ class JobList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onclick(event) {
 | 
			
		||||
    let jobElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (jobElement === null) {throw 'Could not locate job element';}
 | 
			
		||||
    let jobId = jobElement.dataset.id;
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    let action;
 | 
			
		||||
    let actionButtonElement;
 | 
			
		||||
    let deleteModal;
 | 
			
		||||
    let deleteModalElement;
 | 
			
		||||
    let jobElement;
 | 
			
		||||
    let jobId;
 | 
			
		||||
    let tmp;
 | 
			
		||||
 | 
			
		||||
    jobElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (jobElement === null) {return;}
 | 
			
		||||
    jobId = jobElement.dataset.id;
 | 
			
		||||
    actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete':
 | 
			
		||||
        let deleteModalHTML = `
 | 
			
		||||
        tmp = document.createElement('div');
 | 
			
		||||
        tmp.innerHTML = `
 | 
			
		||||
          <div class="modal">
 | 
			
		||||
            <div class="modal-content">
 | 
			
		||||
              <h4>Confirm job deletion</h4>
 | 
			
		||||
@@ -27,10 +36,16 @@ class JobList extends RessourceList {
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        `.trim();
 | 
			
		||||
        let deleteModalParentElement = document.querySelector('#modals');
 | 
			
		||||
        deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML);
 | 
			
		||||
        let deleteModalElement = deleteModalParentElement.lastChild;
 | 
			
		||||
        let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}});
 | 
			
		||||
        deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
 | 
			
		||||
        deleteModal = M.Modal.init(
 | 
			
		||||
          deleteModalElement,
 | 
			
		||||
          {
 | 
			
		||||
            onCloseEnd: () => {
 | 
			
		||||
              deleteModal.destroy();
 | 
			
		||||
              deleteModalElement.remove();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        );
 | 
			
		||||
        deleteModal.open();
 | 
			
		||||
        break;
 | 
			
		||||
      case 'view':
 | 
			
		||||
@@ -42,25 +57,34 @@ class JobList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)`);
 | 
			
		||||
    let filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (let operation of filteredPatch) {
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let jobId;
 | 
			
		||||
    let match;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let re;
 | 
			
		||||
    let valueName;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)`);
 | 
			
		||||
    filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (operation of filteredPatch) {
 | 
			
		||||
      switch(operation.op) {
 | 
			
		||||
        case 'add':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)$`);
 | 
			
		||||
          if (re.test(operation.path)) {this.add(operation.value);}
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            this.add(operation.value);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 'remove':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)$`);
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            let [match, jobId] = operation.path.match(re);
 | 
			
		||||
            [match, jobId] = operation.path.match(re);
 | 
			
		||||
            this.remove(jobId);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 'replace':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)/(service|status|description|title)$`);
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            let [match, jobId, valueName] = operation.path.match(re);
 | 
			
		||||
            [match, jobId, valueName] = operation.path.match(re);
 | 
			
		||||
            this.replace(jobId, valueName, operation.value);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,17 @@ class JobResultList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onclick(event) {
 | 
			
		||||
    let jobResultElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    let action;
 | 
			
		||||
    let actionButtonElement;
 | 
			
		||||
    let jobResultElement;
 | 
			
		||||
    let jobResultId;
 | 
			
		||||
 | 
			
		||||
    jobResultElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (jobResultElement === null) {return;}
 | 
			
		||||
    let jobResultId = jobResultElement.dataset.id;
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    jobResultId = jobResultElement.dataset.id;
 | 
			
		||||
    actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    if (actionButtonElement === null) {return;}
 | 
			
		||||
    let action = actionButtonElement.dataset.action;
 | 
			
		||||
    action = actionButtonElement.dataset.action;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'download':
 | 
			
		||||
        window.location.href = `/jobs/${this.jobId}/results/${jobResultId}`;
 | 
			
		||||
@@ -25,13 +30,19 @@ class JobResultList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)`);
 | 
			
		||||
    let filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (let operation of filteredPatch) {
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let re;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)`);
 | 
			
		||||
    filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (operation of filteredPatch) {
 | 
			
		||||
      switch(operation.op) {
 | 
			
		||||
        case 'add':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)$`);
 | 
			
		||||
          if (re.test(operation.path)) {this.add(operation.value);}
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            this.add(operation.value);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
@@ -41,6 +52,7 @@ class JobResultList extends RessourceList {
 | 
			
		||||
 | 
			
		||||
  preprocessRessource(jobResult) {
 | 
			
		||||
    let description;
 | 
			
		||||
 | 
			
		||||
    if (jobResult.filename.endsWith('.pdf.zip')) {
 | 
			
		||||
      description = 'PDF files with text layer';
 | 
			
		||||
    } else if (jobResult.filename.endsWith('.txt.zip')) {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,23 @@ class QueryResultList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onclick(event) {
 | 
			
		||||
    let queryResultElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    let action;
 | 
			
		||||
    let actionButtonElement;
 | 
			
		||||
    let deleteModal;
 | 
			
		||||
    let deleteModalElement;
 | 
			
		||||
    let queryResultElement;
 | 
			
		||||
    let queryResultId;
 | 
			
		||||
    let tmp;
 | 
			
		||||
 | 
			
		||||
    queryResultElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (queryResultElement === null) {return;}
 | 
			
		||||
    let queryResultId = queryResultElement.dataset.id;
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    queryResultId = queryResultElement.dataset.id;
 | 
			
		||||
    actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete':
 | 
			
		||||
        let deleteModalHTML = `
 | 
			
		||||
        tmp = document.createElement('div');
 | 
			
		||||
        tmp.innerHTML = `
 | 
			
		||||
          <div class="modal">
 | 
			
		||||
            <div class="modal-content">
 | 
			
		||||
              <h4>Confirm query result deletion</h4>
 | 
			
		||||
@@ -27,10 +36,16 @@ class QueryResultList extends RessourceList {
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        `.trim();
 | 
			
		||||
        let deleteModalParentElement = document.querySelector('#modals');
 | 
			
		||||
        deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML);
 | 
			
		||||
        let deleteModalElement = deleteModalParentElement.lastChild;
 | 
			
		||||
        let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}});
 | 
			
		||||
        deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
 | 
			
		||||
        deleteModal = M.Modal.init(
 | 
			
		||||
          deleteModalElement,
 | 
			
		||||
          {
 | 
			
		||||
            onCloseEnd: () => {
 | 
			
		||||
              deleteModal.destroy();
 | 
			
		||||
              deleteModalElement.remove();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        );
 | 
			
		||||
        deleteModal.open();
 | 
			
		||||
        break;
 | 
			
		||||
      case 'view':
 | 
			
		||||
@@ -42,25 +57,34 @@ class QueryResultList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  usersPatchHandler(patch) {
 | 
			
		||||
    let re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)`);
 | 
			
		||||
    let filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (let operation of filteredPatch) {
 | 
			
		||||
    let filteredPatch;
 | 
			
		||||
    let match;
 | 
			
		||||
    let operation;
 | 
			
		||||
    let queryResultId;
 | 
			
		||||
    let re;
 | 
			
		||||
    let valueName;
 | 
			
		||||
 | 
			
		||||
    re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)`);
 | 
			
		||||
    filteredPatch = patch.filter(operation => re.test(operation.path));
 | 
			
		||||
    for (operation of filteredPatch) {
 | 
			
		||||
      switch(operation.op) {
 | 
			
		||||
        case 'add':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`);
 | 
			
		||||
          if (re.test(operation.path)) {this.add(operation.value);}
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            this.add(operation.value);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 'remove':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`);
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            let [match, queryResultId] = operation.path.match(re);
 | 
			
		||||
            [match, queryResultId] = operation.path.match(re);
 | 
			
		||||
            this.remove(queryResultId);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 'replace':
 | 
			
		||||
          re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)/(corpus_title|description|query|title)$`);
 | 
			
		||||
          if (re.test(operation.path)) {
 | 
			
		||||
            let [match, queryResultId, valueName] = operation.path.match(re);
 | 
			
		||||
            [match, queryResultId, valueName] = operation.path.match(re);
 | 
			
		||||
            this.replace(queryResultId, valueName, operation.value);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,23 @@ class UserList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onclick(event) {
 | 
			
		||||
    let userElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    let action;
 | 
			
		||||
    let actionButtonElement;
 | 
			
		||||
    let deleteModal;
 | 
			
		||||
    let deleteModalElement;
 | 
			
		||||
    let tmp;
 | 
			
		||||
    let userElement;
 | 
			
		||||
    let userId;
 | 
			
		||||
 | 
			
		||||
    userElement = event.target.closest('tr[data-id]');
 | 
			
		||||
    if (userElement === null) {return;}
 | 
			
		||||
    let userId = userElement.dataset.id;
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    let action = (actionButtonElement === null) ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    userId = userElement.dataset.id;
 | 
			
		||||
    actionButtonElement = event.target.closest('.action-button[data-action]');
 | 
			
		||||
    action = (actionButtonElement === null) ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete':
 | 
			
		||||
        let deleteModalHTML = `
 | 
			
		||||
        tmp = document.createElement('div');
 | 
			
		||||
        tmp.innerHTML = `
 | 
			
		||||
          <div class="modal">
 | 
			
		||||
            <div class="modal-content">
 | 
			
		||||
              <h4>Confirm user deletion</h4>
 | 
			
		||||
@@ -27,10 +36,16 @@ class UserList extends RessourceList {
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        `.trim();
 | 
			
		||||
        let deleteModalParentElement = document.querySelector('#modals');
 | 
			
		||||
        deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML);
 | 
			
		||||
        let deleteModalElement = deleteModalParentElement.lastChild;
 | 
			
		||||
        let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}});
 | 
			
		||||
        deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
 | 
			
		||||
        deleteModal = M.Modal.init(
 | 
			
		||||
          deleteModalElement,
 | 
			
		||||
          {
 | 
			
		||||
            onCloseEnd: () => {
 | 
			
		||||
              deleteModal.destroy();
 | 
			
		||||
              deleteModalElement.remove();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        );
 | 
			
		||||
        deleteModal.open();
 | 
			
		||||
        break;
 | 
			
		||||
      case 'edit':
 | 
			
		||||
@@ -50,7 +65,7 @@ class UserList extends RessourceList {
 | 
			
		||||
      id_: user.id,
 | 
			
		||||
      username: user.username,
 | 
			
		||||
      email: user.email,
 | 
			
		||||
      last_seen: user.last_seen.toLocaleString("en-US"),
 | 
			
		||||
      last_seen: new Date(user.last_seen).toLocaleString("en-US"),
 | 
			
		||||
      role: user.role.name
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user