diff --git a/resources/assets/javascripts/bootstrap/actionmenu.js b/resources/assets/javascripts/bootstrap/actionmenu.js
index 75542ce63bff17baefeb26aa81141c17d0226845..0c025eeeea9f5e6958decbc815d852cf4c4b2499 100644
--- a/resources/assets/javascripts/bootstrap/actionmenu.js
+++ b/resources/assets/javascripts/bootstrap/actionmenu.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6 */
-
 (function ($) {
     'use strict';
 
diff --git a/resources/assets/javascripts/bootstrap/application.js b/resources/assets/javascripts/bootstrap/application.js
index d747946c5fe43650730cc6771730ddf69a617425..b7e3854a2c28c63ba6d154daf67db2cb97357e18 100644
--- a/resources/assets/javascripts/bootstrap/application.js
+++ b/resources/assets/javascripts/bootstrap/application.js
@@ -1,7 +1,5 @@
 import { $gettext } from '../lib/gettext.js';
 
-/*jslint browser: true, esversion: 6 */
-/*global window, $, jQuery, _ */
 /* ------------------------------------------------------------------------
  * application.js
  * This file is part of Stud.IP - http://www.studip.de
@@ -331,7 +329,7 @@ STUDIP.domReady(function () {
         } else {
             STUDIP.Scroll.removeHandler('horizontal-scroll');
         }
-    };
+    }
 
     if ($('.no-touch #layout_content').length > 0) {
         window.matchMedia('screen').addListener(function() {
@@ -348,7 +346,7 @@ jQuery(document).on('click', '.course-admin td .course-completion', function ()
     var href    = $(this).attr('href'),
         timeout = window.setTimeout(function () {
             $(this).addClass('ajaxing');
-        }.bind(this), 300);;
+        }.bind(this), 300);
 
     $.getJSON(href).done(function (completion) {
         clearTimeout(timeout);
diff --git a/resources/assets/javascripts/bootstrap/article.js b/resources/assets/javascripts/bootstrap/article.js
index 581157577db367eb6ffab30c0ecfeb7fe59615be..fbfc1317e5824f1475cfd091fd2d56cfaa86024f 100644
--- a/resources/assets/javascripts/bootstrap/article.js
+++ b/resources/assets/javascripts/bootstrap/article.js
@@ -1,5 +1,3 @@
-/*jslint browser: true */
-/*global jQuery, STUDIP */
 (function ($, STUDIP) {
     'use strict';
 
diff --git a/resources/assets/javascripts/bootstrap/avatar.js b/resources/assets/javascripts/bootstrap/avatar.js
index b4035e75db5d6d72e07ae05144461cca3c6b4b48..cbda58851fedaa7a4620a6d2c3a932ca87807f93 100644
--- a/resources/assets/javascripts/bootstrap/avatar.js
+++ b/resources/assets/javascripts/bootstrap/avatar.js
@@ -1,4 +1,3 @@
-/*global jQuery, STUDIP */
 STUDIP.domReady(() => {
     STUDIP.Avatar.init('#avatar-upload');
 
diff --git a/resources/assets/javascripts/bootstrap/blubber.js b/resources/assets/javascripts/bootstrap/blubber.js
index ef9512998b8848086bc371f17a17951da8f093c5..750e2f0c1a318d0e6746ffa010b62e06e8df8f27 100644
--- a/resources/assets/javascripts/bootstrap/blubber.js
+++ b/resources/assets/javascripts/bootstrap/blubber.js
@@ -1,4 +1,3 @@
-/*global jQuery, STUDIP */
 STUDIP.domReady(() => {
     STUDIP.Blubber.init();
 });
diff --git a/resources/assets/javascripts/bootstrap/cache-admin.js b/resources/assets/javascripts/bootstrap/cache-admin.js
index 67cf7f93e33d46346267cdf09ba70547957d1d44..97b41073d223b97d26689c114f1c6e3599739bab 100644
--- a/resources/assets/javascripts/bootstrap/cache-admin.js
+++ b/resources/assets/javascripts/bootstrap/cache-admin.js
@@ -7,7 +7,6 @@
  * @since     Stud.IP 5.0
  */
 
-/*global jQuery, STUDIP */
 import CacheAdministration from '../../../vue/components/CacheAdministration.vue'
 
 STUDIP.domReady(() => {
diff --git a/resources/assets/javascripts/bootstrap/copyable_links.js b/resources/assets/javascripts/bootstrap/copyable_links.js
index 1cd9c5fef459f03dceae15b2aa33afb5f8b53cbd..f8aa2803eabe68abdb38ba5f94970bf07f04f74e 100644
--- a/resources/assets/javascripts/bootstrap/copyable_links.js
+++ b/resources/assets/javascripts/bootstrap/copyable_links.js
@@ -1,6 +1,5 @@
 import { $gettext } from '../lib/gettext.js';
 
-/*jslint esversion: 6*/
 $(document).on('click', 'a.copyable-link', function (event) {
     event.preventDefault();
 
diff --git a/resources/assets/javascripts/bootstrap/files.js b/resources/assets/javascripts/bootstrap/files.js
index ae47af4415713f9b10c95d1ce8b4f56c1cef79aa..7118e083db0a04c8ddeadaa77923d29d29be3ede 100644
--- a/resources/assets/javascripts/bootstrap/files.js
+++ b/resources/assets/javascripts/bootstrap/files.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6 */
 function searchMoreFiles (button) {
     var table = $(button).closest('table');
     var loading = $('<div class="loading" style="padding: 10px">').html(
@@ -76,7 +75,7 @@ jQuery(document).on('ajaxComplete', (event, xhr) => {
     var payload = false;
 
     function process(key, handler) {
-        if (!changes.hasOwnProperty(key)) {
+        if (changes[key] === undefined) {
             return;
         }
 
@@ -86,10 +85,11 @@ jQuery(document).on('ajaxComplete', (event, xhr) => {
                 if (payload === false) {
                     payload = JSON.parse(xhr.responseText);
                 }
-                if (payload.hasOwnProperty(key)) {
+                if (payload[key] !== undefined) {
                     values = payload[key];
                 }
             } catch (e) {
+                console.log('Error parsing payload', e);
             }
         }
 
@@ -105,4 +105,4 @@ jQuery(document).on('ajaxComplete', (event, xhr) => {
     });
     process('close_dialog', STUDIP.Dialog.close);
 
-});
\ No newline at end of file
+});
diff --git a/resources/assets/javascripts/bootstrap/forms.js b/resources/assets/javascripts/bootstrap/forms.js
index 27871ccb5a4b9bcfebecc829d2b249fe50b08928..503fdda512696bd6c5069f83b5513968a24fdf65 100644
--- a/resources/assets/javascripts/bootstrap/forms.js
+++ b/resources/assets/javascripts/bootstrap/forms.js
@@ -263,19 +263,7 @@ STUDIP.ready(function () {
     // class and attribute changes in order to detect when the select
     // element itself will become visible. Pretty straight forward, huh?
     $('select.nested-select:not(:has(optgroup)):hidden:not(.select2-awaiting)').each(function() {
-        var observer = new window.MutationObserver(function(mutations) {
-            mutations.forEach(function(mutation) {
-                if ($('select.select2-awaiting', mutation.target).length > 0) {
-                    $('select.select2-awaiting', mutation.target)
-                        .removeClass('select2-awaiting')
-                        .each(function() {
-                            createSelect2(this);
-                        });
-                    observer.disconnect();
-                    observer = null;
-                }
-            });
-        });
+        var observer = new window.MutationObserver(onDomChange);
         observer.observe($(this).closest(':visible')[0], {
             attributeOldValue: true,
             attributes: true,
@@ -288,6 +276,19 @@ STUDIP.ready(function () {
         $(this).addClass('select2-awaiting');
     });
 
+    function onDomChange(mutations, observer) {
+        mutations.forEach(function(mutation) {
+            if ($('select.select2-awaiting', mutation.target).length > 0) {
+                $('select.select2-awaiting', mutation.target)
+                    .removeClass('select2-awaiting')
+                    .each(function() {
+                        createSelect2(this);
+                    });
+                observer.disconnect();
+            }
+        });
+    }
+
     // Unfortunately, this code needs to be duplicated because jQuery
     // namespacing kind of sucks. If the below change handler is namespaced
     // and we trigger that namespaced event here, still all change handlers
diff --git a/resources/assets/javascripts/bootstrap/fullcalendar.js b/resources/assets/javascripts/bootstrap/fullcalendar.js
index 6280b4cc2f1133f0a1a1172776853cf614dc91a4..a3d0c483e38d68178c3b904989a84f717e7b6672 100644
--- a/resources/assets/javascripts/bootstrap/fullcalendar.js
+++ b/resources/assets/javascripts/bootstrap/fullcalendar.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 STUDIP.ready(function () {
     //Check if fullcalendar instances are to be displayed:
     $('*[data-fullcalendar="1"]').each(function () {
@@ -11,19 +10,20 @@ STUDIP.ready(function () {
                     calendar = STUDIP.Fullcalendar.createFromNode(this);
                 }
 
-                let continuousRefresh = (ttl) => {
-                    setTimeout(() => {
-                        calendar.updateSize();
-                        if (ttl > 0) {
-                            continuousRefresh(ttl - 1);
-                        }
-                    }, 200);
-                };
-                continuousRefresh(10);
+                continuousRefresh(calendar, 10);
             }
         });
     });
 
+    function continuousRefresh(calendar, ttl) {
+        setTimeout(() => {
+            calendar.updateSize();
+            if (ttl > 0) {
+                continuousRefresh(ttl - 1);
+            }
+        }, 200);
+    }
+
     if ($('#event-color-picker > option').length <= 1) {
         var selectedColor = $('#selected-color').val();
         var colors = ['yellow', 'orange', 'red', 'violet', 'dark-violet', 'green', 'dark-green', 'petrol', 'brown'];
diff --git a/resources/assets/javascripts/bootstrap/inline-editing.js b/resources/assets/javascripts/bootstrap/inline-editing.js
index b72e0141982fcb0d55afdcf82f16ead7db53d8b7..8f96f31410efd320a0de86e40f274bc741a6d4db 100644
--- a/resources/assets/javascripts/bootstrap/inline-editing.js
+++ b/resources/assets/javascripts/bootstrap/inline-editing.js
@@ -4,7 +4,7 @@ jQuery(
         jQuery(document).ready(
             function() {
                 var elements = jQuery('[data-inline-editing]');
-                for (element of elements) {
+                for (const element of elements) {
                     STUDIP.InlineEditing.init(element);
                 }
             }
@@ -15,7 +15,7 @@ jQuery(
             null,
             function() {
                 var elements = jQuery('.ui-dialog [data-inline-editing]');
-                for (element of elements) {
+                for (const element of elements) {
                     STUDIP.InlineEditing.init(element);
                 }
             }
diff --git a/resources/assets/javascripts/bootstrap/installer.js b/resources/assets/javascripts/bootstrap/installer.js
index a60c1ed15e01c36dbd01347f511107e920aa390d..2ee85e82433992fae0b2b61ae2d14b0c3963d937 100644
--- a/resources/assets/javascripts/bootstrap/installer.js
+++ b/resources/assets/javascripts/bootstrap/installer.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 function domReady(fn) {
     if (document.readyState === 'complete' || document.readyState === 'interactive') {
         setTimeout(fn, 1);
diff --git a/resources/assets/javascripts/bootstrap/mvv_difflog.js b/resources/assets/javascripts/bootstrap/mvv_difflog.js
index b674ef021b6afaf161bad8fd061d853a5469ab89..b59795cdfdf945d14d55274eae5596602829cd61 100644
--- a/resources/assets/javascripts/bootstrap/mvv_difflog.js
+++ b/resources/assets/javascripts/bootstrap/mvv_difflog.js
@@ -14,6 +14,8 @@ STUDIP.domReady(() => {
             });
 
         if (mvv_field != '') {
+            var mvv_id;
+            var senddata;
             $(this)
                 .parentsUntil('div')
                 .each(function() {
@@ -31,9 +33,9 @@ STUDIP.domReady(() => {
                 var obj_elements = fields[i].split('.');
 
                 if (obj_elements.length == 1) {
-                    var senddata = { mvv_field: fields[i], mvv_debug: mvv_debug, log_action: 'del' };
+                    senddata = { mvv_field: fields[i], mvv_debug: mvv_debug, log_action: 'del' };
                 } else {
-                    var senddata = { mvv_field: fields[i], mvv_id: mvv_id, log_action: 'update' };
+                    senddata = { mvv_field: fields[i], mvv_id: mvv_id, log_action: 'update' };
                 }
 
                 var url = STUDIP.URLHelper.getURL('dispatch.php/shared/log_event/get_log_autor');
@@ -57,16 +59,17 @@ STUDIP.domReady(() => {
         var mvv_field = '';
         var mvv_coid = '';
         var mvv_id = '';
+        var mvv_log_action;
 
         switch ($('ins').attr('class')) {
             case 'diffins':
-                var mvv_log_action = 'new';
+                mvv_log_action = 'new';
                 break;
             case 'diffmod':
-                var mvv_log_action = 'update';
+                mvv_log_action = 'update';
                 break;
             default:
-                var mvv_log_action = null;
+                mvv_log_action = null;
                 break;
         }
 
@@ -93,9 +96,10 @@ STUDIP.domReady(() => {
             var ins = $(this);
             var fields = mvv_field.split(' ');
             for (var i = 0; i < fields.length; ++i) {
+                var senddata;
                 var obj_elements = fields[i].split('.');
                 if (obj_elements.length == 1 && mvv_coid) {
-                    var senddata = {
+                    senddata = {
                         mvv_field: fields[i],
                         mvv_id: mvv_id,
                         mvv_coid: mvv_coid,
@@ -113,7 +117,7 @@ STUDIP.domReady(() => {
                                 .attr('data-mvv-index') +
                             ';' +
                             classes[1];
-                        var senddata = {
+                        senddata = {
                             mvv_field: fields[i],
                             mvv_id: mvv_id,
                             mvv_coid: mvv_coid,
@@ -124,7 +128,7 @@ STUDIP.domReady(() => {
                         return true;
                     }
                 } else {
-                    var senddata = { mvv_field: fields[i], mvv_id: mvv_id, log_action: mvv_log_action };
+                    senddata = { mvv_field: fields[i], mvv_id: mvv_id, log_action: mvv_log_action };
                 }
 
                 var url = STUDIP.URLHelper.getURL('dispatch.php/shared/log_event/get_log_autor');
@@ -160,18 +164,19 @@ STUDIP.domReady(() => {
                 $.post(
                     url,
                     { mvv_field: 'mvv_' + mvv_type, mvv_id: mvv_id, log_action: 'new' },
-                    function(data) {
-                        if (data) {
-                            var info = $gettextInterpolate('Hinzugefügt von %{user} am %{time}', data);
-                            curtable.attr('title', info);
-                            const log = $('<ins class="difflog"/>').text(` [${info}] `);
-                            const cell = $('<td/>').append(log);
-                            const row = $('<tr/>').append(cell);
-                            curtable.append(row);
-                        }
-                    },
+                    onSuccess,
                     'json'
                 );
+                function onSuccess((data) {
+                    if (data) {
+                        var info = $gettextInterpolate('Hinzugefügt von %{user} am %{time}', data);
+                        curtable.attr('title', info);
+                        const log = $('<ins class="difflog"/>').text(` [${info}] `);
+                        const cell = $('<td/>').append(log);
+                        const row = $('<tr/>').append(cell);
+                        curtable.append(row);
+                    }
+                };
             });
     });
 
@@ -191,18 +196,19 @@ STUDIP.domReady(() => {
                 $.post(
                     url,
                     { mvv_field: 'mvv_' + mvv_type, mvv_id: mvv_id, log_action: 'del' },
-                    function(data) {
-                        if (data) {
-                            var info = $gettextInterpolate('Entfernt von %{user} am %{time}', data);
-                            curtable.attr('title', info);
-                            const log = $('<del class="difflog"/>').text(` [${info}] `);
-                            const cell = $('<td/>').append(log);
-                            const row = $('<tr/>').append(cell);
-                            curtable.append(row);
-                        }
-                    },
+                    onSuccess,
                     'json'
                 );
+                function onSuccess(data) {
+                    if (data) {
+                        var info = $gettextInterpolate('Entfernt von %{user} am %{time}', data);
+                        curtable.attr('title', info);
+                        const log = $('<del class="difflog"/>').text(` [${info}] `);
+                        const cell = $('<td/>').append(log);
+                        const row = $('<tr/>').append(cell);
+                        curtable.append(row);
+                    }
+                }
             });
     });
 });
diff --git a/resources/assets/javascripts/bootstrap/raumzeit.js b/resources/assets/javascripts/bootstrap/raumzeit.js
index 5f7d534a6a865bb13e0b31cb03b7762e855625cb..2140497d57c14ed96893accee97e84fbcdc3e8db 100644
--- a/resources/assets/javascripts/bootstrap/raumzeit.js
+++ b/resources/assets/javascripts/bootstrap/raumzeit.js
@@ -47,27 +47,23 @@ $(document).on('click', '.bookable_rooms_action', function(event) {
                     .append(me.data('options').clone(true));
             }
 
-            if (
-                $(this)
-                    .parents('form')
-                    .attr('action')
-                    .split('saveDate/').length > 1
-            ) {
-                var singleDate = $(this)
+            let singleDate;
+            if ($(this).parents('form').attr('action').split('saveDate/').length > 1) {
+                singleDate = $(this)
                     .parents('form')
                     .attr('action')
                     .split('saveDate/')[1]
                     .split('?')[0];
-            } else {
-                var singleDate = undefined;
             }
+
+            let checked_dates;
             if ($("input[name='checked_dates']").length > 0) {
-                var checked_dates = $("input[name='checked_dates']")
+                checked_dates = $("input[name='checked_dates']")
                     .val()
                     .split(',');
                 var ndate = [];
             } else {
-                var checked_dates = [singleDate];
+                checked_dates = [singleDate];
                 var startDate = $("input[name='date']").val();
                 var start_time = $("input[name='start_time']")
                     .val()
diff --git a/resources/assets/javascripts/bootstrap/resources.js b/resources/assets/javascripts/bootstrap/resources.js
index da266af06765da3b2859f1ac94ad0088dd39d113..07772f0f3dd0e8a19e0b41d70d5c6b7e5ca1854c 100644
--- a/resources/assets/javascripts/bootstrap/resources.js
+++ b/resources/assets/javascripts/bootstrap/resources.js
@@ -86,8 +86,7 @@ STUDIP.ready(function () {
         //Check if the seats checkbox is checked. Only include "its" input
         //fields when it is checked.
         let seats_checked = jQuery(this).find('input[name="special__seats_enabled"]').is(':checked');
-        if (seats_checked) {
-        } else {
+        if (!seats_checked) {
             jQuery(this).find('input[name="special__seats_min"]').attr('disabled', 'disabled');
             jQuery(this).find('input[name="special__seats_max"]').attr('disabled', 'disabled');
         }
@@ -647,19 +646,13 @@ STUDIP.ready(function () {
         if (!changed) {
             sURLVariables.push('defaultView=' + defaultView);
         }
-        if (sURLVariables.length > 2) {
-            var newurl = sURLVariables[0] + '?' + sURLVariables[1] + '&';
-            sURLVariables.shift();
-            sURLVariables.shift();
-            newurl += sURLVariables.join('&');
-        } else {
-            var newurl = sURLVariables.join('?');
-        }
+
+        let newurl = `${sURLVariables[0]}?${sURLVariables.slice(1).join('&')}`;
         history.pushState({}, null, newurl);
         var std_day = newurl.replace(/&?allday=\d+/, '');
         $('.booking-plan-std_view').attr('href', std_day);
         $('.booking-plan-allday_view').attr('href', std_day + '&allday=1');
-    };
+    }
 
     function submitDatePicker() {
         var picked = $('#booking-plan-jmpdate').val();
@@ -727,14 +720,7 @@ STUDIP.ready(function () {
             if (!changed) {
                 sURLVariables.push('defaultDate=' + changeddate);
             }
-            if (sURLVariables.length > 2) {
-                var newurl = sURLVariables[0] + '?' + sURLVariables[1] + '&';
-                sURLVariables.shift();
-                sURLVariables.shift();
-                newurl += sURLVariables.join('&');
-            } else {
-                var newurl = sURLVariables.join('?');
-            }
+            let newurl = `${sURLVariables[0]}?${sURLVariables.slice(1).join('&')}`;
             history.pushState({}, null, newurl);
             var std_day = newurl.replace(/&?allday=\d+/, '');
             $('.booking-plan-std_view').attr('href', std_day);
@@ -743,7 +729,7 @@ STUDIP.ready(function () {
             //Store the date in the sessionStorage:
             sessionStorage.setItem('booking_plan_date', changeddate)
         }
-    };
+    }
 
     jQuery('#booking-plan-jmpdate').datepicker(
         {
@@ -757,8 +743,7 @@ STUDIP.ready(function () {
         }
     );
 
-    var nodes = jQuery('*.resource-plan[data-resources-fullcalendar="1"]');
-    jQuery.each(nodes, function (index, node) {
+    jQuery('*.resource-plan[data-resources-fullcalendar="1"]').each(function () {
         STUDIP.loadChunk('fullcalendar').then(() => {
             //Get the default date from the sessionStorage, if it is set
             //and no date is specified in the url.
@@ -770,10 +755,10 @@ STUDIP.ready(function () {
                     use_session_date = false;
                 }
             }
-            if (node.calendar == undefined) {
-                if (jQuery(node).hasClass('semester-plan')) {
+            if (this.calendar === undefined) {
+                if (jQuery(this).hasClass('semester-plan')) {
                     STUDIP.Fullcalendar.createSemesterCalendarFromNode(
-                        node,
+                        this,
                         {
                             loading: function (isLoading) {
                                 if (!isLoading) {
@@ -810,24 +795,20 @@ STUDIP.ready(function () {
                             config.defaultDate = session_date_string;
                         }
                     }
-                    STUDIP.Fullcalendar.createFromNode(node, config);
+                    STUDIP.Fullcalendar.createFromNode(this, config);
                 }
             }
         });
     });
 
     //Check if an individual booking plan is to be displayed:
-    var nodes = jQuery('.individual-booking-plan[data-resources-fullcalendar="1"]');
-    jQuery.each(nodes, function (index, node) {
+    jQuery('.individual-booking-plan[data-resources-fullcalendar="1"]').each(function () {
         STUDIP.loadChunk('fullcalendar').then(() => {
             STUDIP.Fullcalendar.createFromNode(
-                node,
+                this,
                 {
-                    eventPositioned: function (info, calendar_event, dom_element, view) {
-                        var calendar_event = info.event;
-                        var dom_element = info.el;
-                        var view = info.view;
-                        jQuery(dom_element).droppable({
+                    eventPositioned: function (info) {
+                        jQuery(info.el).droppable({
                             drop: function (event, ui_element) {
                                 event.preventDefault();
 
diff --git a/resources/assets/javascripts/bootstrap/responsive.js b/resources/assets/javascripts/bootstrap/responsive.js
index 5dffb4e7add8dcf9666685b8761e9cb76d51e3ed..e7c1aed4f2f0677d1ebadfe37187f87c6b4c3e31 100644
--- a/resources/assets/javascripts/bootstrap/responsive.js
+++ b/resources/assets/javascripts/bootstrap/responsive.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 // Build responsive menu on domready or resize
 STUDIP.domReady(() => {
     const cache = STUDIP.Cache.getInstance('responsive.');
diff --git a/resources/assets/javascripts/bootstrap/search.js b/resources/assets/javascripts/bootstrap/search.js
index 6b94a021ec23c9f739e120cf8ef474f6c2761439..6a0559b8f397959bc3a5c3fe6802bc60baf51593 100644
--- a/resources/assets/javascripts/bootstrap/search.js
+++ b/resources/assets/javascripts/bootstrap/search.js
@@ -118,7 +118,7 @@ STUDIP.domReady(() => {
         history_timeout = setTimeout(() => {
             if (location.href !== url) {
                 history.pushState({
-                    needle: info.needle || STUDIP.Search.getCache().get('searchterm'),
+                    needle: info.needle || STUDIP.Search.getCache().get('searchterm'),
                     category: info.category
                 }, '', url)
             }
diff --git a/resources/assets/javascripts/bootstrap/sidebar.js b/resources/assets/javascripts/bootstrap/sidebar.js
index bc7329c0fffc089f07674267996ef469ac132b19..af0861e1981c0c3803a505287b43645e7fc2b4fd 100644
--- a/resources/assets/javascripts/bootstrap/sidebar.js
+++ b/resources/assets/javascripts/bootstrap/sidebar.js
@@ -3,6 +3,14 @@ $(document).on('tourstart.studip tourend.studip', function(event) {
     STUDIP.Sidebar.setSticky(event.type === 'tourend.studip');
 });
 
+function heightChangeHandler() {
+    var curr_height = $(document).height();
+    if (doc_height !== curr_height) {
+        doc_height = curr_height;
+        $(document.body).trigger('sticky_kit:recalc');
+    }
+}
+
 // Handle dynamic content
 if (window.MutationObserver !== undefined) {
     // Attach mutation observer to #layout_content and trigger it on
@@ -31,14 +39,6 @@ if (window.MutationObserver !== undefined) {
     // Stores document height (we will need this to check for changes)
     var doc_height;
 
-    function heightChangeHandler() {
-        var curr_height = $(document).height();
-        if (doc_height !== curr_height) {
-            doc_height = curr_height;
-            $(document.body).trigger('sticky_kit:recalc');
-        }
-    }
-
     STUDIP.domReady(() => {
         doc_height = $(document).height();
     });
diff --git a/resources/assets/javascripts/bootstrap/statusgroups.js b/resources/assets/javascripts/bootstrap/statusgroups.js
index e6b6ed418b2ab80ac58f37319cbbcfaf16e00b94..c79bb324e3a3c86e4beb8432cd461d754276a65c 100644
--- a/resources/assets/javascripts/bootstrap/statusgroups.js
+++ b/resources/assets/javascripts/bootstrap/statusgroups.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 STUDIP.ready(function() {
     STUDIP.Statusgroups.ajax_endpoint = $('meta[name="statusgroups-ajax-movable-endpoint"]').attr('content');
     STUDIP.Statusgroups.apply();
diff --git a/resources/assets/javascripts/bootstrap/studip_helper_attributes.js b/resources/assets/javascripts/bootstrap/studip_helper_attributes.js
index a733638a91d9e3af66b386156da3e81f9d7699b0..491d2ac5d9845adee85b59db34731d2093ce885f 100644
--- a/resources/assets/javascripts/bootstrap/studip_helper_attributes.js
+++ b/resources/assets/javascripts/bootstrap/studip_helper_attributes.js
@@ -185,8 +185,7 @@ function confirmation_handler(event) {
             // so that the original event can be executed
             element
                 .removeAttr('data-confirm')
-                .get(0)
-                [event.type]();
+                .get(0)[event.type]();
 
             // Reapply the data-confirm attribute
             window.setTimeout(function() {
diff --git a/resources/assets/javascripts/bootstrap/tables.js b/resources/assets/javascripts/bootstrap/tables.js
index f4afc52f7b5d221d53eb0f0e4494c985f8d9bef8..4825c3692b819778b2a789adeb4b3602fb5e5241 100644
--- a/resources/assets/javascripts/bootstrap/tables.js
+++ b/resources/assets/javascripts/bootstrap/tables.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 STUDIP.domReady(function() {
     if (window.MutationObserver !== undefined) {
         var observer = new window.MutationObserver(function(mutations) {
diff --git a/resources/assets/javascripts/bootstrap/tfa.js b/resources/assets/javascripts/bootstrap/tfa.js
index 4880825a66897cf5b8fd017939391010fca3019d..975e7dbfe8a39bac29cce69528005f93a50c826b 100644
--- a/resources/assets/javascripts/bootstrap/tfa.js
+++ b/resources/assets/javascripts/bootstrap/tfa.js
@@ -5,7 +5,7 @@ $(document).on('keyup', '.tfa-code-input input', function (event) {
         if (this.value.length === 0) {
             $(this).prev('input').val('');
         }
-    } else if (event.keyCode === 46) {
+    } else if (event.keyCode === 46) {
         $(this).nextAll('input:not(:hidden)').each(function () {
             $(this).prev().val(this.value);
             this.value = '';
diff --git a/resources/assets/javascripts/bootstrap/tooltip.js b/resources/assets/javascripts/bootstrap/tooltip.js
index d99879ce5919df16de809c62c27f634b99756dd3..c2493cf745606ff11c3a8110df0ad516878964a4 100644
--- a/resources/assets/javascripts/bootstrap/tooltip.js
+++ b/resources/assets/javascripts/bootstrap/tooltip.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 // Attach global hover handler for tooltips.
 // Applies to all elements having a "data-tooltip" attribute.
 // Tooltip may be provided in the data-attribute itself or by
@@ -17,7 +15,7 @@ $(document).on('mouseenter mouseleave focusin focusout', '[data-tooltip],.toolti
     const offset = $(this).offset();
     const x = offset.left + $(this).outerWidth(true) / 2;
     const y = offset.top;
-    const delay = data.hasOwnProperty('tooltipDelay') ? data.tooltipDelay : 300;
+    const delay = data.tooltipDelay ?? 300;
 
     let content;
     let tooltip;
@@ -27,9 +25,9 @@ $(document).on('mouseenter mouseleave focusin focusout', '[data-tooltip],.toolti
         // contents and create the actual tooltip object.
         if (!data.tooltip || !$.isPlainObject(data.tooltip)) {
             content = $('<div/>').text(data.tooltip || $(this).attr('title')).html();
-        } else if (data.tooltip.hasOwnProperty('html')) {
+        } else if (data.tooltip.html !== undefined) {
             content = data.tooltip.html;
-        } else if (data.tooltip.hasOwnProperty('text')) {
+        } else if (data.tooltip.text !== undefined) {
             content = data.tooltip.text;
         } else {
             throw "Invalid content for tooltip via data";
diff --git a/resources/assets/javascripts/bootstrap/vue.js b/resources/assets/javascripts/bootstrap/vue.js
index 550f09712f6f7f377c4a9c1739708c342ed84739..b8c938d2904a4dbf8a0d2dd3829fb699614dc4c9 100644
--- a/resources/assets/javascripts/bootstrap/vue.js
+++ b/resources/assets/javascripts/bootstrap/vue.js
@@ -18,7 +18,7 @@ STUDIP.ready(() => {
         }, $(this).data().vueApp);
 
         let data = {};
-        if (config.id && window.STUDIP.AppData && window.STUDIP.AppData.hasOwnProperty(config.id)) {
+        if (config.id && window.STUDIP.AppData && window.STUDIP.AppData[config.id] !== undefined) {
             data = window.STUDIP.AppData[config.id];
         }
 
@@ -38,10 +38,7 @@ STUDIP.ready(() => {
                 Object.keys(data).forEach(command => {
                     store.commit(`${config.id}/${command}`, data[command]);
                 });
-                vm = createApp({
-                    components,
-                    ...mapGetters()
-                });
+                vm = createApp({components});
             } else {
                 vm = createApp({data, components});
             }
diff --git a/resources/assets/javascripts/chunk-loader.js b/resources/assets/javascripts/chunk-loader.js
index bdecb5d6d3547741b5f49238e578aad4662b60d3..81bb04b784dd2c06256393ebf799743767573f7b 100644
--- a/resources/assets/javascripts/chunk-loader.js
+++ b/resources/assets/javascripts/chunk-loader.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 STUDIP.loadScript = function (script_name) {
     return new Promise(function (resolve, reject) {
         let script = document.createElement('script');
@@ -53,18 +52,16 @@ STUDIP.loadChunk = (function () {
                     ).then(() => {
                         (function (origPrint) {
                             window.print = function () {
-                                MathJax.Hub.Queue(
-                                    ['Delay', MathJax.Callback, 700],
+                                window.MathJax.Hub.Queue(
+                                    ['Delay', window.MathJax.Callback, 700],
                                     origPrint
                                 );
                             };
                         })(window.print);
 
-                        mathjax_loaded = true;
-
-                        return MathJax;
+                        return window.MathJax;
                     }).catch(() => {
-                        mathjax_loaded = false;
+                        console.log('Could not load mathjax')
                     });
                 }
                 promise = mathjax_promise;
@@ -78,7 +75,7 @@ STUDIP.loadChunk = (function () {
                 break;
 
             default:
-                promise = Promise.reject('Unknown chunk');
+                promise = Promise.reject(new Error(`Unknown chunk: ${chunk}`));
         }
 
         return promise.catch((error) => {
diff --git a/resources/assets/javascripts/chunks/code-highlight.js b/resources/assets/javascripts/chunks/code-highlight.js
index 9428e8e1e6a902cf1d3d09478d59a1387f939541..16c97cd77daee4bdce5e5ae1f6a469530ae87fa0 100644
--- a/resources/assets/javascripts/chunks/code-highlight.js
+++ b/resources/assets/javascripts/chunks/code-highlight.js
@@ -1,3 +1,4 @@
+/* global require */
 import "highlight.js/styles/tomorrow.css"
 
 import hljs from "highlight.js/lib/core.js"
diff --git a/resources/assets/javascripts/feedback.js b/resources/assets/javascripts/feedback.js
index 849980b20d686f97677121c36f371ba7521a259b..5555bb7ea2abcb001f634a4739eedb9a94fd04c5 100644
--- a/resources/assets/javascripts/feedback.js
+++ b/resources/assets/javascripts/feedback.js
@@ -1,169 +1,146 @@
 STUDIP.Feedback = {
 
-	initiate: function(feedback)
-	{
+    initiate: function(feedback)
+    {
         var range_id = $(feedback).attr('for');
         var range_type = $(feedback).attr('type');
         var course_id = $(feedback).attr('context');
 
-		$(feedback).load(STUDIP.URLHelper.getURL('dispatch.php/course/feedback/index_for/' + range_id + '/' + range_type + '?cid=' + course_id), function()
-		{
-			if ($('.feedback-delete').length) {
-				$('.feedback-delete').prop("onclick", null).off("click");
-				$('.feedback-delete').click(function (event) {
-					event.preventDefault();
-					var id = $(this).attr('data-id');
-					STUDIP.Dialog.confirm($(this).attr('data-confirm')).done(function() {
-						STUDIP.Feedback.delete(id,feedback);
-					});
-				});
-			}
-			STUDIP.Feedback.initiateView();
-		});
-	},
+        $(feedback).load(STUDIP.URLHelper.getURL('dispatch.php/course/feedback/index_for/' + range_id + '/' + range_type + '?cid=' + course_id), function()
+        {
+            if ($('.feedback-delete').length) {
+                $('.feedback-delete').prop("onclick", null).off("click");
+                $('.feedback-delete').click(function (event) {
+                    event.preventDefault();
+                    var id = $(this).attr('data-id');
+                    STUDIP.Dialog.confirm($(this).attr('data-confirm')).done(function() {
+                        STUDIP.Feedback.delete(id,feedback);
+                    });
+                });
+            }
+            STUDIP.Feedback.initiateView();
+        });
+    },
 
-	initiateView: function() {
-		$('.feedback-entry-add').prop("onclick", null).off("click");
-		$('.feedback-entry-add').find('.accept').click(function (event) {
-			event.preventDefault();
-			var id = $(this).closest('article').attr('data-id');
-			var feedback_id = $(this).closest('form').serialize();
-			STUDIP.Feedback.addEntry(id,feedback_id);
-		});
-		$('.feedback-entry-edit').prop("onclick", null).off("click");
-		$('.feedback-entry-edit').click(function (event) {
-			event.preventDefault();
-			var entry_id = $(this).closest('article').attr('data-id');
-			var feedback_id = $(this).closest('.feedback-stream').attr('data-id');
-			STUDIP.Feedback.editEntryForm(entry_id,feedback_id) ;
-		});
-		$('.feedback-entry-delete').prop("onclick", null).off("click");
-		$('.feedback-entry-delete').click(function (event) {
-			event.preventDefault();
-			var entry_id = $(this).closest('article').attr('data-id');
-			var feedback_id = $(this).closest('.feedback-stream').attr('data-id');
-			STUDIP.Dialog.confirm($(this).attr('data-confirm')).done(function() {
-				STUDIP.Feedback.deleteEntry(entry_id,feedback_id);
-			});
-		});
-		STUDIP.Feedback.initiateFeedbackEntryForm();
-		if ($('table.sortable-table').length) {
-			$('table.sortable-table').each(function(index, element) {
-				STUDIP.Table.enhanceSortableTable(element);
-			});
-		}
-	},
-	delete: function(id,feedback)
-	{
-		var url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/delete/' + id);
-		request = $.ajax({
-            url: url,
-            type: 'post'
-		});
-		request.done(function()
-		{
-			STUDIP.Feedback.initiate(feedback);
-		});
-	},
-	addEntry: function(feedback_id,data)
-	{
-		var url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_add/' + feedback_id);
-		request = $.ajax({
-            url: url,
-            type: 'post',
-            data: data
-		});
-		request.done(function()
-		{
-			STUDIP.Feedback.reloadView(feedback_id);
-		});
-
-	},
-	editEntryForm: function(entry_id,feedback_id)
-	{
-		url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_edit_form/' + entry_id);
-		$('#feedback-stream-' + feedback_id).find('.feedback-view').load(url, function() {
-			STUDIP.Feedback.initiateFeedbackEntryForm();
-			$('#feedback-stream-' + feedback_id).find('.accept ').prop("onclick", null).off("click");
-			$('#feedback-stream-' + feedback_id).find('.accept ').click(function (event) {
-				event.preventDefault();
-				var data = $(this).closest('form').serialize();
-				STUDIP.Feedback.editEntry(entry_id,feedback_id,data);
-			});
-			$('#feedback-stream-' + feedback_id).find('.cancel').prop("onclick", null).off("click");
-			$('#feedback-stream-' + feedback_id).find('.cancel').click(function (event) {
-				event.preventDefault();
-				STUDIP.Feedback.reloadView(feedback_id);
-			});
-		});
-	},
-	editEntry: function(entry_id,feedback_id,data)
-	{
-		var url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_edit/' + entry_id);
-		request = $.ajax({
-            url: url,
-            type: 'post',
-            data: data
-		});
-		request.done(function()
-		{
-			STUDIP.Feedback.reloadView(feedback_id);
-		});
-	},
-	deleteEntry: function(entry_id,feedback_id)
-	{
-		var url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_delete/' + entry_id);
-		request = $.ajax({
-            url: url,
-            type: 'post',
-		});
-		request.done(function()
-		{
-			STUDIP.Feedback.reloadView(feedback_id);
-		});
-	},
-	reloadView: function(feedback_id) {
-		url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/view/' + feedback_id);
-		$('#feedback-stream-' + feedback_id).find('.feedback-view').load(url, function() {
-			STUDIP.Feedback.initiateView();
-		});
-	},
-	initiateFeedbackEntryForm: function() {
-		if ($('.star-rating').length) {
-			$('.star-rating').hover(
-				function() {
-					$(this).addClass('hover');
-				  	$(this).prevAll('.star-rating').addClass('hover');
-				  	$(this).nextAll('.star-rating').addClass('out');
-				}, function() {
-					$(this).removeClass('hover');
-					$(this).siblings('.star-rating').removeClass('hover out');
-				}
-			);
-			$('.star-rating-input').change(
-				function() {
-					$(this).parent().addClass('checked');
-					$(this).parent().prevAll('.star-rating').addClass('checked');
-					$(this).parent().nextAll('.star-rating').removeClass('checked');
-				}
-			);
-		}
-		if ($('.feedback-entry-cancel').length) {
-			$('.feedback-entry-cancel').prop("onclick", null).off("click");
-			$('.feedback-entry-cancel').click(function (event) {
-				event.preventDefault();
-				$(this).closest('form')[0].reset();
-				$(this).closest('form').find('.star-rating').removeClass('checked');
-			});
-		}
-	}
+    initiateView: function() {
+        $('.feedback-entry-add').prop("onclick", null).off("click");
+        $('.feedback-entry-add').find('.accept').click(function (event) {
+            event.preventDefault();
+            var id = $(this).closest('article').attr('data-id');
+            var feedback_id = $(this).closest('form').serialize();
+            STUDIP.Feedback.addEntry(id,feedback_id);
+        });
+        $('.feedback-entry-edit').prop("onclick", null).off("click");
+        $('.feedback-entry-edit').click(function (event) {
+            event.preventDefault();
+            var entry_id = $(this).closest('article').attr('data-id');
+            var feedback_id = $(this).closest('.feedback-stream').attr('data-id');
+            STUDIP.Feedback.editEntryForm(entry_id,feedback_id) ;
+        });
+        $('.feedback-entry-delete').prop("onclick", null).off("click");
+        $('.feedback-entry-delete').click(function (event) {
+            event.preventDefault();
+            var entry_id = $(this).closest('article').attr('data-id');
+            var feedback_id = $(this).closest('.feedback-stream').attr('data-id');
+            STUDIP.Dialog.confirm($(this).attr('data-confirm')).done(function() {
+                STUDIP.Feedback.deleteEntry(entry_id,feedback_id);
+            });
+        });
+        STUDIP.Feedback.initiateFeedbackEntryForm();
+        if ($('table.sortable-table').length) {
+            $('table.sortable-table').each(function(index, element) {
+                STUDIP.Table.enhanceSortableTable(element);
+            });
+        }
+    },
+    delete: function(id,feedback)
+    {
+        const url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/delete/' + id);
+        $.post(url).done(() => {
+            STUDIP.Feedback.initiate(feedback);
+        });
+    },
+    addEntry: function(feedback_id,data)
+    {
+        const url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_add/' + feedback_id);
+        $.post(url, data).done(() => {
+            STUDIP.Feedback.reloadView(feedback_id);
+        });
+    },
+    editEntryForm: function(entry_id,feedback_id)
+    {
+        const url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_edit_form/' + entry_id);
+        $('#feedback-stream-' + feedback_id).find('.feedback-view').load(url, function() {
+            STUDIP.Feedback.initiateFeedbackEntryForm();
+            $('#feedback-stream-' + feedback_id).find('.accept').prop("onclick", null).off("click");
+            $('#feedback-stream-' + feedback_id).find('.accept').click(function (event) {
+                event.preventDefault();
+                var data = $(this).closest('form').serialize();
+                STUDIP.Feedback.editEntry(entry_id,feedback_id,data);
+            });
+            $('#feedback-stream-' + feedback_id).find('.cancel').prop("onclick", null).off("click");
+            $('#feedback-stream-' + feedback_id).find('.cancel').click(function (event) {
+                event.preventDefault();
+                STUDIP.Feedback.reloadView(feedback_id);
+            });
+        });
+    },
+    editEntry: function(entry_id,feedback_id,data)
+    {
+        const url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_edit/' + entry_id);
+        $.post(url, data).done(() => {
+            STUDIP.Feedback.reloadView(feedback_id);
+        });
+    },
+    deleteEntry: function(entry_id,feedback_id)
+    {
+        const url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/entry_delete/' + entry_id);
+        $.post(url).done(() => {
+            STUDIP.Feedback.reloadView(feedback_id);
+        });
+    },
+    reloadView: function(feedback_id) {
+        const url = STUDIP.URLHelper.getURL('dispatch.php/course/feedback/view/' + feedback_id);
+        $('#feedback-stream-' + feedback_id).find('.feedback-view').load(url, function() {
+            STUDIP.Feedback.initiateView();
+        });
+    },
+    initiateFeedbackEntryForm: function() {
+        if ($('.star-rating').length) {
+            $('.star-rating').hover(
+                function() {
+                    $(this).addClass('hover');
+                    $(this).prevAll('.star-rating').addClass('hover');
+                    $(this).nextAll('.star-rating').addClass('out');
+                }, function() {
+                    $(this).removeClass('hover');
+                    $(this).siblings('.star-rating').removeClass('hover out');
+                }
+            );
+            $('.star-rating-input').change(
+                function() {
+                    $(this).parent().addClass('checked');
+                    $(this).parent().prevAll('.star-rating').addClass('checked');
+                    $(this).parent().nextAll('.star-rating').removeClass('checked');
+                }
+            );
+        }
+        if ($('.feedback-entry-cancel').length) {
+            $('.feedback-entry-cancel').prop("onclick", null).off("click");
+            $('.feedback-entry-cancel').click(function (event) {
+                event.preventDefault();
+                $(this).closest('form')[0].reset();
+                $(this).closest('form').find('.star-rating').removeClass('checked');
+            });
+        }
+    }
 }
 
 STUDIP.ready(function (event) {
-	STUDIP.Feedback.initiateFeedbackEntryForm();
+    STUDIP.Feedback.initiateFeedbackEntryForm();
     if ($('div.feedback-elements').length) {
-		$('div.feedback-elements', event.target).each((index, element) => {
-			STUDIP.Feedback.initiate(element);
-		});
-	}
+        $('div.feedback-elements', event.target).each((index, element) => {
+            STUDIP.Feedback.initiate(element);
+        });
+    }
 });
diff --git a/resources/assets/javascripts/init.js b/resources/assets/javascripts/init.js
index 07512c8c8bc4463a1430e16d944462426c203f02..a1000e0a888baec47ea509af96460baa508b5f82 100644
--- a/resources/assets/javascripts/init.js
+++ b/resources/assets/javascripts/init.js
@@ -5,7 +5,6 @@ import admin_sem_class from './lib/admin_sem_class.js';
 import Admission from './lib/admission.js';
 import Arbeitsgruppen from './lib/arbeitsgruppen.js';
 import Archive from './lib/archive.js';
-import Audio from './lib/audio.js';
 import Avatar from './lib/avatar.js';
 import BigImageHandler from './lib/big_image_handler.js';
 import Blubber from './lib/blubber.js';
@@ -93,7 +92,6 @@ window.STUDIP = _.assign(window.STUDIP || {}, {
     api,
     Arbeitsgruppen,
     Archive,
-    Audio,
     Avatar,
     BigImageHandler,
     Blubber,
diff --git a/resources/assets/javascripts/lib/abstract-api.js b/resources/assets/javascripts/lib/abstract-api.js
index 4239118b876ea0bca6da497dea62d98be10575c9..8e33e22d8a74e676b0cd70f581042a24b5db6d30 100644
--- a/resources/assets/javascripts/lib/abstract-api.js
+++ b/resources/assets/javascripts/lib/abstract-api.js
@@ -92,7 +92,7 @@ class AbstractAPI
                 this.queue.shift().resolve();
             }
         }).promise();
-    };
+    }
 }
 
 // Create shortcut methods for easier access by method
diff --git a/resources/assets/javascripts/lib/actionmenu.js b/resources/assets/javascripts/lib/actionmenu.js
index d6c074d3b152b34984911b0f6fed25e5f7f69143..5bfef934e413c9a2066b4d66e2db6f83f581f657 100644
--- a/resources/assets/javascripts/lib/actionmenu.js
+++ b/resources/assets/javascripts/lib/actionmenu.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 /**
  * Determine whether the menu should be opened in dialog or regular layout.
  * @type {[type]}
diff --git a/resources/assets/javascripts/lib/audio.js b/resources/assets/javascripts/lib/audio.js
deleted file mode 100644
index 7b23055c2da22ee52c26dd2841b0738318d53034..0000000000000000000000000000000000000000
--- a/resources/assets/javascripts/lib/audio.js
+++ /dev/null
@@ -1,44 +0,0 @@
-var initialised = false,
-    loaded = false,
-    queue = [],
-    load_audioplayer = function() {
-        AudioPlayer.setup(STUDIP.ASSETS_URL + 'flash/player.swf', {
-            animation: 'no',
-            transparentpagebg: 'yes',
-            width: 300
-        });
-        loaded = true;
-
-        // Process queue
-        var item = queue.shift();
-        while (item) {
-            Audio.handle(item);
-            item = queue.shift();
-        }
-    },
-    initialise = function() {
-        if (!initialised) {
-            var script = document.createElement('script');
-            script.src = STUDIP.ASSETS_URL + 'javascripts/audio-player.js';
-            script.onload = load_audioplayer;
-            document.getElementsByTagName('head')[0].appendChild(script);
-            initialised = true;
-        }
-        return loaded;
-    };
-
-const Audio = {
-    handle: function(element) {
-        if (!initialise()) {
-            queue.push(element);
-        } else {
-            AudioPlayer.embed(element.id, {
-                soundFile: encodeURIComponent(element.src),
-                titles: element.title,
-                width: element.clientWidth || 300
-            });
-        }
-    }
-};
-
-export default Audio;
diff --git a/resources/assets/javascripts/lib/blubber.js b/resources/assets/javascripts/lib/blubber.js
index 3aca3c74fbc51e22bb7e4047785060aa1d999c12..800f742b3052c37965c53b5d2b071db8e8d2c14e 100644
--- a/resources/assets/javascripts/lib/blubber.js
+++ b/resources/assets/javascripts/lib/blubber.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 import { $gettext } from './gettext';
 
 
@@ -182,8 +181,8 @@ const Blubber = {
     },
     Composer: {
         vue: null,
-        async init () {
-            STUDIP.Blubber.Composer.vue = await STUDIP.Vue.load().then(({createApp}) => {
+        init () {
+            STUDIP.Vue.load().then(({createApp}) => {
                 let components = STUDIP.Blubber.components;
                 return createApp({
                     el: '#blubber_contact_ids',
@@ -211,6 +210,8 @@ const Blubber = {
                     },
                     components,
                 });
+            }).then((app) => {
+                STUDIP.Blubber.Composer.vue = app;
             });
         }
     }
diff --git a/resources/assets/javascripts/lib/cache.js b/resources/assets/javascripts/lib/cache.js
index 0423fb1a4b7ba4e6a101fd4f243d4ae80cabe074..bd773444227351ff129da590f77402967aa55e16 100644
--- a/resources/assets/javascripts/lib/cache.js
+++ b/resources/assets/javascripts/lib/cache.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 import Cookie from './cookie.js';
 
 /**
@@ -106,7 +105,7 @@ class Cache {
     locate(index) {
         index = this.prefix + index;
 
-        if (cache.hasOwnProperty(index)) {
+        if (cache[index] !== undefined) {
             const now = new Date().getTime();
 
             let item = JSON.parse(cache.getItem(index));
@@ -187,7 +186,7 @@ class Cache {
     prune() {
         if (this.prefix) {
             for (let key in cache) {
-                if (cache.hasOwnProperty(key) && key.indexOf(this.prefix) === 0) {
+                if (cache[key] !== undefined && key.indexOf(this.prefix) === 0) {
                     cache.removeItem(key);
                 }
             }
@@ -211,7 +210,7 @@ const CacheFacade = {
             Cookie.set('cache_session', session_id);
 
             for (let key in cache) {
-                if (!cache.hasOwnProperty(key) || key.indexOf('studip.') !== 0) {
+                if (cache[key] === undefined || key.indexOf('studip.') !== 0) {
                     continue;
                 }
 
diff --git a/resources/assets/javascripts/lib/cookie.js b/resources/assets/javascripts/lib/cookie.js
index 7823312240c00a07820558a23fb83120b666babf..6046d62d8201586402277cd27a9705dc246baa59 100644
--- a/resources/assets/javascripts/lib/cookie.js
+++ b/resources/assets/javascripts/lib/cookie.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 class Cookie {
     static set(name, value, expiry_days) {
         var chunks = [name + '=' + value, 'SameSite=strict'];
@@ -28,7 +27,7 @@ class Cookie {
             data[chunks[0].trim()] = chunks.slice(1).join('=');
         });
 
-        return data.hasOwnProperty(name) ? data[name] : undefined;
+        return data[name];
     }
 }
 
diff --git a/resources/assets/javascripts/lib/course_wizard.js b/resources/assets/javascripts/lib/course_wizard.js
index f692f12a8da42bc3f90d4c5e4954f0b60882c6e9..87e65707e5a16b757af62e9a8706612f1d1343c1 100644
--- a/resources/assets/javascripts/lib/course_wizard.js
+++ b/resources/assets/javascripts/lib/course_wizard.js
@@ -298,21 +298,13 @@ const CourseWizard = {
      * @returns {boolean}
      */
     buildPartialTree: function(items, assignable, source_node) {
-        if (assignable) {
-            var classPrefix = 'sem-tree-';
-        } else {
-            var classPrefix = 'sem-tree-assigned-';
-        }
+        var classPrefix = assignable ? 'sem-tree-': 'sem-tree-assigned-';
         for (var i = 0; i < items.length; i++) {
             var parent = $('.' + classPrefix + items[i].parent);
             var node = $('.' + classPrefix + items[i].id);
             if (node.length == 0) {
-                if (!assignable && source_node == items[i].id) {
-                    var selected = true;
-                } else {
-                    var selected = false;
-                }
-                var node = CourseWizard.createTreeNode(items[i], assignable, selected);
+                var selected = !assignable && source_node == items[i].id;
+                node = CourseWizard.createTreeNode(items[i], assignable, selected);
                 parent.children('ul').append(node);
             } else {
                 node.removeClass('css-tree-hidden');
@@ -352,9 +344,11 @@ const CourseWizard = {
      * @returns {*|jQuery}
      */
     createTreeNode: function(values, assignable, selected) {
+        let item = $('<li/>');
+
         // Node in "All study areas" tree.
         if (assignable) {
-            var item = $('<li>').addClass('sem-tree-' + values.id);
+            item.addClass('sem-tree-' + values.id);
             var assign = $('<input>')
                 .attr('type', 'image')
                 .attr('name', 'assign[' + values.id + ']')
@@ -412,7 +406,7 @@ const CourseWizard = {
             }
             // Node in "assigned study areas" tree.
         } else {
-            var item = $('<li>').addClass('sem-tree-assigned-' + values.id);
+            item.addClass('sem-tree-assigned-' + values.id);
             item.html(
                 $('<div/>')
                     .text(values.name)
@@ -429,7 +423,7 @@ const CourseWizard = {
                 item.append(unassign);
             }
             if (values.assignable && selected) {
-                var input = $('<input>')
+                input = $('<input>')
                     .attr('type', 'hidden')
                     .attr('name', 'studyareas[]')
                     .attr('value', values.id);
diff --git a/resources/assets/javascripts/lib/dates.js b/resources/assets/javascripts/lib/dates.js
index 1fc983068202da61910315716d2b38d21f42fd6d..3be67c057582b271a547de18421c123e0a041092 100644
--- a/resources/assets/javascripts/lib/dates.js
+++ b/resources/assets/javascripts/lib/dates.js
@@ -14,7 +14,7 @@ const Dates = {
             title: topic_name,
             termin_id: termin_id
         }).done(function(response) {
-            if (response.hasOwnProperty('li')) {
+            if (response.li !== undefined) {
                 $('#new_topic')
                     .closest('[data-termin-id]')
                     .find('.themen-list')
diff --git a/resources/assets/javascripts/lib/dialog.js b/resources/assets/javascripts/lib/dialog.js
index 0ac76522109e280cb4ca12445784e00df506aa0f..bc649703a1d40cb0e4ff8343636a9add4d4b2b0e 100644
--- a/resources/assets/javascripts/lib/dialog.js
+++ b/resources/assets/javascripts/lib/dialog.js
@@ -5,8 +5,6 @@ import Overlay from './overlay.js';
 import PageLayout from './page_layout.js';
 import Report from './report.js';
 
-/*jslint esversion: 6*/
-
 /**
  * Specialized dialog handler
  *
@@ -63,7 +61,7 @@ const Dialog = {
     stack: [],
     hasInstance: function(id) {
         id = id || 'default';
-        return this.instances.hasOwnProperty(id);
+        return this.instances[id] !== undefined;
     },
     getInstance: function(id) {
         id = id || 'default';
@@ -138,12 +136,12 @@ Dialog.handlers.header['X-Dialog-Execute'] = function(value, options, xhr) {
     }
 
     // Check for invalid call
-    if (!value.hasOwnProperty('func')) {
+    if (value.func === undefined) {
         throw 'Dialog: Invalid value for X-Dialog-Execute';
     }
 
     // Populate payload if not set
-    if (!value.hasOwnProperty('payload')) {
+    if (value.payload === undefined) {
         value.payload = xhr.getResponseHeader('Content-Type').match(/json/)
             ? $.parseJSON(xhr.responseText)
             : xhr.responseText;
@@ -278,10 +276,10 @@ Dialog.fromURL = function(url, options) {
         headers: { 'X-Dialog': true },
         cache: false,
         contentType:
-            options.hasOwnProperty('processData') && !options.processData
+            options.processData !== undefined && !options.processData
                 ? false
                 : 'application/x-www-form-urlencoded; charset=UTF-8',
-        processData: options.hasOwnProperty('processData') ? options.processData : true
+        processData: options.processData ?? true
     })
         .done(function(response, status, xhr) {
             var advance = true;
@@ -418,10 +416,10 @@ Dialog.show = function(content, options = {}) {
     });
 
     // Create buttons
-    if (!options.hasOwnProperty('buttons') || (options.buttons && !$.isPlainObject(options.buttons))) {
+    if (options.buttons === undefined || (options.buttons && !$.isPlainObject(options.buttons))) {
         dialog_options.buttons = extractButtons.call(this, instance.element);
         // Create 'close' button
-        if (!dialog_options.buttons.hasOwnProperty('cancel')) {
+        if (dialog_options.buttons.cancel === undefined) {
             dialog_options.buttons.cancel = {
                 text: $gettext('Schließen'),
                 'class': 'cancel'
@@ -452,7 +450,9 @@ Dialog.close = function(options) {
             try {
                 instance.element.dialog('close');
                 instance.open = instance.element.dialog('isOpen');
-            } catch (ignore) {}
+            } catch (ignore) {
+                // No action necessary
+            }
 
             // Apparently the close event has been canceled, so don't force
             // a close
@@ -463,13 +463,15 @@ Dialog.close = function(options) {
             try {
                 instance.element.dialog('destroy');
                 instance.element.remove();
-            } catch (ignore) {}
+            } catch (ignore) {
+                // No action necessary
+            }
         }
 
         Dialog.removeInstance(options.id);
     }
 
-    if (options['reload-on-close'] && !options.hasOwnProperty('is-reloading')) {
+    if (options['reload-on-close'] && options['is-reloading'] === undefined) {
         window.location.reload();
         options['is-reloading'] = true;
     }
@@ -504,7 +506,7 @@ Dialog.calculateDimensions = function (instance, content, options) {
         max_width  = $(window).width() - 6; // Subtract border
         max_height = $(window).height();
 
-        if (!options.hasOwnProperty('width')) {
+        if (options.width === undefined) {
             width  = $(window).width() * 0.95;
             height = $(window).height() * 0.98;
         }
@@ -533,7 +535,7 @@ Dialog.calculateDimensions = function (instance, content, options) {
         // Prevent buttons from wrapping
         $('[data-dialog-button]', helper).css('white-space', 'nowrap');
         // Add cancel button if missing
-        if ((!options.hasOwnProperty('buttons') || options.buttons !== false)) {
+        if ((options.buttons === undefined || options.buttons !== false)) {
             $('<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"></div>')
                 .append('<div class="ui-dialog-buttonset"><button class="ui-button ui-widget ui-corner-all cancel">Foo</button></div>')
                 .appendTo(helper)
@@ -585,7 +587,7 @@ Dialog.calculateDimensions = function (instance, content, options) {
     height = Math.min(height, max_height);
     if (
         previous &&
-        previous.hasOwnProperty('dimensions') &&
+        previous.dimensions !== undefined &&
         width > previous.dimensions.width &&
         height > previous.dimensions.height
     ) {
@@ -664,7 +666,7 @@ Dialog.registerHeaderHandler = function (header, handler) {
     Dialog.handlers.header[header] = handler;
 };
 Dialog.removeHeaderHandler = function (header) {
-    if (Dialog.handlers.header.hasOwnProperty(header)) {
+    if (Dialog.handlers.header[header] !== undefined) {
         delete Dialog.handlers.header[header];
     }
 };
diff --git a/resources/assets/javascripts/lib/extract_callback.js b/resources/assets/javascripts/lib/extract_callback.js
index 5b88607ef0c4a9cc569ed4aa60fbe0036a924e6a..49246461f7719970a7304b089b0531ac40698530 100644
--- a/resources/assets/javascripts/lib/extract_callback.js
+++ b/resources/assets/javascripts/lib/extract_callback.js
@@ -8,7 +8,9 @@ export default function extractCallback(cmd, payload) {
     // Try to decode URI component in case it is encoded
     try {
         command = window.decodeURIComponent(command);
-    } catch (ignore) {}
+    } catch (ignore) {
+        // No action necessary
+    }
 
     // Try to parse value as JSON (value might be {func: 'foo', payload: {}})
     try {
@@ -18,12 +20,12 @@ export default function extractCallback(cmd, payload) {
     }
 
     // Check for invalid call
-    if (!command.hasOwnProperty('func')) {
+    if (command.func === undefined) {
         throw 'Dialog: Invalid value for X-Dialog-Execute';
     }
 
     // Populate payload if not set
-    if (!command.hasOwnProperty('payload')) {
+    if (command.payload === undefined) {
         command.payload = payload;
     }
 
@@ -37,7 +39,7 @@ export default function extractCallback(cmd, payload) {
         }
 
         // Check for not finished/closed chunk
-        if (chunk.match(/\([^\)]*$/)) {
+        if (chunk.match(/\([^)]*$/)) {
             last_chunk = chunk;
             return;
         }
diff --git a/resources/assets/javascripts/lib/files.js b/resources/assets/javascripts/lib/files.js
index 08adc296c0e51b43f5e69833f37438be0cb3be0c..cd17ddf6b058d833e0b250ca7cddc58453a0044d 100644
--- a/resources/assets/javascripts/lib/files.js
+++ b/resources/assets/javascripts/lib/files.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 import { $gettext } from './gettext.js';
 import Dialog from './dialog.js';
 import FilesTable from '../../../vue/components/FilesTable.vue';
@@ -205,7 +204,7 @@ const Files = {
         var redirect = false;
         var html = [];
 
-        if (payload.hasOwnProperty('html') && payload.html !== undefined) {
+        if (payload.html !== undefined) {
             redirect = payload.redirect;
             html = payload.html;
         }
diff --git a/resources/assets/javascripts/lib/forum.js b/resources/assets/javascripts/lib/forum.js
index 42c9152c773ee57a5718902a8f38e91882927ed6..9a6ff176deb0ccae877c0f75439a805c2e28db44 100644
--- a/resources/assets/javascripts/lib/forum.js
+++ b/resources/assets/javascripts/lib/forum.js
@@ -423,11 +423,9 @@ const Forum = {
                 // watch out for anonymous postings
                 var anonymous = jQuery('.anonymous_post[data-profile=' + topic_id + ']').length > 0;
 
-                if (anonymous) {
-                    var name = $gettext('Anonym');
-                } else {
-                    var name = jQuery('span.username[data-profile=' + topic_id + ']').text().trim();
-                }
+                var name = anonymous
+                    ? $gettext('Anonym')
+                    : jQuery('span.username[data-profile=' + topic_id + ']').text().trim();
 
                 // add content from cited posting in [quote]-tags
                 var originalContent = jQuery(
diff --git a/resources/assets/javascripts/lib/fullcalendar.js b/resources/assets/javascripts/lib/fullcalendar.js
index 0d9d0f1b8c44a818b3fec3f49c580801798d99c6..54414ed1be1774528c85ce76228dd88b56920c83 100644
--- a/resources/assets/javascripts/lib/fullcalendar.js
+++ b/resources/assets/javascripts/lib/fullcalendar.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 /**
  * This class contains Stud.IP specific code for the fullcalendar package.
  */
@@ -137,7 +135,7 @@ class Fullcalendar
 
         if (Array.isArray(config.eventSources)) {
             config.eventSources = config.eventSources.map((s) => {
-                if (s.hasOwnProperty('url')) {
+                if (s.url !== undefined) {
                     return s;
                 }
             });
diff --git a/resources/assets/javascripts/lib/fullscreen.js b/resources/assets/javascripts/lib/fullscreen.js
index 10ff69eecc35d045d181fa34f865b382bf6b8e9b..1f10090ad6230deddbb00f203779fb9b5a2929fc 100644
--- a/resources/assets/javascripts/lib/fullscreen.js
+++ b/resources/assets/javascripts/lib/fullscreen.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 const Fullscreen = {
     toggle () {
         if (sessionStorage.getItem('studip-fullscreen') === 'on') {
diff --git a/resources/assets/javascripts/lib/gettext.js b/resources/assets/javascripts/lib/gettext.js
index 699136fee2584b414085c482f50210b158cd34f3..88e726e2da3c0211197222c5c0b37b123fd38cd2 100644
--- a/resources/assets/javascripts/lib/gettext.js
+++ b/resources/assets/javascripts/lib/gettext.js
@@ -23,7 +23,8 @@ async function setLocale(locale = getInitialLocale()) {
 
     state.locale = locale;
     if (state.translations[state.locale] === null) {
-        state.translations[state.locale] = await getTranslations(state.locale);
+        const translations = await getTranslations(state.locale);
+        state.translations[state.locale] = translations;
     }
 
     translate.initTranslations(state.translations, {
diff --git a/resources/assets/javascripts/lib/inline-editing.js b/resources/assets/javascripts/lib/inline-editing.js
index a86442db1876da23afb09f8c2836dd32d4c0bec0..b1f025fb0a31a54350cf1642d4796f97d835e67b 100644
--- a/resources/assets/javascripts/lib/inline-editing.js
+++ b/resources/assets/javascripts/lib/inline-editing.js
@@ -63,7 +63,7 @@ class InlineEditing
         jQuery(element).empty();
         jQuery(element).append(display_container);
         jQuery(element).append(edit_container);
-    };
+    }
 
 
     static activate(element) {
@@ -74,7 +74,7 @@ class InlineEditing
 
         jQuery(container).children('.display-container').addClass('invisible');
         jQuery(container).children('.edit-container').removeClass('invisible');
-    };
+    }
 
 
     static save(element) {
@@ -119,7 +119,7 @@ class InlineEditing
                 }
             }
         );
-    };
+    }
 
 
     static abort(element) {
@@ -131,7 +131,7 @@ class InlineEditing
         jQuery(container).children('.edit-container').addClass('invisible');
         jQuery(container).children('.display-container').removeClass('invisible');
 
-    };
+    }
 }
 
 
diff --git a/resources/assets/javascripts/lib/jsupdater.js b/resources/assets/javascripts/lib/jsupdater.js
index 9469fccbb46a16646136f93435ed074d16ae18cd..fad92e21df773d0a99ab7a1a1ea3b63cf84f1b94 100644
--- a/resources/assets/javascripts/lib/jsupdater.js
+++ b/resources/assets/javascripts/lib/jsupdater.js
@@ -26,7 +26,7 @@ let registeredHandlers = {};
 // Reset json memory, used to delay polling if consecutive requests always
 // return the same result
 function resetJSONMemory(json) {
-    if (json.hasOwnProperty('server_timestamp')) {
+    if (json.server_timestamp !== undefined) {
         delete json.server_timestamp;
     }
     json = JSON.stringify(json);
diff --git a/resources/assets/javascripts/lib/multi_select.js b/resources/assets/javascripts/lib/multi_select.js
index 3a447fb4c37a3ed12bb462bc0214a3048a6b7b1d..b4abeb9c1ed4f5ddf14e89a5bddc386771aa9288 100644
--- a/resources/assets/javascripts/lib/multi_select.js
+++ b/resources/assets/javascripts/lib/multi_select.js
@@ -1,4 +1,3 @@
-/*jslint esversion:6*/
 import { $gettext } from './gettext.js';
 
 /**
diff --git a/resources/assets/javascripts/lib/news.js b/resources/assets/javascripts/lib/news.js
index 5319ed750ffa955941285dfe6713cd34ea8ae7c1..80575ccf1a172b115fcbe41660d6e14c6eacdf3a 100644
--- a/resources/assets/javascripts/lib/news.js
+++ b/resources/assets/javascripts/lib/news.js
@@ -1,7 +1,5 @@
 import { $gettext } from '../lib/gettext.js';
 
-/*jslint browser: true, unparam: true */
-/*global jQuery, STUDIP */
 const News = {
     /**
      * (Re-)initialise news-page, f.e. to stay in dialog
diff --git a/resources/assets/javascripts/lib/oer.js b/resources/assets/javascripts/lib/oer.js
index 02f1d16ab0a7b90dc372823ff6c39e8fd918f51c..701a37b90a2af89f1108e71723fa70ae795e95da 100755
--- a/resources/assets/javascripts/lib/oer.js
+++ b/resources/assets/javascripts/lib/oer.js
@@ -154,8 +154,8 @@ const OER = {
                                     }
                                     resolve();
                                 },
-                                error: function () {
-                                    reject();
+                                error: function (jqXHR, textStatus, errorThrown) {
+                                    reject(new Error(errorThrown));
                                 }
                             });
                         });
diff --git a/resources/assets/javascripts/lib/page_layout.js b/resources/assets/javascripts/lib/page_layout.js
index 9509518f842e01f63c35195bac56a312586c9d24..4d3ed338e93b46d06a9386a572e0e4124868ab48 100644
--- a/resources/assets/javascripts/lib/page_layout.js
+++ b/resources/assets/javascripts/lib/page_layout.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 let options = {
     title: document.title,
     prefix: ''
diff --git a/resources/assets/javascripts/lib/parse_options.js b/resources/assets/javascripts/lib/parse_options.js
index 8160f37829772bcde46f6c184e3e8e33ef8fbbfa..994feb80fc9ff03a6ea590a05b7dd2318900cd13 100644
--- a/resources/assets/javascripts/lib/parse_options.js
+++ b/resources/assets/javascripts/lib/parse_options.js
@@ -77,10 +77,10 @@ function parseValue(value) {
     if (value.toLowerCase() === 'false') {
         return false;
     }
-    if (/^[+\-]\d+$/.test(value)) {
+    if (/^[+-]\d+$/.test(value)) {
         return parseInt(value, 10);
     }
-    if (/^[+\-]\d+\.\d+$/.test(value)) {
+    if (/^[+-]\d+\.\d+$/.test(value)) {
         return parseFloat(value, 10);
     }
     return value.replace(/^(["'])(.*)\1$/, '$2');
diff --git a/resources/assets/javascripts/lib/personal_notifications.js b/resources/assets/javascripts/lib/personal_notifications.js
index 4a0a6e317e50bbeb5ca9b1566f27982bd84ba82c..f61150a5824e9b0d6ae39537e92af535a59f7e69 100644
--- a/resources/assets/javascripts/lib/personal_notifications.js
+++ b/resources/assets/javascripts/lib/personal_notifications.js
@@ -61,12 +61,12 @@ function process_notifications({ notifications }) {
             $(`#${notification.html_id}`).on('mouseenter', PersonalNotifications.isVisited);
         }
 
-        changed = changed || !stack.hasOwnProperty(id);
+        changed = changed || stack[id] === undefined;
 
         // Check if notifications should be sent (depends on the
         // Notification itself and session storage)
         if (
-            !window.hasOwnProperty('Notification')
+            window.Notification === undefined
             || Notification.permission !== 'granted'
             || cache.has(notification.id)
         ) {
diff --git a/resources/assets/javascripts/lib/qr_code.js b/resources/assets/javascripts/lib/qr_code.js
index 781d1aa7ac2c94e78e6666629d7ee281925e2057..6766d78bcc896f60ead5664affa8b5c9806de8ef 100644
--- a/resources/assets/javascripts/lib/qr_code.js
+++ b/resources/assets/javascripts/lib/qr_code.js
@@ -49,7 +49,7 @@ const QRCode = {
     },
     generate: function (element, text, options = {}) {
         options.text = text;
-        if (!options.hasOwnProperty('correctLevel')) {
+        if (options.correctLevel === undefined) {
             options.correctLevel = 3;
         }
 
diff --git a/resources/assets/javascripts/lib/questionnaire.js b/resources/assets/javascripts/lib/questionnaire.js
index 56da337f398f385b9ff7707bf9495388d937d5e2..cfafc8dfc0ba7a250d9958bc8db7af0a309f8f73 100644
--- a/resources/assets/javascripts/lib/questionnaire.js
+++ b/resources/assets/javascripts/lib/questionnaire.js
@@ -260,7 +260,7 @@ const Questionnaire = {
                     { labelPosition: 'outside' }
                 );
             }
-        };
+        }
     },
     initTestEvaluation: async function (el, data, isAjax, isMultiple) {
         this.initVoteEvaluation(el, data, isAjax, isMultiple);
diff --git a/resources/assets/javascripts/lib/quick_search.js b/resources/assets/javascripts/lib/quick_search.js
index d8fda74b15276f5080add56cf77860c89fc9fd46..a755184a5710ef5d8e1d84064d0e5d1ce773da96 100644
--- a/resources/assets/javascripts/lib/quick_search.js
+++ b/resources/assets/javascripts/lib/quick_search.js
@@ -1,4 +1,3 @@
-/*jslint esversion: 6*/
 import { $gettext } from './gettext.js';
 
 /* ------------------------------------------------------------------------
diff --git a/resources/assets/javascripts/lib/ready.js b/resources/assets/javascripts/lib/ready.js
index 3464ec6ab1becdc444393b04c6007e37724c8b51..1550a5a1eedf2b33d86da36e3e7c2c7fdd4e1b52 100644
--- a/resources/assets/javascripts/lib/ready.js
+++ b/resources/assets/javascripts/lib/ready.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 function ready(callback, top = false) {
     if (top) {
         ready.handlers.unshift({
diff --git a/resources/assets/javascripts/lib/resources.js b/resources/assets/javascripts/lib/resources.js
index 4189e927d87fb783cd74f4d0e7a1a70fcdff7a8f..9f1f066b88f0d9d4db54c38bfae2cdecd148ed0e 100644
--- a/resources/assets/javascripts/lib/resources.js
+++ b/resources/assets/javascripts/lib/resources.js
@@ -442,6 +442,7 @@ class Resources
         }
         var tbody = jQuery(table).find('tbody')[0];
         if (!tbody) {
+            return;
         }
 
         var selected_option = jQuery(select).find(':selected')[0];
@@ -647,7 +648,7 @@ class Resources
             }
             $(".time-option-container").show();
         }
-    };
+    }
 
 
     //Fullcalendar specialisations:
@@ -668,7 +669,7 @@ class Resources
                 }
             }
         ).done(function (data) {
-            if (!data || (data.length == 0)) {
+            if (!data || data.length === 0) {
                 return;
             }
             var new_interval_id = data[0].interval_id;
@@ -677,11 +678,11 @@ class Resources
                 var move_url = calendar_event.extendedProps.studip_api_urls['move'];
                 var resize_url = calendar_event.extendedProps.studip_api_urls['resize'];
                 move_url = move_url.replace(
-                    /\&interval_id=([0-9a-f]{32})/,
+                    /&interval_id=([0-9a-f]{32})/,
                     '&interval_id=' + new_interval_id
                 );
                 resize_url = resize_url.replace(
-                    /\&interval_id=([0-9a-f]{32})/,
+                    /&interval_id=([0-9a-f]{32})/,
                     '&interval_id=' + new_interval_id
                 );
                 var studip_api_urls = calendar_event.extendedProps.studip_api_urls;
@@ -825,11 +826,7 @@ class Resources
                             {
                                 method: 'get',
                                 dataType: 'json',
-                                async: false,
-                                success: function(data) {
-                                    if (data) {
-                                    }
-                                }
+                                async: false
                             }
                         );
                     }
@@ -839,7 +836,7 @@ class Resources
         }
     }
 
-};
+}
 
 
 //Class properties:
diff --git a/resources/assets/javascripts/lib/responsive.js b/resources/assets/javascripts/lib/responsive.js
index 09712dd74a1f40e1691f47eb86dafbb06d12c7b0..87e742c82053aaca8635ffdc82834e453546dd33 100644
--- a/resources/assets/javascripts/lib/responsive.js
+++ b/resources/assets/javascripts/lib/responsive.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 import HeaderMagic from './header_magic.js';
 import Sidebar from './sidebar.js';
 
diff --git a/resources/assets/javascripts/lib/search.js b/resources/assets/javascripts/lib/search.js
index c059144862d182802a3ca8206946ac73e1dc9df0..99b525d23eda9751c0d0182349eedd42f83725d9 100644
--- a/resources/assets/javascripts/lib/search.js
+++ b/resources/assets/javascripts/lib/search.js
@@ -172,11 +172,16 @@ const Search = {
         return category;
     },
 
-    printSingleResult: function(categoryName, data, result, counter, fullsearch, categoryBodyDiv) {
-        var resultsPerType  = data.resultsPerType;
+    printSingleResult: function(
+        categoryName,
+        { resultsPerType, imgAdd, imgRemove },
+        result,
+        counter,
+        fullsearch,
+        categoryBodyDiv
+    ) {
         var hasSubcourses   = (categoryName === 'GlobalSearchMyCourses' || categoryName === 'GlobalSearchCourses') && result.has_children;
-        var addIcon         = data.imgAdd;
-        var removeIcon      = data.imgRemove;
+
         // Create single result entry.
         var single          = $('<section>');
         var data            = $('<div class="search-result-data">');
@@ -209,7 +214,7 @@ const Search = {
                     STUDIP.Search.showSubcourses(result.id);
                     e.preventDefault();
                 })
-                .html(addIcon)
+                .html(imgAdd)
                 .appendTo(data);
             // initially hide the 'remove' icon
             $(`<a href="#" id="hide-subcourses-${result.id}" class="search-has-subcourses">`)
@@ -217,7 +222,7 @@ const Search = {
                     STUDIP.Search.hideSubcourses(result.id);
                     e.preventDefault();
                 })
-                .html(removeIcon)
+                .html(imgRemove)
                 .appendTo(data)
                 .hide();
         }
@@ -345,7 +350,7 @@ const Search = {
     showFilter: function (category) {
         var filters = $('#search-results').data('filters');
         STUDIP.Search.hideAllFilters();
-        if (filters && filters.hasOwnProperty(category) && category != 'show_all_categories') {
+        if (filters && filters.category !== undefined && category != 'show_all_categories') {
             for (let i = 0; i < filters[category].length; i++) {
                 $(`#${filters[category][i]}_filter`).show();
             }
diff --git a/resources/assets/javascripts/lib/studip-vue.js b/resources/assets/javascripts/lib/studip-vue.js
index eac667905f7f8ef5631a9a524e846e4ff0da6f14..c7cf89a2924001d0b2fe6042a7e911a540bd7cbd 100644
--- a/resources/assets/javascripts/lib/studip-vue.js
+++ b/resources/assets/javascripts/lib/studip-vue.js
@@ -1,5 +1,5 @@
 const load = async function () {
-    return await STUDIP.loadChunk('vue');
+    return STUDIP.loadChunk('vue');
 };
 
 const on = async function (...args) {
diff --git a/resources/assets/javascripts/lib/tooltip.js b/resources/assets/javascripts/lib/tooltip.js
index 7c6c9683ea880da4fb5f7d16b6552884afa184ad..5ae28edfd203d02a7c34f065d942e5066841a7f7 100644
--- a/resources/assets/javascripts/lib/tooltip.js
+++ b/resources/assets/javascripts/lib/tooltip.js
@@ -1,5 +1,3 @@
-/*jslint esversion: 6*/
-
 import CSS from './css.js';
 
 /**
diff --git a/resources/assets/javascripts/lib/url_helper.js b/resources/assets/javascripts/lib/url_helper.js
index 61a5a6294cfa36fd9360b3465bde144f275f6aa6..c6c5660507962cf28d884f08696a52bbc65e0aea 100644
--- a/resources/assets/javascripts/lib/url_helper.js
+++ b/resources/assets/javascripts/lib/url_helper.js
@@ -31,7 +31,7 @@ class URLHelper {
         }
         var base_url = this.base_url;
         if (url.charAt(0) === '/') {
-            var host = this.base_url.match(/^[a-zA-Z][a-zA-Z0-9+-.]*:\/\/[\w:.\-]+/);
+            var host = this.base_url.match(/^[a-zA-Z][a-zA-Z0-9+-.]*:\/\/[\w:.-]+/);
             base_url = host ? host[0] : '';
         }
         return base_url + url;
diff --git a/resources/assets/javascripts/lib/user_filter.js b/resources/assets/javascripts/lib/user_filter.js
index ee2d6221c6534921c3b0196b51ca1f9aaec73f3b..b10415206fcee6f88b2d0962cc6b1612e4e60362 100644
--- a/resources/assets/javascripts/lib/user_filter.js
+++ b/resources/assets/javascripts/lib/user_filter.js
@@ -3,6 +3,7 @@
  * ------------------------------------------------------------------------ */
 import { $gettext } from './gettext.js';
 import Dialog from './dialog.js';
+import Dialogs from './dialogs.js';
 
 const UserFilter = {
     new_group_nr: 1,
diff --git a/resources/assets/javascripts/lib/wysiwyg.js b/resources/assets/javascripts/lib/wysiwyg.js
index 87929c9e5a7d9bc3f95e08301e40949563fe8fa5..933d93fa07a0e58021a7cddfabcf5f850bf73e42 100644
--- a/resources/assets/javascripts/lib/wysiwyg.js
+++ b/resources/assets/javascripts/lib/wysiwyg.js
@@ -308,21 +308,21 @@ const wysiwyg = {
                 ],
                 (function() {
                     var greek = [];
-                    for (var i = 913; i <= 929; i++) {
+                    for (let i = 913; i <= 929; i++) {
                         // 17 uppercase characters
                         greek.push('&#' + String(i));
                     }
-                    for (var i = 945; i <= 962; i++) {
+                    for (let i = 945; i <= 962; i++) {
                         // 17 lowercase characters
                         greek.push('&#' + String(i));
                     }
                     // NOTE character #930 is not assigned!!
-                    for (var i = 931; i <= 937; i++) {
+                    for (let i = 931; i <= 937; i++) {
                         // remaining upercase
                         greek.push('&#' + String(i));
                     }
                     greek.push('');
-                    for (var i = 963; i <= 969; i++) {
+                    for (let i = 963; i <= 969; i++) {
                         // remaining lowercase
                         greek.push('&#' + String(i));
                     }
diff --git a/resources/assets/javascripts/mvv.js b/resources/assets/javascripts/mvv.js
index 257ad907c0bea2b4345181f4669062da70adcaa2..7233df89634f7c6618d47c5dc43c157e0d5a51c1 100644
--- a/resources/assets/javascripts/mvv.js
+++ b/resources/assets/javascripts/mvv.js
@@ -29,7 +29,7 @@ jQuery(function ($) {
     });
 
     $(document).on('click', '.mvv-item-edit-properties', function () {
-    	$(this).parents("li").find(".mvv-item-document-comments").toggle();
+        $(this).parents("li").find(".mvv-item-document-comments").toggle();
         return false;
     });
 
@@ -569,7 +569,7 @@ STUDIP.MVV.Content = {
         if (element.data('hasData')) {
             element.next().slideToggle('fast');
             return false;
-        };
+        }
         if (_.isNull(STUDIP.MVV.Content.deskriptor_data)) {
             jQuery.ajax({
                 url: STUDIP.URLHelper.getURL(STUDIP.MVV.CONTROLLER_URL + 'show_original/'),
@@ -613,11 +613,9 @@ STUDIP.MVV.Content = {
         return false;
     },
     showAllOriginal: function () {
-        elements = jQuery('.mvv-show-original');
-        _.each(elements, function (e) {
-            var element = jQuery(e);
-            if (element.next(':visible').length === 0) {
-                element.click();
+        jQuery('.mvv-show-original').each(function () {
+            if ($(this).next(':visible').length === 0) {
+                $(this).click();
             }
         });
         return false;
diff --git a/resources/assets/javascripts/mvv_course_wizard.js b/resources/assets/javascripts/mvv_course_wizard.js
index 2cda92a36b084a07dc1a004698d34731ab4197a3..63822f562cd04a0818fcd3359df58d745dc24d75 100644
--- a/resources/assets/javascripts/mvv_course_wizard.js
+++ b/resources/assets/javascripts/mvv_course_wizard.js
@@ -35,7 +35,7 @@ STUDIP.MVV.CourseWizard = {
                     target.find('.tree-loading').remove();
                     if (items.length > 0) {
                         var list = target.children('ul');
-                        for (i = 0; i < items.length; i++) {
+                        for (let i = 0; i < items.length; i++) {
                             if (items[i].assignable || items[i].has_children) {
                                 list.append(STUDIP.MVV.CourseWizard.createTreeNode(items[i], assignable));
                             }
@@ -98,7 +98,7 @@ STUDIP.MVV.CourseWizard = {
                         $('#lvgsearchresults ul').empty();
                         $('#lvgsearchresults').show();
                         for (var i = 0; i < items.length; i++) {
-                            lvgroup_html = $(items[i].html_string);
+                            const lvgroup_html = $(items[i].html_string);
                             if ($('#lvgroup-tree-assigned-' + items[i].id).length) {
                                 lvgroup_html
                                     .find('input')
diff --git a/resources/assets/javascripts/public-path.js b/resources/assets/javascripts/public-path.js
index 1fd9fe0c5de015b59ecaa4686b420c699d0150c8..a84ad1b63cf0f46944619dc65ea60a26d3a1b36f 100644
--- a/resources/assets/javascripts/public-path.js
+++ b/resources/assets/javascripts/public-path.js
@@ -1 +1,2 @@
+/* global __webpack_public_path__ : writable */
 __webpack_public_path__ = __webpack_public_path__ || (window.STUDIP && window.STUDIP.ASSETS_URL)
diff --git a/resources/assets/javascripts/studip-jquery-selection-helper.js b/resources/assets/javascripts/studip-jquery-selection-helper.js
index 165e7653609a1835a82138aa564628f33bc5d831..1c0c27ccb983a69a85acff1ac00440592d3ba886 100644
--- a/resources/assets/javascripts/studip-jquery-selection-helper.js
+++ b/resources/assets/javascripts/studip-jquery-selection-helper.js
@@ -4,7 +4,7 @@ $.fn.extend({
         var that = this[0],
             range,
             position;
-        if (!!document.selection) {
+        if (document.selection) {
             that.focus();
             range = document.selection.createRange();
             range.moveStart('character', -that.value.length);
@@ -21,10 +21,10 @@ $.fn.extend({
     // Returns the currently selected text
     getSelection: function() {
         var that = this[0];
-        if (!!document.selection) {
+        if (document.selection) {
             return document.selection.createRange().text;
         }
-        if (!!this[0].setSelectionRange) {
+        if (this[0].setSelectionRange) {
             return this[0].value.substring(this[0].selectionStart, this[0].selectionEnd);
         }
         return false;
@@ -33,15 +33,12 @@ $.fn.extend({
     setSelection: function(start, end) {
         return this.each(function() {
             var range;
-            if (!!this.setSelectionRange) {
+            if (this.setSelectionRange) {
                 this.setSelectionRange(start, end);
-            } else if (!!this.createTextRange) {
+            } else if (this.createTextRange) {
                 this.focus();
                 range = this.createTextRange();
                 range.collapse(true);
-                if (position < 0) {
-                    position = Math.max(0, this.value.length + position);
-                }
                 range.moveStart('character', start);
                 range.moveEnd('character', end);
                 range.select();
@@ -53,13 +50,13 @@ $.fn.extend({
         return $(this).each(function() {
             var selection = false,
                 position;
-            if (!!document.selection) {
+            if (document.selection) {
                 position = $(this).getCaretPosition();
                 selection = {
                     start: position,
                     end: position + $(this).getSelection().length
                 };
-            } else if (!!this.setSelectionRange) {
+            } else if (this.setSelectionRange) {
                 selection = {
                     start: this.selectionStart,
                     end: this.selectionEnd
@@ -86,12 +83,12 @@ $.fn.extend({
             var scroll_top = this.scrollTop,
                 range,
                 selection_start;
-            if (!!document.selection) {
+            if (document.selection) {
                 this.focus();
                 range = document.selection.createRange();
                 range.text = replacement;
                 range.select();
-            } else if (!!this.setSelectionRange) {
+            } else if (this.setSelectionRange) {
                 selection_start = this.selectionStart;
                 this.value =
                     this.value.substring(0, selection_start) + replacement + this.value.substring(this.selectionEnd);
diff --git a/resources/assets/javascripts/studip-jquery-tweaks.js b/resources/assets/javascripts/studip-jquery-tweaks.js
index b8a14486eb49496ea42abc4ce8bd4c1aa4c80b4f..7527b2c4006f682aa2374d6f892bf517c5544255 100644
--- a/resources/assets/javascripts/studip-jquery-tweaks.js
+++ b/resources/assets/javascripts/studip-jquery-tweaks.js
@@ -1,6 +1,3 @@
-/*jslint browser: true */
-/*global jQuery */
-
 /**
  * SVG class handling.
  *
@@ -64,4 +61,4 @@
         return originals.hasClass.call(this, value);
     };
 
-}(jQuery));
\ No newline at end of file
+}(jQuery));
diff --git a/resources/assets/javascripts/studip-jquery.multi-select.tweaks.js b/resources/assets/javascripts/studip-jquery.multi-select.tweaks.js
index d9277bb2e36fa16a66f80229f272bb02ecdf5160..dd6fc2d083a2d8f380dbd68d4f573c0bebfb5c8b 100644
--- a/resources/assets/javascripts/studip-jquery.multi-select.tweaks.js
+++ b/resources/assets/javascripts/studip-jquery.multi-select.tweaks.js
@@ -1,7 +1,5 @@
 import { $gettext } from './lib/gettext.js';
 
-/*jslint browser: true */
-/*global jQuery */
 
 /**
  * Neccessary tweaks/adjustments for the jQuery UI multiselect addon.
@@ -83,4 +81,4 @@ import { $gettext } from './lib/gettext.js';
     };
 
 
-}(jQuery, jQuery.fn.multiSelect.Constructor));
\ No newline at end of file
+}(jQuery, jQuery.fn.multiSelect.Constructor));
diff --git a/resources/assets/javascripts/studip-ui.js b/resources/assets/javascripts/studip-ui.js
index 657a2ddd13bcddce151948227c680ee4ea1bd64f..f04a790740a42d67912c8235e1f2cc482e58a1d7 100644
--- a/resources/assets/javascripts/studip-ui.js
+++ b/resources/assets/javascripts/studip-ui.js
@@ -1,8 +1,5 @@
 import { $gettext } from './lib/gettext.js';
 
-/*jslint browser: true */
-/*global jQuery, STUDIP */
-
 /**
  * This file contains extensions/adjustments for jQuery UI.
  */
@@ -129,7 +126,7 @@ import { $gettext } from './lib/gettext.js';
                     options = $(element).data().datePicker;
                 if (options) {
                     $.each(options, function (key, value) {
-                        if (STUDIP.UI.Datepicker.dataHandlers.hasOwnProperty(key)) {
+                        if (STUDIP.UI.Datepicker.dataHandlers[key] !== undefined) {
                             STUDIP.UI.Datepicker.dataHandlers[key].call(element, value);
                         }
                     });
@@ -262,7 +259,7 @@ import { $gettext } from './lib/gettext.js';
                     options = $(element).data().datetimePicker;
                 if (options) {
                     $.each(options, function (key, value) {
-                        if (STUDIP.UI.DateTimepicker.dataHandlers.hasOwnProperty(key)) {
+                        if (STUDIP.UI.DateTimepicker.dataHandlers[key] !== undefined) {
                             STUDIP.UI.DateTimepicker.dataHandlers[key].call(element, value);
                         }
                     });
@@ -389,7 +386,7 @@ import { $gettext } from './lib/gettext.js';
                     options = $(element).data().timePicker;
                 if (options) {
                     $.each(options, function (key, value) {
-                        if (STUDIP.UI.Timepicker.dataHandlers.hasOwnProperty(key)) {
+                        if (STUDIP.UI.Timepicker.dataHandlers[key] !== undefined) {
                             STUDIP.UI.Timepicker.dataHandlers[key].call(element, value);
                         }
                     });
diff --git a/resources/vue/store/courseware/structure.module.js b/resources/vue/store/courseware/structure.module.js
index 0b71b090785611f3190a7ba37f87c4f6aacee011..8f2a30f0b16e01e58370b2053cbb6fb792597827 100644
--- a/resources/vue/store/courseware/structure.module.js
+++ b/resources/vue/store/courseware/structure.module.js
@@ -170,7 +170,9 @@ const actions = {
         function pickleDescendants() {
             try {
                 cache.set(cacheKey, rootGetters['courseware-structural-elements/all']);
-            } catch (e) {}
+            } catch (e) {
+                // No action necessary
+            }
         }
 
         function removeStaleElements() {