From 03a57fd7eef987606a1d84eb64b26352e0c5c7fc Mon Sep 17 00:00:00 2001 From: Patrick Jentsch Date: Thu, 2 Dec 2021 16:25:48 +0100 Subject: [PATCH] Create a proper class for the upload form --- .../nopaque/RessourceLists/CorpusFileList.js | 34 ++-- .../js/nopaque/RessourceLists/CorpusList.js | 30 ++-- .../js/nopaque/RessourceLists/JobInputList.js | 24 +-- .../js/nopaque/RessourceLists/JobList.js | 30 ++-- .../nopaque/RessourceLists/JobResultList.js | 26 +-- .../nopaque/RessourceLists/QueryResultList.js | 28 ++-- .../nopaque/RessourceLists/RessourceList.js | 36 +++- .../js/nopaque/RessourceLists/UserList.js | 37 +++-- app/static/js/nopaque/UploadForm.js | 125 ++++++++++++++ app/static/js/nopaque/main.js | 155 ------------------ app/templates/_scripts.html.j2 | 6 +- app/templates/corpora/add_corpus_file.html.j2 | 2 +- app/templates/corpora/import_corpus.html.j2 | 2 +- app/templates/services/file_setup.html.j2 | 17 +- app/templates/services/nlp.html.j2 | 2 +- app/templates/services/ocr.html.j2 | 2 +- 16 files changed, 280 insertions(+), 276 deletions(-) create mode 100644 app/static/js/nopaque/UploadForm.js delete mode 100644 app/static/js/nopaque/main.js diff --git a/app/static/js/nopaque/RessourceLists/CorpusFileList.js b/app/static/js/nopaque/RessourceLists/CorpusFileList.js index e49ee8fa..a7a663b3 100644 --- a/app/static/js/nopaque/RessourceLists/CorpusFileList.js +++ b/app/static/js/nopaque/RessourceLists/CorpusFileList.js @@ -1,4 +1,22 @@ class CorpusFileList extends RessourceList { + static options = { + item: ` + + + + + + + delete + file_download + send + + + `.trim(), + valueNames: [{data: ['id']}, 'author', 'filename', 'publishing_year', 'title'] + }; + + constructor(listElement, options = {}) { super(listElement, {...CorpusFileList.options, ...options}); this.corpusId = listElement.dataset.corpusId; @@ -109,19 +127,3 @@ class CorpusFileList extends RessourceList { }; } } -CorpusFileList.options = { - item: ` - - - - - - - delete - file_download - send - - - `.trim(), - valueNames: [{data: ['id']}, 'author', 'filename', 'publishing_year', 'title'] -}; diff --git a/app/static/js/nopaque/RessourceLists/CorpusList.js b/app/static/js/nopaque/RessourceLists/CorpusList.js index 156623d3..749ee73f 100644 --- a/app/static/js/nopaque/RessourceLists/CorpusList.js +++ b/app/static/js/nopaque/RessourceLists/CorpusList.js @@ -1,4 +1,20 @@ class CorpusList extends RessourceList { + static options = { + item: ` + + book +
+ + + delete + send + + + `.trim(), + valueNames: [{data: ['id']}, {name: 'status', attr: 'data-status'}, 'description', 'title'] + }; + + constructor(listElement, options = {}) { super(listElement, {...CorpusList.options, ...options}); } @@ -102,17 +118,3 @@ class CorpusList extends RessourceList { }; } } -CorpusList.options = { - item: ` - - book -
- - - delete - send - - - `.trim(), - valueNames: [{data: ['id']}, {name: 'status', attr: 'data-status'}, 'description', 'title'] -}; diff --git a/app/static/js/nopaque/RessourceLists/JobInputList.js b/app/static/js/nopaque/RessourceLists/JobInputList.js index 4fed368e..d537a797 100644 --- a/app/static/js/nopaque/RessourceLists/JobInputList.js +++ b/app/static/js/nopaque/RessourceLists/JobInputList.js @@ -1,4 +1,17 @@ class JobInputList extends RessourceList { + static options = { + item: ` + + + + file_download + + + `.trim(), + valueNames: [{data: ['id']}, 'filename'] + }; + + constructor(listElement, options = {}) { super(listElement, {...JobInputList.options, ...options}); this.jobId = listElement.dataset.jobId; @@ -39,14 +52,3 @@ class JobInputList extends RessourceList { }; } } -JobInputList.options = { - item: ` - - - - file_download - - - `.trim(), - valueNames: [{data: ['id']}, 'filename'] -}; diff --git a/app/static/js/nopaque/RessourceLists/JobList.js b/app/static/js/nopaque/RessourceLists/JobList.js index 9dc19ec6..6562d072 100644 --- a/app/static/js/nopaque/RessourceLists/JobList.js +++ b/app/static/js/nopaque/RessourceLists/JobList.js @@ -1,4 +1,20 @@ class JobList extends RessourceList { + static options = { + item: ` + + +
+ + + delete + send + + + `.trim(), + valueNames: [{data: ['id']}, {name: 'service', attr: 'data-service'}, {name: 'status', attr: 'data-status'}, 'description', 'title'] + }; + + constructor(listElement, options = {}) { super(listElement, {...JobList.options, ...options}); } @@ -105,17 +121,3 @@ class JobList extends RessourceList { }; } } -JobList.options = { - item: ` - - -
- - - delete - send - - - `.trim(), - valueNames: [{data: ['id']}, {name: 'service', attr: 'data-service'}, {name: 'status', attr: 'data-status'}, 'description', 'title'] -}; diff --git a/app/static/js/nopaque/RessourceLists/JobResultList.js b/app/static/js/nopaque/RessourceLists/JobResultList.js index 0dab71cc..4413b30d 100644 --- a/app/static/js/nopaque/RessourceLists/JobResultList.js +++ b/app/static/js/nopaque/RessourceLists/JobResultList.js @@ -1,4 +1,18 @@ class JobResultList extends RessourceList { + static options = { + item: ` + + + + + file_download + + + `.trim(), + valueNames: [{data: ['id']}, 'description', 'filename'] + }; + + constructor(listElement, options = {}) { super(listElement, {...JobResultList.options, ...options}); this.jobId = listElement.dataset.jobId; @@ -74,15 +88,3 @@ class JobResultList extends RessourceList { }; } } -JobResultList.options = { - item: ` - - - - - file_download - - - `.trim(), - valueNames: [{data: ['id']}, 'description', 'filename'] -}; diff --git a/app/static/js/nopaque/RessourceLists/QueryResultList.js b/app/static/js/nopaque/RessourceLists/QueryResultList.js index 302967aa..43baafeb 100644 --- a/app/static/js/nopaque/RessourceLists/QueryResultList.js +++ b/app/static/js/nopaque/RessourceLists/QueryResultList.js @@ -1,4 +1,19 @@ class QueryResultList extends RessourceList { + static options = { + item: ` + +

+
+ + delete + send + + + `.trim(), + valueNames: [{data: ['id']}, 'corpus_title', 'description', 'query', 'title'] + }; + + constructor(listElement, options = {}) { super(listElement, {...QueryResultList.options, ...options}); } @@ -105,16 +120,3 @@ class QueryResultList extends RessourceList { }; } } -QueryResultList.options = { - item: ` - -

-
- - delete - send - - - `.trim(), - valueNames: [{data: ['id']}, 'corpus_title', 'description', 'query', 'title'] -}; diff --git a/app/static/js/nopaque/RessourceLists/RessourceList.js b/app/static/js/nopaque/RessourceLists/RessourceList.js index 442f25c9..f5bebd76 100644 --- a/app/static/js/nopaque/RessourceLists/RessourceList.js +++ b/app/static/js/nopaque/RessourceLists/RessourceList.js @@ -3,6 +3,41 @@ class RessourceList { * This class is not meant to be used directly, instead it should be used as * a base class for concrete ressource list implementations. */ + static autoInit() { + const nopaqueRessourceListElements = document.querySelectorAll('.nopaque-ressource-list[data-ressource-type]:not(.no-autoinit)'); + let nopaqueRessourceListElement; + + for (nopaqueRessourceListElement of nopaqueRessourceListElements) { + switch (nopaqueRessourceListElement.dataset.ressourceType) { + case 'Corpus': + new CorpusList(nopaqueRessourceListElement); + break; + case 'CorpusFile': + new CorpusFileList(nopaqueRessourceListElement); + break; + case 'Job': + new JobList(nopaqueRessourceListElement); + break; + case 'JobInput': + new JobInputList(nopaqueRessourceListElement); + break; + case 'JobResult': + new JobResultList(nopaqueRessourceListElement); + break; + case 'QueryResult': + new QueryResultList(nopaqueRessourceListElement); + break; + case 'User': + new UserList(nopaqueRessourceListElement); + break; + default: + break; + } + } + } + static options = {page: 5, pagination: [{innerWindow: 4, outerWindow: 1}]}; + + constructor(listElement, options = {}) { let i; @@ -88,4 +123,3 @@ class RessourceList { this.listjs.get('id', id)[0].values({[valueName]: newValue}); } } -RessourceList.options = {page: 5, pagination: [{innerWindow: 4, outerWindow: 1}]}; diff --git a/app/static/js/nopaque/RessourceLists/UserList.js b/app/static/js/nopaque/RessourceLists/UserList.js index 24b26ad3..37d3f4ed 100644 --- a/app/static/js/nopaque/RessourceLists/UserList.js +++ b/app/static/js/nopaque/RessourceLists/UserList.js @@ -1,4 +1,24 @@ class UserList extends RessourceList { + static options = { + item: ` + + + + + + + + delete + edit + send + + + `.trim(), + valueNames: [{data: ['id']}, 'id_', 'username', 'email', 'last_seen', 'role'] + }; + + + constructor(listElement, options = {}) { super(listElement, {...UserList.options, ...options}); } @@ -70,20 +90,3 @@ class UserList extends RessourceList { }; } } -UserList.options = { - item: ` - - - - - - - - delete - edit - send - - - `.trim(), - valueNames: [{data: ['id']}, 'id_', 'username', 'email', 'last_seen', 'role'] -}; diff --git a/app/static/js/nopaque/UploadForm.js b/app/static/js/nopaque/UploadForm.js new file mode 100644 index 00000000..2a1df808 --- /dev/null +++ b/app/static/js/nopaque/UploadForm.js @@ -0,0 +1,125 @@ +class UploadForm { + static autoInit() { + const nopaqueSubmitForms = document.querySelectorAll('.nopaque-upload-form'); + let nopaqueSubmitForm; + + for (nopaqueSubmitForm of nopaqueSubmitForms) { + new UploadForm(nopaqueSubmitForm); + } + } + + + constructor(formElement) { + this.formElement = formElement; + this.request = new XMLHttpRequest(); + + this.formElement.addEventListener('submit', (event) => { + event.preventDefault(); + this.submit(); + }); + } + + submit() { + const selectElements = this.formElement.querySelectorAll('select'); + let abortElement; + let helperTextElement; + let helperTextElements; + let inputFieldElement; + let modal; + let modalElement; + let progressElement; + let selectElement; + let tmp; + + // Check if select elements are filled out properly + for (selectElement of selectElements) { + if (selectElement.value === '') { + inputFieldElement = selectElement.closest('.input-field'); + inputFieldElement.querySelector('.select-dropdown').classList.add('invalid'); + helperTextElements = inputFieldElement.querySelectorAll('.helper-text'); + for (helperTextElement of helperTextElements) { + helperTextElement.remove(); + } + inputFieldElement.insertAdjacentHTML( + 'beforeend', + 'Please select an option.' + ); + return; + } + } + + // Setup modal + tmp = document.createElement('div'); + tmp.innerHTML = ` + + `.trim(); + modalElement = document.querySelector('#modals').appendChild(tmp.firstChild); + modal = M.Modal.init( + modalElement, + { + dismissible: false, + onCloseEnd: () => { + modal.destroy(); + modalElement.remove(); + } + } + ); + modal.open(); + + // Setup abort handling + abortElement = modalElement.querySelector('.abort'); + abortElement.addEventListener('click', event => {this.request.abort();}); + this.request.addEventListener('abort', event => { + this.request.abort(); + modal.close(); + }); + + // Setup load handling (after the request completed) + this.request.addEventListener('load', event => { + const response = JSON.parse(this.request.responseText); + let inputError; + let inputErrors; + let inputFieldElement; + let inputName; + + if (this.request.status === 201) { + window.location.href = response.redirect_url; + } + if (this.request.status === 400) { + for ([inputName, inputErrors] of Object.entries(response)) { + inputFieldElement = this.formElement.querySelector(`input[name="${inputName}"], select[name="${inputName}"]`).closest('.input-field'); + for (inputError of inputErrors) { + inputFieldElement.insertAdjacentHTML( + 'beforeend', + `${inputError}` + ); + } + } + } + if (this.request.status === 500) { + location.reload(); + } + modal.close(); + }); + + // Setup progress handling + progressElement = modalElement.querySelector('.progress > .determinate'); + this.request.upload.addEventListener('progress', event => { + const progress = Math.floor(100 * event.loaded / event.total); + progressElement.style.width = `${progress}%`; + }); + + this.request.open('POST', window.location.href); + this.request.send(new FormData(this.formElement)); + } +} diff --git a/app/static/js/nopaque/main.js b/app/static/js/nopaque/main.js deleted file mode 100644 index a998656b..00000000 --- a/app/static/js/nopaque/main.js +++ /dev/null @@ -1,155 +0,0 @@ -/* - * The nopaque object is used as a namespace for nopaque specific functions and - * variables. - */ -var nopaque = {}; - -nopaque.Forms = {}; -nopaque.Forms.autoInit = () => { - const nopaqueSubmitForms = document.querySelectorAll('.nopaque-submit-form'); - let nopaqueSubmitForm; - - for (nopaqueSubmitForm of nopaqueSubmitForms) { - nopaqueSubmitForm.addEventListener('submit', (event) => { - event.preventDefault(); - - const request = new XMLHttpRequest(); - const selectElements = nopaqueSubmitForm.querySelectorAll('select'); - let abortElement; - let helperTextElement; - let helperTextElements; - let inputFieldElement; - let modal; - let modalElement; - let progressElement; - let selectElement; - let tmp; - - // Check if select elements are filled out properly - for (selectElement of selectElements) { - if (selectElement.value === '') { - inputFieldElement = selectElement.closest('.input-field'); - inputFieldElement.querySelector('.select-dropdown').classList.add('invalid'); - helperTextElements = inputFieldElement.querySelectorAll('.helper-text'); - for (helperTextElement of helperTextElements) { - helperTextElement.remove(); - } - inputFieldElement.insertAdjacentHTML( - 'beforeend', - 'Please select an option.' - ); - return; - } - } - - // Setup modal - tmp = document.createElement('div'); - tmp.innerHTML = ` - - `.trim(); - modalElement = document.querySelector('#modals').appendChild(tmp.firstChild); - modal = M.Modal.init( - modalElement, - { - dismissible: false, - onCloseEnd: () => { - modal.destroy(); - modalElement.remove(); - } - } - ); - modal.open(); - - // Setup abort handling - abortElement = modalElement.querySelector('.abort'); - abortElement.addEventListener('click', event => {request.abort();}); - request.addEventListener('abort', event => { - request.abort(); - modal.close(); - }); - - // Setup load handling (after the request completed) - request.addEventListener('load', event => { - const response = JSON.parse(request.responseText); - let inputError; - let inputErrors; - let inputFieldElement; - let inputName; - - if (request.status === 201) { - window.location.href = response.redirect_url; - } - if (request.status === 400) { - for ([inputName, inputErrors] of Object.entries(response)) { - inputFieldElement = nopaqueSubmitForm.querySelector(`input[name="${inputName}"], select[name="${inputName}"]`).closest('.input-field'); - for (inputError of inputErrors) { - inputFieldElement.insertAdjacentHTML( - 'beforeend', - `${inputError}` - ); - } - } - } - if (request.status === 500) { - location.reload(); - } - modal.close(); - }); - - // Setup progress handling - progressElement = modalElement.querySelector('.progress > .determinate'); - request.upload.addEventListener('progress', event => { - const progress = Math.floor(100 * event.loaded / event.total); - progressElement.style.width = `${progress}%`; - }); - - request.open('POST', window.location.href); - request.send(new FormData(nopaqueSubmitForm)); - }); - } -} - - -nopaque.RessourceList = {}; -nopaque.RessourceList.autoInit = () => { - const nopaqueRessourceListElements = document.querySelectorAll('.nopaque-ressource-list[data-ressource-type]:not(.no-autoinit)'); - let nopaqueRessourceListElement; - - for (nopaqueRessourceListElement of nopaqueRessourceListElements) { - switch (nopaqueRessourceListElement.dataset.ressourceType) { - case 'Corpus': - new CorpusList(nopaqueRessourceListElement); - break; - case 'CorpusFile': - new CorpusFileList(nopaqueRessourceListElement); - break; - case 'Job': - new JobList(nopaqueRessourceListElement); - break; - case 'JobInput': - new JobInputList(nopaqueRessourceListElement); - break; - case 'JobResult': - new JobResultList(nopaqueRessourceListElement); - break; - case 'QueryResult': - new QueryResultList(nopaqueRessourceListElement); - break; - case 'User': - new UserList(nopaqueRessourceListElement); - break; - default: - break; - } - } -} diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2 index ca9b2591..41bca4f1 100644 --- a/app/templates/_scripts.html.j2 +++ b/app/templates/_scripts.html.j2 @@ -9,7 +9,6 @@ - {% assets filters='rjsmin', output="js/nopaque/RessourceDisplays.min.bundle.js", "js/nopaque/RessourceDisplays/RessourceDisplay.js", "js/nopaque/RessourceDisplays/CorpusDisplay.js", @@ -27,6 +26,7 @@ "js/nopaque/RessourceLists/UserList.js" %} {% endassets %} + diff --git a/app/templates/corpora/add_corpus_file.html.j2 b/app/templates/corpora/add_corpus_file.html.j2 index fe0320de..8246821a 100644 --- a/app/templates/corpora/add_corpus_file.html.j2 +++ b/app/templates/corpora/add_corpus_file.html.j2 @@ -17,7 +17,7 @@
-
+
{{ form.hidden_tag() }} diff --git a/app/templates/corpora/import_corpus.html.j2 b/app/templates/corpora/import_corpus.html.j2 index d2322fd7..865a3398 100644 --- a/app/templates/corpora/import_corpus.html.j2 +++ b/app/templates/corpora/import_corpus.html.j2 @@ -17,7 +17,7 @@
- +
{{ form.hidden_tag() }} diff --git a/app/templates/services/file_setup.html.j2 b/app/templates/services/file_setup.html.j2 index 1c974a9e..9e70288c 100644 --- a/app/templates/services/file_setup.html.j2 +++ b/app/templates/services/file_setup.html.j2 @@ -39,7 +39,7 @@

Submit a job

- +
{{ form.hidden_tag() }}
@@ -66,18 +66,3 @@
{% endblock page_content %} - -{% block modals %} -{{ super() }} - -{% endblock modals %} diff --git a/app/templates/services/nlp.html.j2 b/app/templates/services/nlp.html.j2 index 6132b322..d07470e1 100644 --- a/app/templates/services/nlp.html.j2 +++ b/app/templates/services/nlp.html.j2 @@ -57,7 +57,7 @@

Submit a job

- +
{{ form.hidden_tag() }}
diff --git a/app/templates/services/ocr.html.j2 b/app/templates/services/ocr.html.j2 index 433a1576..9af593b4 100644 --- a/app/templates/services/ocr.html.j2 +++ b/app/templates/services/ocr.html.j2 @@ -39,7 +39,7 @@

Submit a job

- +
{{ form.hidden_tag() }}