mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-04 04:12:45 +00:00 
			
		
		
		
	Change List.js integration and rename service-icon css
This commit is contained in:
		@@ -201,15 +201,15 @@ $color: (
 | 
			
		||||
 | 
			
		||||
@each $ressource-name, $color-palette in map-get($color, "status") {
 | 
			
		||||
  @each $key, $color-code in $color-palette {
 | 
			
		||||
    .#{$ressource-name}-status-color[data-#{$ressource-name}-status="#{$key}"] {
 | 
			
		||||
    .#{$ressource-name}-status-color[data-status="#{$key}"] {
 | 
			
		||||
      background-color: $color-code !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .#{$ressource-name}-status-color-border[data-#{$ressource-name}-status="#{$key}"] {
 | 
			
		||||
    .#{$ressource-name}-status-color-border[data-status="#{$key}"] {
 | 
			
		||||
      border-color: $color-code !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .#{$ressource-name}-status-color-text[data-#{$ressource-name}-status="#{$key}"] {
 | 
			
		||||
    .#{$ressource-name}-status-color-text[data-status="#{$key}"] {
 | 
			
		||||
      color: $color-code !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
  transform: scale(2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn-scale-x2 .nopaque-icons.service-icon {
 | 
			
		||||
.btn-scale-x2 .nopaque-icons.service-icons {
 | 
			
		||||
  font-size: 2.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -37,17 +37,20 @@ h1 .nopaque-icons, h2 .nopaque-icons, h3 .nopaque-icons, h4 .nopaque-icons, .tab
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.corpus-status-text {text-transform: lowercase;}
 | 
			
		||||
.corpus-status-text[data-corpus-status]:empty:before {content: attr(data-corpus-status);}
 | 
			
		||||
.corpus-status-text, .job-status-text {text-transform: lowercase;}
 | 
			
		||||
.corpus-status-text[data-status]:empty::before, .job-status-text[data-status]:empty::before {content: attr(data-status);}
 | 
			
		||||
 | 
			
		||||
.job-status-text {text-transform: lowercase;}
 | 
			
		||||
.job-status-text[data-job-status]:empty:before {content: attr(data-job-status);}
 | 
			
		||||
.service-scheme[data-service="file-setup-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "E";}
 | 
			
		||||
.service-scheme[data-service="tesseract-ocr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
 | 
			
		||||
.service-scheme[data-service="transkribus-htr-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "F";}
 | 
			
		||||
.service-scheme[data-service="spacy-nlp-pipeline"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "G";}
 | 
			
		||||
.service-scheme[data-service="corpus-analysis"] .nopaque-icons.service-icons[data-service="inherit"]:empty::before {content: "H";}
 | 
			
		||||
 | 
			
		||||
.nopaque-icons.service-icon[data-service="file-setup-pipeline"]:empty:before {content: "E";}
 | 
			
		||||
.nopaque-icons.service-icon[data-service="tesseract-ocr-pipeline"]:empty:before {content: "F";}
 | 
			
		||||
.nopaque-icons.service-icon[data-service="transkribus-htr-pipeline"]:empty:before {content: "F";}
 | 
			
		||||
.nopaque-icons.service-icon[data-service="spacy-nlp-pipeline"]:empty:before {content: "G";}
 | 
			
		||||
.nopaque-icons.service-icon[data-service="corpus-analysis"]:empty:before {content: "H";}
 | 
			
		||||
.nopaque-icons.service-icons[data-service="file-setup-pipeline"]:empty::before {content: "E";}
 | 
			
		||||
.nopaque-icons.service-icons[data-service="tesseract-ocr-pipeline"]:empty::before {content: "F";}
 | 
			
		||||
.nopaque-icons.service-icons[data-service="transkribus-htr-pipeline"]:empty::before {content: "F";}
 | 
			
		||||
.nopaque-icons.service-icons[data-service="spacy-nlp-pipeline"]:empty::before {content: "G";}
 | 
			
		||||
.nopaque-icons.service-icons[data-service="corpus-analysis"]:empty::before {content: "H";}
 | 
			
		||||
 | 
			
		||||
.clickable {
 | 
			
		||||
  cursor: pointer !important;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search corpus file</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search corpus file</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -28,6 +28,18 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (corpusFile) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': corpusFile.id,
 | 
			
		||||
        'author': corpusFile.author,
 | 
			
		||||
        'creation-date': corpusFile.creation_date,
 | 
			
		||||
        'filename': corpusFile.filename,
 | 
			
		||||
        'publishing-year': corpusFile.publishing_year,
 | 
			
		||||
        'title': corpusFile.title
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['creation-date', {order: 'desc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><span class="filename"></span></td>
 | 
			
		||||
@@ -41,17 +53,6 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (corpusFile) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': corpusFile.id,
 | 
			
		||||
        'author': corpusFile.author,
 | 
			
		||||
        'creation-date': corpusFile.creation_date,
 | 
			
		||||
        'filename': corpusFile.filename,
 | 
			
		||||
        'publishing-year': corpusFile.publishing_year,
 | 
			
		||||
        'title': corpusFile.title
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['creation-date', {order: 'desc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['creation-date']},
 | 
			
		||||
@@ -60,11 +61,12 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
        'publishing-year',
 | 
			
		||||
        'title'
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...CorpusFileList.options, ...options});
 | 
			
		||||
    this.corpusId = listElement.dataset.corpusId;
 | 
			
		||||
  constructor(listContainerElement, options={}) {
 | 
			
		||||
    super(listContainerElement, _.merge({}, CorpusFileList.options, options));
 | 
			
		||||
    this.corpusId = listContainerElement.dataset.corpusId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {
 | 
			
		||||
@@ -72,10 +74,12 @@ class CorpusFileList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onClick(event) {
 | 
			
		||||
    let corpusFileElement = event.target.closest('tr');
 | 
			
		||||
    if (corpusFileElement === null) {return;}
 | 
			
		||||
    let corpusFileId = corpusFileElement.dataset.id;
 | 
			
		||||
    if (corpusFileId === undefined) {return;}
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    let corpusFileElement = event.target.closest('tr');
 | 
			
		||||
    let corpusFileId = corpusFileElement.dataset.id;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete': {
 | 
			
		||||
        Utils.deleteCorpusFileRequest(this.userId, this.corpusId, corpusFileId);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,4 @@
 | 
			
		||||
class CorpusList extends RessourceList {
 | 
			
		||||
  static instances = [];
 | 
			
		||||
 | 
			
		||||
  static getInstance(elem) {
 | 
			
		||||
    return CorpusList.instances.find((instance) => {
 | 
			
		||||
      return instance.listjs.list === elem;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static autoInit() {
 | 
			
		||||
    for (let corpusListElement of document.querySelectorAll('.corpus-list:not(.no-autoinit)')) {
 | 
			
		||||
      new CorpusList(corpusListElement);
 | 
			
		||||
@@ -14,12 +6,12 @@ class CorpusList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search corpus</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search corpus</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -35,6 +27,17 @@ class CorpusList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (corpus) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': corpus.id,
 | 
			
		||||
        'creation-date': corpus.creation_date,
 | 
			
		||||
        'description': corpus.description,
 | 
			
		||||
        'status': corpus.status,
 | 
			
		||||
        'title': corpus.title
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['creation-date', {order: 'desc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><a class="btn-floating disabled"><i class="material-icons service-color darken" data-service="corpus-analysis">book</i></a></td>
 | 
			
		||||
@@ -46,28 +49,18 @@ class CorpusList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (corpus) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': corpus.id,
 | 
			
		||||
        'creation-date': corpus.creation_date,
 | 
			
		||||
        'description': corpus.description,
 | 
			
		||||
        'status': corpus.status,
 | 
			
		||||
        'title': corpus.title
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['creation-date', {order: 'desc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['creation-date']},
 | 
			
		||||
      {name: 'status', attr: 'data-corpus-status'},
 | 
			
		||||
        {name: 'status', attr: 'data-status'},
 | 
			
		||||
        'description',
 | 
			
		||||
        'title'
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...CorpusList.options, ...options});
 | 
			
		||||
    CorpusList.instances.push(this);
 | 
			
		||||
  constructor(listContainerElement, options={}) {
 | 
			
		||||
    super(listContainerElement, _.merge({}, CorpusList.options, options));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {
 | 
			
		||||
@@ -75,10 +68,12 @@ class CorpusList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onClick(event) {
 | 
			
		||||
    let corpusElement = event.target.closest('tr');
 | 
			
		||||
    if (corpusElement === null) {return;}
 | 
			
		||||
    let corpusId = corpusElement.dataset.id;
 | 
			
		||||
    if (corpusId === undefined) {return;}
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    let corpusElement = event.target.closest('tr');
 | 
			
		||||
    let corpusId = corpusElement.dataset.id;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete-request': {
 | 
			
		||||
        Utils.deleteCorpusRequest(this.userId, corpusId);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class JobInputList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search job input</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search job input</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -25,6 +25,15 @@ class JobInputList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (jobInput) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': jobInput.id,
 | 
			
		||||
        'creation-date': jobInput.creation_date,
 | 
			
		||||
        'filename': jobInput.filename
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['filename', {order: 'asc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><span class="filename"></span></td>
 | 
			
		||||
@@ -33,24 +42,17 @@ class JobInputList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (jobInput) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': jobInput.id,
 | 
			
		||||
        'creation-date': jobInput.creation_date,
 | 
			
		||||
        'filename': jobInput.filename
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['filename', {order: 'asc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['creation-date']},
 | 
			
		||||
        'filename'
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...JobInputList.options, ...options});
 | 
			
		||||
    this.jobId = listElement.dataset.jobId;
 | 
			
		||||
  constructor(listContainerElement, options={}) {
 | 
			
		||||
    super(listContainerElement, _.merge({}, JobInputList.options, options));
 | 
			
		||||
    this.jobId = listContainerElement.dataset.jobId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {
 | 
			
		||||
@@ -58,10 +60,12 @@ class JobInputList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onClick(event) {
 | 
			
		||||
    let jobInputElement = event.target.closest('tr');
 | 
			
		||||
    if (jobInputElement === null) {return;}
 | 
			
		||||
    let jobInputId = jobInputElement.dataset.id;
 | 
			
		||||
    if (jobInputId === undefined) {return;}
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button');
 | 
			
		||||
    let action = actionButtonElement === null ? 'download' : actionButtonElement.dataset.action;
 | 
			
		||||
    let jobInputElement = event.target.closest('tr');
 | 
			
		||||
    let jobInputId = jobInputElement.dataset.id;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'download': {
 | 
			
		||||
        window.location.href = `/jobs/${this.jobId}/inputs/${jobInputId}/download`;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class JobList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search job</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search job</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -27,44 +27,43 @@ class JobList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    item: `
 | 
			
		||||
      <tr class="clickable hoverable service-color lighten">
 | 
			
		||||
        <td><a class="btn-floating disabled"><i class="service-1 nopaque-icons service-color darken service-icon"></i></a></td>
 | 
			
		||||
        <td><b class="title"></b><br><i class="description"></i></td>
 | 
			
		||||
        <td><span class="status badge new job-status-color job-status-text" data-badge-caption=""></span></td>
 | 
			
		||||
        <td class="right-align">
 | 
			
		||||
          <a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
 | 
			
		||||
          <a class="action-button btn-floating service-color darken waves-effect waves-light service-2" data-action="view"><i class="material-icons">send</i></a>
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
    `.trim(),
 | 
			
		||||
    ressourceMapper: (job) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': job.id,
 | 
			
		||||
        'creation-date': job.creation_date,
 | 
			
		||||
        'description': job.description,
 | 
			
		||||
        'service': job.service,
 | 
			
		||||
        'service-1': job.service,
 | 
			
		||||
        'service-2': job.service,
 | 
			
		||||
        'status': job.status,
 | 
			
		||||
        'title': job.title
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['creation-date', {order: 'desc'}],
 | 
			
		||||
    sortParams: ['creation-date', {order: 'desc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable service-scheme">
 | 
			
		||||
          <td><a class="btn-floating"><i class="nopaque-icons service-icons" data-service="inherit"></i></a></td>
 | 
			
		||||
          <td><b class="title"></b><br><i class="description"></i></td>
 | 
			
		||||
          <td><span class="badge new job-status-color job-status-text status" data-badge-caption=""></span></td>
 | 
			
		||||
          <td class="right-align">
 | 
			
		||||
            <a class="action-button btn-floating red waves-effect waves-light" data-action="delete-request"><i class="material-icons">delete</i></a>
 | 
			
		||||
            <a class="action-button btn-floating darken waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['creation-date']},
 | 
			
		||||
        {data: ['service']},
 | 
			
		||||
      {name: 'service-1', attr: 'data-service'},
 | 
			
		||||
      {name: 'service-2', attr: 'data-service'},
 | 
			
		||||
      {name: 'status', attr: 'data-job-status'},
 | 
			
		||||
        {name: 'status', attr: 'data-status'},
 | 
			
		||||
        'description',
 | 
			
		||||
        'title'
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...JobList.options, ...options});
 | 
			
		||||
  constructor(listContainerElement, options={}) {
 | 
			
		||||
    super(listContainerElement, _.merge({}, JobList.options, options));
 | 
			
		||||
    console.log(this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {
 | 
			
		||||
@@ -72,10 +71,12 @@ class JobList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onClick(event) {
 | 
			
		||||
    let jobElement = event.target.closest('tr');
 | 
			
		||||
    if (jobElement === null) {return;}
 | 
			
		||||
    let jobId = jobElement.dataset.id;
 | 
			
		||||
    if (jobId === undefined) {return;}
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    let jobElement = event.target.closest('tr');
 | 
			
		||||
    let jobId = jobElement.dataset.id;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete-request': {
 | 
			
		||||
        Utils.deleteJobRequest(this.userId, jobId);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class JobResultList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search job result</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search job result</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -26,6 +26,16 @@ class JobResultList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (jobResult) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': jobResult.id,
 | 
			
		||||
        'creation-date': jobResult.creation_date,
 | 
			
		||||
        'description': jobResult.description,
 | 
			
		||||
        'filename': jobResult.filename
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['filename', {order: 'asc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><span class="description"></span></td>
 | 
			
		||||
@@ -35,26 +45,18 @@ class JobResultList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (jobResult) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': jobResult.id,
 | 
			
		||||
        'creation-date': jobResult.creation_date,
 | 
			
		||||
        'description': jobResult.description,
 | 
			
		||||
        'filename': jobResult.filename
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['filename', {order: 'asc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['creation-date']},
 | 
			
		||||
        'description',
 | 
			
		||||
        'filename'
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...JobResultList.options, ...options});
 | 
			
		||||
    this.jobId = listElement.dataset.jobId;
 | 
			
		||||
  constructor(listContainerElement, options = {}) {
 | 
			
		||||
    super(listContainerElement, {...JobResultList.options, ...options});
 | 
			
		||||
    this.jobId = listContainerElement.dataset.jobId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(user) {
 | 
			
		||||
@@ -62,10 +64,12 @@ class JobResultList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onClick(event) {
 | 
			
		||||
    let jobResultElement = event.target.closest('tr');
 | 
			
		||||
    if (jobResultElement === null) {return;}
 | 
			
		||||
    let jobResultId = jobResultElement.dataset.id;
 | 
			
		||||
    if (jobResultId === undefined) {return;}
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button');
 | 
			
		||||
    let action = actionButtonElement === null ? 'download' : actionButtonElement.dataset.action;
 | 
			
		||||
    let jobResultElement = event.target.closest('tr');
 | 
			
		||||
    let jobResultId = jobResultElement.dataset.id;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'download': {
 | 
			
		||||
        window.location.href = `/jobs/${this.jobId}/results/${jobResultId}/download`;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class PublicUserList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search user</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search user</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -30,6 +30,20 @@ class PublicUserList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (user) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': user.id,
 | 
			
		||||
        'member-since': user.member_since,
 | 
			
		||||
        'avatar': user.avatar ? `/profile/${user.id}/avatar` : '/static/images/user_avatar.png',
 | 
			
		||||
        'username': user.username,
 | 
			
		||||
        'full-name': user.full_name ? user.full_name : '',
 | 
			
		||||
        'location': user.location ? user.location : '',
 | 
			
		||||
        'organization': user.organization ? user.organization : '',
 | 
			
		||||
        'corpora-online': '0'
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['member-since', {order: 'desc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><img alt="user-image" class="circle responsive-img avatar" style="width:50%"></td>
 | 
			
		||||
@@ -43,19 +57,6 @@ class PublicUserList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (user) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': user.id,
 | 
			
		||||
        'member-since': user.member_since,
 | 
			
		||||
        'avatar': user.avatar ? `/profile/${user.id}/avatar` : '/static/images/user_avatar.png',
 | 
			
		||||
        'username': user.username,
 | 
			
		||||
        'full-name': user.full_name ? user.full_name : '',
 | 
			
		||||
        'location': user.location ? user.location : '',
 | 
			
		||||
        'organization': user.organization ? user.organization : '',
 | 
			
		||||
        'corpora-online': '0'
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['member-since', {order: 'desc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['member-since']},
 | 
			
		||||
@@ -66,10 +67,11 @@ class PublicUserList extends RessourceList {
 | 
			
		||||
        'organization',
 | 
			
		||||
        'corpora-online'
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...PublicUserList.options, ...options});
 | 
			
		||||
  constructor(listContainerElement, options = {}) {
 | 
			
		||||
    super(listContainerElement, {...PublicUserList.options, ...options});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(users) {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,38 +16,45 @@ class RessourceList {
 | 
			
		||||
    UserList.autoInit();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {page: 5, pagination: {innerWindow: 2, outerWindow: 2}};
 | 
			
		||||
  static options = {
 | 
			
		||||
    listContainerInnerHTMLGenerator: null,
 | 
			
		||||
    ressourceMapper: null,
 | 
			
		||||
    sortParams: null,
 | 
			
		||||
    listjs: {
 | 
			
		||||
      page: 5,
 | 
			
		||||
      pagination: {
 | 
			
		||||
        innerWindow: 2,
 | 
			
		||||
        outerWindow: 2
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    if (!(listElement.hasAttribute('id'))) {
 | 
			
		||||
  constructor(listContainerElement, options={}) {
 | 
			
		||||
    let mergedOptions = _.merge({}, RessourceList.options, options);
 | 
			
		||||
    this.isInitialized = false;
 | 
			
		||||
    this.listContainerInnerHTMLGenerator = mergedOptions.listContainerInnerHTMLGenerator;
 | 
			
		||||
    this.ressourceMapper = mergedOptions.ressourceMapper;
 | 
			
		||||
    this.sortParams = mergedOptions.sortParams;
 | 
			
		||||
    this.userId = listContainerElement.dataset.userId;
 | 
			
		||||
    // #region Make sure listElement has an id
 | 
			
		||||
    if (!listContainerElement.hasAttribute('id')) {
 | 
			
		||||
      let i;
 | 
			
		||||
      for (i = 0; true; i++) {
 | 
			
		||||
        if (document.querySelector(`#ressource-list-${i}`)) {continue;}
 | 
			
		||||
        listElement.id = `ressource-list-${i}`;
 | 
			
		||||
        listContainerElement.id = `ressource-list-${i}`;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    options = {
 | 
			
		||||
      ...RessourceList.options,
 | 
			
		||||
      ...options
 | 
			
		||||
    // #endregion
 | 
			
		||||
    if (this.listContainerInnerHTMLGenerator !== null && listContainerElement.textContent.trim() === '') {
 | 
			
		||||
      this.listContainerInnerHTMLGenerator(listContainerElement);
 | 
			
		||||
    }
 | 
			
		||||
    if ('ressourceMapper' in options && typeof options.ressourceMapper === 'function') {
 | 
			
		||||
      this.ressourceMapper = options.ressourceMapper;
 | 
			
		||||
      delete options.ressourceMapper;
 | 
			
		||||
    }
 | 
			
		||||
    if ('initialHtmlGenerator' in options && typeof options.initialHtmlGenerator === 'function') {
 | 
			
		||||
      this.initialHtmlGenerator = options.initialHtmlGenerator;
 | 
			
		||||
      listElement.innerHTML = this.initialHtmlGenerator(listElement.id);
 | 
			
		||||
      delete options.initialHtmlGenerator;
 | 
			
		||||
    }
 | 
			
		||||
    if ('sortArgs' in options) {
 | 
			
		||||
      this.sortArgs = options.sortArgs;
 | 
			
		||||
      delete options.sortArgs;
 | 
			
		||||
    }
 | 
			
		||||
    this.listjs = new List(listElement, {...RessourceList.options, ...options});
 | 
			
		||||
    this.listjs = new List(listContainerElement, mergedOptions.listjs);
 | 
			
		||||
    this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
 | 
			
		||||
    this.listjs.list.innerHTML = `
 | 
			
		||||
      <tr>
 | 
			
		||||
        <td class="row" colspan="100%">
 | 
			
		||||
        <td colspan="100%">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col s12"> </div>
 | 
			
		||||
            <div class="col s3 m2 xl1">
 | 
			
		||||
              <div class="preloader-wrapper active">
 | 
			
		||||
@@ -68,12 +75,10 @@ class RessourceList {
 | 
			
		||||
              <span class="card-title">Waiting for data...</span>
 | 
			
		||||
              <p>This list is not initialized yet.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
    `.trim();
 | 
			
		||||
    this.userId = this.listjs.listContainer.dataset.userId;
 | 
			
		||||
    this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
 | 
			
		||||
    this.isInitialized = false;
 | 
			
		||||
    if (this.userId) {
 | 
			
		||||
      app.subscribeUser(this.userId)
 | 
			
		||||
        .then((response) => {
 | 
			
		||||
@@ -113,12 +118,12 @@ class RessourceList {
 | 
			
		||||
 | 
			
		||||
  add(ressources) {
 | 
			
		||||
    let values = Array.isArray(ressources) ? ressources : [ressources];
 | 
			
		||||
    if ('ressourceMapper' in this) {
 | 
			
		||||
    if (this.ressourceMapper !== null) {
 | 
			
		||||
      values = values.map((value) => {return this.ressourceMapper(value);});
 | 
			
		||||
    }
 | 
			
		||||
    this.listjs.add(values, () => {
 | 
			
		||||
      if ('sortArgs' in this) {
 | 
			
		||||
        this.listjs.sort(...this.sortArgs);
 | 
			
		||||
      if (this.sortParams !== null) {
 | 
			
		||||
        this.listjs.sort(...this.sortParams);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class SpaCyNLPPipelineModelList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search SpaCy NLP Pipeline Model</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search SpaCy NLP Pipeline Model</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -26,6 +26,24 @@ class SpaCyNLPPipelineModelList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (spaCyNLPPipelineModel) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': spaCyNLPPipelineModel.id,
 | 
			
		||||
        'creation-date': spaCyNLPPipelineModel.creation_date,
 | 
			
		||||
        'description': spaCyNLPPipelineModel.description,
 | 
			
		||||
        'publisher': spaCyNLPPipelineModel.publisher,
 | 
			
		||||
        'publisher-url': spaCyNLPPipelineModel.publisher_url,
 | 
			
		||||
        'publishing-url': spaCyNLPPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-url-2': spaCyNLPPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-year': spaCyNLPPipelineModel.publishing_year,
 | 
			
		||||
        'title': spaCyNLPPipelineModel.title,
 | 
			
		||||
        'title-2': spaCyNLPPipelineModel.title,
 | 
			
		||||
        'version': spaCyNLPPipelineModel.version,
 | 
			
		||||
        'is_public': spaCyNLPPipelineModel.is_public ? 'True' : 'False'
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['creation-date', {order: 'desc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><b><span class="title"></span> <span class="version"></span></b><br><i><span class="description"></span></i></td>
 | 
			
		||||
@@ -46,23 +64,6 @@ class SpaCyNLPPipelineModelList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (spaCyNLPPipelineModel) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': spaCyNLPPipelineModel.id,
 | 
			
		||||
        'creation-date': spaCyNLPPipelineModel.creation_date,
 | 
			
		||||
        'description': spaCyNLPPipelineModel.description,
 | 
			
		||||
        'publisher': spaCyNLPPipelineModel.publisher,
 | 
			
		||||
        'publisher-url': spaCyNLPPipelineModel.publisher_url,
 | 
			
		||||
        'publishing-url': spaCyNLPPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-url-2': spaCyNLPPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-year': spaCyNLPPipelineModel.publishing_year,
 | 
			
		||||
        'title': spaCyNLPPipelineModel.title,
 | 
			
		||||
        'title-2': spaCyNLPPipelineModel.title,
 | 
			
		||||
        'version': spaCyNLPPipelineModel.version,
 | 
			
		||||
        'is_public': spaCyNLPPipelineModel.is_public ? 'True' : 'False'
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['creation-date', {order: 'desc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['creation-date']},
 | 
			
		||||
@@ -77,10 +78,11 @@ class SpaCyNLPPipelineModelList extends RessourceList {
 | 
			
		||||
        'version',
 | 
			
		||||
        {name: 'is_public', attr: 'data-checked'}
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...SpaCyNLPPipelineModelList.options, ...options});
 | 
			
		||||
  constructor(listContainerElement, options = {}) {
 | 
			
		||||
    super(listContainerElement, {...SpaCyNLPPipelineModelList.options, ...options});
 | 
			
		||||
    this.listjs.list.addEventListener('change', (event) => {this.onChange(event)});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class TesseractOCRPipelineModelList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search Tesseract OCR Pipeline Model</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search Tesseract OCR Pipeline Model</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -26,6 +26,24 @@ class TesseractOCRPipelineModelList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (tesseractOCRPipelineModel) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': tesseractOCRPipelineModel.id,
 | 
			
		||||
        'creation-date': tesseractOCRPipelineModel.creation_date,
 | 
			
		||||
        'description': tesseractOCRPipelineModel.description,
 | 
			
		||||
        'publisher': tesseractOCRPipelineModel.publisher,
 | 
			
		||||
        'publisher-url': tesseractOCRPipelineModel.publisher_url,
 | 
			
		||||
        'publishing-url': tesseractOCRPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-url-2': tesseractOCRPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-year': tesseractOCRPipelineModel.publishing_year,
 | 
			
		||||
        'title': tesseractOCRPipelineModel.title,
 | 
			
		||||
        'title-2': tesseractOCRPipelineModel.title,
 | 
			
		||||
        'version': tesseractOCRPipelineModel.version,
 | 
			
		||||
        'is_public': tesseractOCRPipelineModel.is_public ? 'True' : 'False'
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['creation-date', {order: 'desc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><b><span class="title"></span> <span class="version"></span></b><br><i><span class="description"></span></i></td>
 | 
			
		||||
@@ -46,23 +64,6 @@ class TesseractOCRPipelineModelList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (tesseractOCRPipelineModel) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': tesseractOCRPipelineModel.id,
 | 
			
		||||
        'creation-date': tesseractOCRPipelineModel.creation_date,
 | 
			
		||||
        'description': tesseractOCRPipelineModel.description,
 | 
			
		||||
        'publisher': tesseractOCRPipelineModel.publisher,
 | 
			
		||||
        'publisher-url': tesseractOCRPipelineModel.publisher_url,
 | 
			
		||||
        'publishing-url': tesseractOCRPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-url-2': tesseractOCRPipelineModel.publishing_url,
 | 
			
		||||
        'publishing-year': tesseractOCRPipelineModel.publishing_year,
 | 
			
		||||
        'title': tesseractOCRPipelineModel.title,
 | 
			
		||||
        'title-2': tesseractOCRPipelineModel.title,
 | 
			
		||||
        'version': tesseractOCRPipelineModel.version,
 | 
			
		||||
        'is_public': tesseractOCRPipelineModel.is_public ? 'True' : 'False'
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['creation-date', {order: 'desc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['creation-date']},
 | 
			
		||||
@@ -77,10 +78,11 @@ class TesseractOCRPipelineModelList extends RessourceList {
 | 
			
		||||
        'version',
 | 
			
		||||
        {name: 'is_public', attr: 'data-checked'}
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...TesseractOCRPipelineModelList.options, ...options});
 | 
			
		||||
  constructor(listContainerElement, options = {}) {
 | 
			
		||||
    super(listContainerElement, {...TesseractOCRPipelineModelList.options, ...options});
 | 
			
		||||
    this.listjs.list.addEventListener('change', (event) => {this.onChange(event)});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ class UserList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static options = {
 | 
			
		||||
    initialHtmlGenerator: (id) => {
 | 
			
		||||
      return `
 | 
			
		||||
    listContainerInnerHTMLGenerator: (listContainerElement) => {
 | 
			
		||||
      listContainerElement.innerHTML = `
 | 
			
		||||
        <div class="input-field">
 | 
			
		||||
          <i class="material-icons prefix">search</i>
 | 
			
		||||
          <input id="${id}-search" class="search" type="search"></input>
 | 
			
		||||
          <label for="${id}-search">Search user</label>
 | 
			
		||||
          <input id="${listContainerElement.id}-search" class="search" type="text"></input>
 | 
			
		||||
          <label for="${listContainerElement.id}-search">Search user</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <table>
 | 
			
		||||
          <thead>
 | 
			
		||||
@@ -29,6 +29,19 @@ class UserList extends RessourceList {
 | 
			
		||||
        <ul class="pagination"></ul>
 | 
			
		||||
      `.trim();
 | 
			
		||||
    },
 | 
			
		||||
    ressourceMapper: (user) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': user.id,
 | 
			
		||||
        'id-1': user.id,
 | 
			
		||||
        'username': user.username,
 | 
			
		||||
        'email': user.email,
 | 
			
		||||
        'last-seen': new Date(user.last_seen).toLocaleString('en-US'),
 | 
			
		||||
        'member-since': user.member_since,
 | 
			
		||||
        'role': user.role.name
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortParams: ['member-since', {order: 'desc'}],
 | 
			
		||||
    listjs: {
 | 
			
		||||
      item: `
 | 
			
		||||
        <tr class="clickable hoverable">
 | 
			
		||||
          <td><span class="id-1"></span></td>
 | 
			
		||||
@@ -43,18 +56,6 @@ class UserList extends RessourceList {
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      `.trim(),
 | 
			
		||||
    ressourceMapper: (user) => {
 | 
			
		||||
      return {
 | 
			
		||||
        'id': user.id,
 | 
			
		||||
        'id-1': user.id,
 | 
			
		||||
        'username': user.username,
 | 
			
		||||
        'email': user.email,
 | 
			
		||||
        'last-seen': new Date(user.last_seen).toLocaleString('en-US'),
 | 
			
		||||
        'member-since': user.member_since,
 | 
			
		||||
        'role': user.role.name
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    sortArgs: ['member-since', {order: 'desc'}],
 | 
			
		||||
      valueNames: [
 | 
			
		||||
        {data: ['id']},
 | 
			
		||||
        {data: ['member-since']},
 | 
			
		||||
@@ -64,10 +65,11 @@ class UserList extends RessourceList {
 | 
			
		||||
        'role',
 | 
			
		||||
        'username'
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(listElement, options = {}) {
 | 
			
		||||
    super(listElement, {...UserList.options, ...options});
 | 
			
		||||
  constructor(listContainerElement, options = {}) {
 | 
			
		||||
    super(listContainerElement, {...UserList.options, ...options});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(users) {
 | 
			
		||||
@@ -75,10 +77,12 @@ class UserList extends RessourceList {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onClick(event) {
 | 
			
		||||
    let userElement = event.target.closest('tr');
 | 
			
		||||
    if (userElement === null) {return;}
 | 
			
		||||
    let userId = userElement.dataset.id;
 | 
			
		||||
    if (userId === undefined) {return;}
 | 
			
		||||
    let actionButtonElement = event.target.closest('.action-button');
 | 
			
		||||
    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
 | 
			
		||||
    let userElement = event.target.closest('tr');
 | 
			
		||||
    let userId = userElement.dataset.id;
 | 
			
		||||
    switch (action) {
 | 
			
		||||
      case 'delete': {
 | 
			
		||||
        Utils.deleteUserRequest(userId);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fast-json-patch/3.1.1/fast-json-patch.min.js" integrity="sha512-5uDdefwnzyq4N+SkmMBmekZLZNmc6dLixvVxCdlHBfqpyz0N3bzLdrJ55OLm7QrZmgZuhLGgHLDtJwU6RZoFCA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 | 
			
		||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js" integrity="sha512-93wYgwrIFL+b+P3RvYxi/WUFRXXUDSLCT2JQk9zhVGXuS2mHl2axj6d+R6pP+gcU5isMHRj1u0oYE/mWyt/RjA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 | 
			
		||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 | 
			
		||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.min.js" integrity="sha512-mHO4BJ0ELk7Pb1AzhTi3zvUeRgq3RXVOu9tTRfnA6qOxGK4pG2u57DJYolI4KrEnnLTcH9/J5wNOozRTDaybXg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 | 
			
		||||
{%- assets
 | 
			
		||||
  filters='rjsmin',
 | 
			
		||||
@@ -38,17 +39,19 @@
 | 
			
		||||
  const currentUserId = {{ current_user.hashid|tojson }};
 | 
			
		||||
 | 
			
		||||
  // Initialize components for current user
 | 
			
		||||
  app.subscribeUser(currentUserId).catch((error) => {throw JSON.stringify(error);});
 | 
			
		||||
  app.getUser(currentUserId, true, true);
 | 
			
		||||
  app.subscribeUser(currentUserId)
 | 
			
		||||
    .catch((error) => {throw JSON.stringify(error);});
 | 
			
		||||
  app.getUser(currentUserId, true, true)
 | 
			
		||||
    .catch((error) => {throw JSON.stringify(error);});
 | 
			
		||||
  {%- endif %}
 | 
			
		||||
 | 
			
		||||
  // Disable all option elements with no value
 | 
			
		||||
  for (let optionElementWithoutValue of document.querySelectorAll('option[value=""]')) {
 | 
			
		||||
    optionElementWithoutValue.disabled = true;
 | 
			
		||||
  for (let optionElement of document.querySelectorAll('option[value=""]')) {
 | 
			
		||||
    optionElement.disabled = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Set the data-length attribute on inputs with the maxlength attribute
 | 
			
		||||
  for (let inputElement of document.querySelectorAll('input[maxlength], textarea[maxlength]')) {
 | 
			
		||||
  // Set the data-length attribute on textareas/inputs with the maxlength attribute
 | 
			
		||||
  for (let inputElement of document.querySelectorAll('textarea[maxlength], input[maxlength]')) {
 | 
			
		||||
    inputElement.dataset.length = inputElement.getAttribute('maxlength');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -63,7 +66,7 @@
 | 
			
		||||
  Form.autoInit();
 | 
			
		||||
 | 
			
		||||
  // Display flashed messages
 | 
			
		||||
  for (let flashedMessage of {{ get_flashed_messages(with_categories=True)|tojson }}) {
 | 
			
		||||
    app.flash(flashedMessage[1], flashedMessage[0]);
 | 
			
		||||
  for (let [category, message] of {{ get_flashed_messages(with_categories=True)|tojson }}) {
 | 
			
		||||
    app.flash(message, message);
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -24,13 +24,13 @@
 | 
			
		||||
  <li><a href="{{ url_for('contributions.contributions') }}"><i class="material-icons">new_label</i>Contribute</a></li>
 | 
			
		||||
  <li><div class="divider"></div></li>
 | 
			
		||||
  <li><a class="subheader">Processes & Services</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="file-setup-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.file_setup_pipeline') }}"><i class="nopaque-icons service-icon" data-service="file-setup-pipeline"></i>File setup</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="tesseract-ocr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.tesseract_ocr_pipeline') }}"><i class="nopaque-icons service-icon" data-service="tesseract-ocr-pipeline"></i>OCR</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="file-setup-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.file_setup_pipeline') }}"><i class="nopaque-icons service-icons" data-service="file-setup-pipeline"></i>File setup</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="tesseract-ocr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.tesseract_ocr_pipeline') }}"><i class="nopaque-icons service-icons" data-service="tesseract-ocr-pipeline"></i>OCR</a></li>
 | 
			
		||||
  {% if config.NOPAQUE_TRANSKRIBUS_ENABLED %}
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="transkribus-htr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.transkribus_htr_pipeline') }}"><i class="nopaque-icons service-icon" data-service="transkribus-htr-pipeline"></i>HTR</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="transkribus-htr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.transkribus_htr_pipeline') }}"><i class="nopaque-icons service-icons" data-service="transkribus-htr-pipeline"></i>HTR</a></li>
 | 
			
		||||
  {% endif %}
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="spacy-nlp-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.spacy_nlp_pipeline') }}"><i class="nopaque-icons service-icon" data-service="spacy-nlp-pipeline"></i>NLP</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="corpus-analysis" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.corpus_analysis') }}"><i class="nopaque-icons service-icon" data-service="corpus-analysis"></i>Corpus analysis</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="spacy-nlp-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.spacy_nlp_pipeline') }}"><i class="nopaque-icons service-icons" data-service="spacy-nlp-pipeline"></i>NLP</a></li>
 | 
			
		||||
  <li class="service-color service-color-border border-darken" data-service="corpus-analysis" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.corpus_analysis') }}"><i class="nopaque-icons service-icons" data-service="corpus-analysis"></i>Corpus analysis</a></li>
 | 
			
		||||
  <li><div class="divider"></div></li>
 | 
			
		||||
  <li><a class="subheader">Account</a></li>
 | 
			
		||||
  <li><a href="{{ url_for('settings.settings') }}"><i class="material-icons">settings</i>General Settings</a></li>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
      <div class="card extension-selector hoverable service-color" data-service="tesseract-ocr-pipeline">
 | 
			
		||||
        <a href="{{ url_for('.tesseract_ocr_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a>
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <span class="card-title" data-service="tesseract-ocr-pipeline"><i class="nopaque-icons service-icon" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline Models</span>
 | 
			
		||||
          <span class="card-title" data-service="tesseract-ocr-pipeline"><i class="nopaque-icons service-icons" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline Models</span>
 | 
			
		||||
          <p>Here you can see and edit the models that you have created. You can also create new models.</p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
      <div class="card extension-selector hoverable service-color" data-service="spacy-nlp-pipeline">
 | 
			
		||||
      <a href="{{ url_for('.spacy_nlp_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a>
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <span class="card-title"><i class="nopaque-icons service-icon" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline Models</span>
 | 
			
		||||
          <span class="card-title"><i class="nopaque-icons service-icons" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline Models</span>
 | 
			
		||||
          <p>Here you can see and edit the models that you have created. You can also create new models.</p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
      <div class="card extension-selector hoverable service-color" data-service="transkribus-htr-pipeline">
 | 
			
		||||
      <a href="" style="position: absolute; width: 100%; height: 100%;"></a>
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <span class="card-title"><i class="nopaque-icons service-icon" data-service="transkribus-htr-pipeline"></i>Transkribus HTR Pipeline Models</span>
 | 
			
		||||
          <span class="card-title"><i class="nopaque-icons service-icons" data-service="transkribus-htr-pipeline"></i>Transkribus HTR Pipeline Models</span>
 | 
			
		||||
          <p>Here you can see and edit the models that you have created. You can also create new models.</p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline"></i>
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline"></i>
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
{% block page_content %}
 | 
			
		||||
<ul class="row tabs no-autoinit" id="corpus-analysis-app-extension-tabs">
 | 
			
		||||
  <li class="tab col s3"><a class="active" href="#corpus-analysis-app-overview"><i class="nopaque-icons service-icon left" data-service="corpus-analysis"></i>Corpus analysis</a></li>
 | 
			
		||||
  <li class="tab col s3"><a class="active" href="#corpus-analysis-app-overview"><i class="nopaque-icons service-icons left" data-service="corpus-analysis"></i>Corpus analysis</a></li>
 | 
			
		||||
  <li class="tab col s3"><a href="#concordance-extension-container"><i class="material-icons left">list_alt</i>Concordance</a></li>
 | 
			
		||||
  <li class="tab col s3"><a href="#reader-extension-container"><i class="material-icons left">chrome_reader_mode</i>Reader</a></li>
 | 
			
		||||
</ul>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <div class="col s12" data-job-id="{{ job.hashid }}" data-user-id="{{ job.user.hashid }}" id="job-display">
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <div class="col s8 m9 l10">
 | 
			
		||||
          <h1 id="title"><i style="font-size: inherit;" class="nopaque-icons service-icon" data-service="{{ job.service }}"></i> <span class="job-title"></span></h1>
 | 
			
		||||
          <h1 id="title"><i style="font-size: inherit;" class="nopaque-icons service-icons" data-service="{{ job.service }}"></i> <span class="job-title"></span></h1>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col s4 m3 l2 right-align">
 | 
			
		||||
          <p> </p>
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@
 | 
			
		||||
          <div class="card-panel center-align hoverable">
 | 
			
		||||
            <br>
 | 
			
		||||
            <a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i>
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
            <br><br>
 | 
			
		||||
            <p class="service-color-text darken" data-service="file-setup-pipeline"><b>File setup</b></p>
 | 
			
		||||
@@ -94,7 +94,7 @@
 | 
			
		||||
          <div class="card-panel center-align hoverable">
 | 
			
		||||
            <br>
 | 
			
		||||
            <a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
            <br><br>
 | 
			
		||||
            <p class="service-color-text darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p>
 | 
			
		||||
@@ -106,7 +106,7 @@
 | 
			
		||||
          <div class="card-panel center-align hoverable">
 | 
			
		||||
            <br>
 | 
			
		||||
            <a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
            <br><br>
 | 
			
		||||
            <p class="service-color-text darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p>
 | 
			
		||||
 
 | 
			
		||||
@@ -220,7 +220,7 @@
 | 
			
		||||
          <div class="card-panel center-align hoverable">
 | 
			
		||||
            <br>
 | 
			
		||||
            <a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i>
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
            <br><br>
 | 
			
		||||
            <p class="service-color-text darken" data-service="file-setup-pipeline"><b>File setup</b></p>
 | 
			
		||||
@@ -232,7 +232,7 @@
 | 
			
		||||
          <div class="card-panel center-align hoverable">
 | 
			
		||||
            <br>
 | 
			
		||||
            <a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
            <br><br>
 | 
			
		||||
            <p class="service-color-text darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p>
 | 
			
		||||
@@ -244,7 +244,7 @@
 | 
			
		||||
          <div class="card-panel center-align hoverable">
 | 
			
		||||
            <br>
 | 
			
		||||
            <a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large waves-effect waves-light" style="transform: scale(2);">
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
              <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline" style="font-size: 2.5rem;"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
            <br><br>
 | 
			
		||||
            <p class="service-color-text darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p>
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@
 | 
			
		||||
            <div class="col s12 m6 l3 center-align">
 | 
			
		||||
              <p> </p>
 | 
			
		||||
              <a href="{{ url_for('services.file_setup_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i>
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
 | 
			
		||||
              </a>
 | 
			
		||||
              <br><br>
 | 
			
		||||
              <p class="service-color-text text-darken" data-service="file-setup-pipeline"><b>File setup</b></p>
 | 
			
		||||
@@ -86,7 +86,7 @@
 | 
			
		||||
            <div class="col s12 m6 l3 center-align">
 | 
			
		||||
              <p> </p>
 | 
			
		||||
              <a href="{{ url_for('services.tesseract_ocr_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline"></i>
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline"></i>
 | 
			
		||||
              </a>
 | 
			
		||||
              <br><br>
 | 
			
		||||
              <p class="service-color-text text-darken" data-service="tesseract-ocr-pipeline"><b>Optical Character Recognition</b></p>
 | 
			
		||||
@@ -95,7 +95,7 @@
 | 
			
		||||
            <div class="col s12 m6 l3 center-align">
 | 
			
		||||
              <p> </p>
 | 
			
		||||
              <a href="{{ url_for('services.transkribus_htr_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icon" data-service="transkribus-htr-pipeline"></i>
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icons" data-service="transkribus-htr-pipeline"></i>
 | 
			
		||||
              </a>
 | 
			
		||||
              <br><br>
 | 
			
		||||
              <p class="service-color-text text-darken" data-service="transkribus-htr-pipeline"><b>Transkribus HTR Pipeline</b></p>
 | 
			
		||||
@@ -104,7 +104,7 @@
 | 
			
		||||
            <div class="col s12 m6 l3 center-align">
 | 
			
		||||
              <p> </p>
 | 
			
		||||
              <a href="{{ url_for('services.spacy_nlp_pipeline') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline"></i>
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline"></i>
 | 
			
		||||
              </a>
 | 
			
		||||
              <br><br>
 | 
			
		||||
              <p class="service-color-text text-darken" data-service="spacy-nlp-pipeline"><b>Natural Language Processing</b></p>
 | 
			
		||||
@@ -113,7 +113,7 @@
 | 
			
		||||
            <div class="col s12 m6 l3 center-align">
 | 
			
		||||
              <p> </p>
 | 
			
		||||
              <a href="{{ url_for('services.corpus_analysis') }}" class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icon" data-service="corpus-analysis"></i>
 | 
			
		||||
                <i class="nopaque-icons service-color darken service-icons" data-service="corpus-analysis"></i>
 | 
			
		||||
              </a>
 | 
			
		||||
              <br><br>
 | 
			
		||||
              <p class="service-color-text text-darken" data-service="corpus-analysis"><b>Corpus analysis</b></p>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
    <div class="col s12 m3 push-m9">
 | 
			
		||||
      <div class="center-align">
 | 
			
		||||
        <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light" style="transform: scale(2);">
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icon" data-service="corpus-analysis"></i>
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icons" data-service="corpus-analysis"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icon" data-service="file-setup-pipeline"></i>
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icons" data-service="file-setup-pipeline"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline"></i>
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icons" data-service="spacy-nlp-pipeline"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icon" data-service="tesseract-ocr-pipeline"></i>
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icons" data-service="tesseract-ocr-pipeline"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <p class="hide-on-small-only"> </p>
 | 
			
		||||
        <a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icon" data-service="transkribus-htr-pipeline"></i>
 | 
			
		||||
          <i class="nopaque-icons service-color darken service-icons" data-service="transkribus-htr-pipeline"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user