diff --git a/app/static/js/add_job.js b/app/static/js/add_job.js
deleted file mode 100644
index 29dae6e8236f6831ac091bccf1fb1e8133ea879e..0000000000000000000000000000000000000000
--- a/app/static/js/add_job.js
+++ /dev/null
@@ -1,54 +0,0 @@
-function SubmitAddJobForm(newJobFormElement, progressModalElement, request) {
-  var formData = new FormData(newJobFormElement);
-  var progressModal = M.Modal.getInstance(progressModalElement);
-
-  progressModal.options.dismissible = false;
-  progressModalElement.querySelector(".title").innerHTML = newJobFormElement.title.value;
-
-  request.addEventListener("abort", function(event) {
-    progressModalElement.querySelector(".progress-in-percent").innerHTML = "0%";
-    progressModalElement.querySelector(".determinate").style.width = "0%";
-  });
-  request.addEventListener("load", function(event) {
-    if (request.status === 201) {
-      window.location.href = JSON.parse(this.responseText)['redirect_url'];
-    }
-    if (request.status === 400) {
-      progressModal.close();
-      progressModalElement.querySelector(".progress-in-percent").innerHTML = "0%";
-      progressModalElement.querySelector(".determinate").style.width = "0%";
-      for (let [field, errors] of Object.entries(JSON.parse(this.responseText))) {
-        let fieldElement = document.getElementById(field).closest('.input-field');
-        for (let error of errors) {
-          fieldElement.insertAdjacentHTML('beforeend', '<span class="helper-text red-text">' + error + '</span>');
-        }
-      }
-    }
-    if (request.status === 500) {
-      location.reload();
-    }
-  });
-  request.upload.addEventListener("progress", function(event) {
-    progressInPercent = Math.floor(100 * event.loaded / event.total).toString() + "%";
-    progressModalElement.querySelector(".progress-in-percent").innerHTML = progressInPercent;
-    progressModalElement.querySelector(".determinate").style.width = progressInPercent;
-  });
-
-  progressModal.open();
-  request.open("POST", window.location.href);
-  request.send(formData);
-}
-
-function initAddJobForm(addJobFormElement, progressModalElement) {
-  var request;
-
-  request = new XMLHttpRequest();
-
-  addJobFormElement.addEventListener("submit", function(event) {
-    event.preventDefault();
-    SubmitAddJobForm(addJobFormElement, progressModalElement, request);
-  });
-  progressModalElement.querySelector(".cancel").addEventListener("click", function(event) {
-    request.abort();
-  });
-}
diff --git a/app/static/js/nopaque.js b/app/static/js/nopaque.js
index 89afcea031c4d03b7dc472ec72dffb8cbb2b90da..0dbbe6dbf15614221ca99414bb8a182ca36a1d0d 100644
--- a/app/static/js/nopaque.js
+++ b/app/static/js/nopaque.js
@@ -18,24 +18,64 @@ nopaque["foreignJobsSubscribers"] = [];
 // nopaque functions
 nopaque["forms"] = {};
 nopaque["forms"]["init"] = function() {
-  for (let form of document.querySelectorAll(".nopaque-form")) {
+  var abortRequestElement, progressElement, progressModal,
+      progressModalElement, request;
+
+  for (let form of document.querySelectorAll(".nopaque-job-form")) {
+    request = new XMLHttpRequest();
+    if (form.dataset.hasOwnProperty('progressModal')) {
+      progressModalElement = document.getElementById(form.dataset.progressModal);
+      progressModal = M.Modal.getInstance(progressModalElement);
+      progressModal.options.dismissible = false;
+      abortRequestElement = progressModalElement.querySelector(".abort-request");
+      // just use request.abort?
+      abortRequestElement.addEventListener("click", function() {request.abort();});
+      progressElement = progressModalElement.querySelector(".determinate");
+    }
     form.addEventListener("submit", function(event) {
       event.preventDefault();
-      if (form.dataset.hasOwnProperty('loadingModal')) {
-        let loadingModalElement = document.getElementById(form.dataset.loadingModal);
-        M.Modal.getInstance(loadingModalElement).open();
+      var formData, progressModalTitleElement;
+
+      formData = new FormData(form);
+      // Initialize progress modal
+      if (progressModalElement) {
+        progressModalTitleElement = progressModalElement.querySelector(".title");
+        progressModalTitleElement.innerText = formData.get("title");
+        progressElement.style.width = "0%";
+        progressModal.open();
+      }
+      request.open("POST", window.location.href);
+      request.send(formData);
+    });
+    request.addEventListener("load", function(event) {
+      var errorElement, fieldElement;
+
+      if (request.status === 201) {
+        window.location.href = JSON.parse(this.responseText)['redirect_url'];
       }
-      let data = {};
-      for (let input of form.querySelectorAll("input")) {
-        if (input.type === "file") {
-          file = input.files[0];
-          data[`${input.name}-wrapper`] = {"bytes": file, "name": file.name};
-        } else {
-          data[input.name] = input.value;
+      if (request.status === 400) {
+        for (let [field, errors] of Object.entries(JSON.parse(this.responseText))) {
+          fieldElement = form.querySelector(`input[name="${field}"]`).closest(".input-field");
+          for (let error of errors) {
+            errorElement = document.createElement("span");
+            errorElement.classList.add("helper-text", "red-text");
+            errorElement.innerText = error;
+            fieldElement.appendChild(errorElement);
+          }
         }
+        if (progressModalElement) {
+          progressModal.close();
+        }
+      }
+      if (request.status === 500) {
+        location.reload();
       }
-      nopaque.socket.emit(`submit-${form.id}`, data);
     });
+    if (progressModalElement) {
+      request.upload.addEventListener("progress", function(event) {
+        progressElement.style.width = Math.floor(100 * event.loaded / event.total).toString() + "%";
+      });
+    }
   }
 }
 
@@ -131,9 +171,7 @@ nopaque.socket.on('update-foreign-jobs', function(msg) {
 document.addEventListener("DOMContentLoaded", function() {
   M.AutoInit();
   M.CharacterCounter.init(document.querySelectorAll(`input[data-length][type="text"]`));
-  M.Dropdown.init(document.getElementById("nav-notifications"),
-                  {"alignment": "right", "constrainWidth": false, "coverTrigger": false});
-  M.Dropdown.init(document.getElementById("nav-account"),
+  M.Dropdown.init(document.querySelectorAll('#nav-notifications, #nav-account'),
                   {"alignment": "right", "constrainWidth": false, "coverTrigger": false});
   nopaque.forms.init();
   nopaque.navigation.init();
diff --git a/app/templates/services/merge_images.html.j2 b/app/templates/services/merge_images.html.j2
index 816712c7316b61b1e6760519a0ef4158c2e6b755..5bf8acc6e9f3a7cafccb6293a5c1e13cea24e12f 100644
--- a/app/templates/services/merge_images.html.j2
+++ b/app/templates/services/merge_images.html.j2
@@ -37,7 +37,7 @@
 
 <div class="col s12">
   <div class="card">
-    <form method="POST" enctype="multipart/form-data" id="add-job-form">
+    <form class="nopaque-job-form" data-progress-modal="progress-modal">
       <div class="card-content">
         {{ add_job_form.hidden_tag() }}
         <div class="row">
@@ -100,15 +100,9 @@
     <div class="progress">
       <div class="determinate" style="width: 0%"></div>
     </div>
-    <p><span class="progress-in-percent"></span> uploaded</p>
   </div>
   <div class="modal-footer">
-    <a href="#!" class="modal-close waves-effect waves-green btn red cancel">Cancel</a>
+    <a href="#!" class="modal-close waves-effect waves-green btn red abort-request">Cancel</a>
   </div>
 </div>
-
-<script>
-  initAddJobForm(document.getElementById("add-job-form"),
-                 document.getElementById("progress-modal"));
-</script>
 {% endblock %}
diff --git a/app/templates/services/nlp.html.j2 b/app/templates/services/nlp.html.j2
index ba0be5e9df5c34854ef32d424761f617f9cd75d5..7bb263279407c9b5e7f355f8e7e3ec4c7e3a6728 100644
--- a/app/templates/services/nlp.html.j2
+++ b/app/templates/services/nlp.html.j2
@@ -53,7 +53,7 @@
 
 <div class="col s12">
   <div class="card">
-    <form method="POST" enctype="multipart/form-data" id="add-job-form">
+    <form class="nopaque-job-form" data-progress-modal="progress-modal">
       <div class="card-content">
         {{ add_job_form.hidden_tag() }}
         <div class="row">
@@ -128,15 +128,9 @@
     <div class="progress">
       <div class="determinate" style="width: 0%"></div>
     </div>
-    <p><span class="progress-in-percent"></span> uploaded</p>
   </div>
   <div class="modal-footer">
-    <a href="#!" class="modal-close waves-effect waves-green btn red cancel">Cancel</a>
+    <a href="#!" class="modal-close waves-effect waves-green btn red abort-request">Cancel</a>
   </div>
 </div>
-
-<script>
-  initAddJobForm(document.getElementById("add-job-form"),
-                 document.getElementById("progress-modal"));
-</script>
 {% endblock %}
diff --git a/app/templates/services/ocr.html.j2 b/app/templates/services/ocr.html.j2
index 2ddba65015110fa629679b387ccd4f79b2b552db..93cf8f0033102a7209d53d877787e8c0bd2f66a2 100644
--- a/app/templates/services/ocr.html.j2
+++ b/app/templates/services/ocr.html.j2
@@ -54,7 +54,7 @@
 
 <div class="col s12">
   <div class="card">
-    <form method="POST" enctype="multipart/form-data" id="add-job-form">
+    <form class="nopaque-job-form" data-progress-modal="progress-modal">
       <div class="card-content">
         {{ add_job_form.hidden_tag() }}
         <div class="row">
@@ -212,19 +212,13 @@
 
 <div id="progress-modal" class="modal">
   <div class="modal-content">
-    <h4><i class="material-icons prefix">file_upload</i> Uploading files for <span class="title"></span></h4>
+    <h4><i class="material-icons left">file_upload</i>Uploading files for <span class="title"></span></h4>
     <div class="progress">
       <div class="determinate" style="width: 0%"></div>
     </div>
-    <p><span class="progress-in-percent"></span> uploaded</p>
   </div>
   <div class="modal-footer">
-    <a href="#!" class="modal-close waves-effect waves-green btn red cancel">Cancel</a>
+    <a href="#!" class="modal-close waves-effect waves-green btn red abort-request">Cancel</a>
   </div>
 </div>
-
-<script>
-  initAddJobForm(document.getElementById("add-job-form"),
-                 document.getElementById("progress-modal"));
-</script>
 {% endblock %}