diff --git a/core/js/core.json b/core/js/core.json
index 4f338f87748809535e1d59a75fb8ac0c6adc4695..c3c7cbbafc2651b40ad53962df59a15079705287 100644
--- a/core/js/core.json
+++ b/core/js/core.json
@@ -2,7 +2,6 @@
 	"libraries": [
 	],
 	"modules": [
-		"js.js",
 		"share.js",
 		"sharetemplates.js",
 		"sharesocialmanager.js",
diff --git a/core/js/dist/login.js b/core/js/dist/login.js
index 11e072559094fb1b2f4297bb407d5837b6be302f..c6a757adcea7d9979740f9c4c5feacb204c556c9 100644
Binary files a/core/js/dist/login.js and b/core/js/dist/login.js differ
diff --git a/core/js/dist/login.js.map b/core/js/dist/login.js.map
index cb24b022c57775437536099020c3d8d89f5f4d55..2cb76387761d8ed271030f288ec8ba91e67341d7 100644
Binary files a/core/js/dist/login.js.map and b/core/js/dist/login.js.map differ
diff --git a/core/js/dist/main.js b/core/js/dist/main.js
index 25ac4026d75b699b112d3e8af304119b2e49ce60..8c36a31859354fbb97414f7b31cf3c0fd4401ab9 100644
Binary files a/core/js/dist/main.js and b/core/js/dist/main.js differ
diff --git a/core/js/dist/main.js.map b/core/js/dist/main.js.map
index 0ff9c2c091d248ea1080f8fdbfdb4fd8b9d27f3c..9a375f28ec497a734774f59542ad990a2f4614e6 100644
Binary files a/core/js/dist/main.js.map and b/core/js/dist/main.js.map differ
diff --git a/core/js/js.js b/core/js/js.js
deleted file mode 100644
index 8b9fae0a9217746e7c0a5c79552759ad23c94c55..0000000000000000000000000000000000000000
--- a/core/js/js.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * @namespace OC
- */
-Object.assign(window.OC, {
-	/* jshint camelcase: false */
-
-	/**
-	 * Warn users that the connection to the server was lost temporarily
-	 *
-	 * This function is throttled to prevent stacked notfications.
-	 * After 7sec the first notification is gone, then we can show another one
-	 * if necessary.
-	 */
-	_ajaxConnectionLostHandler: _.throttle(function() {
-		OC.Notification.showTemporary(t('core', 'Connection to server lost'));
-	}, 7 * 1000, {trailing: false}),
-
-	/**
-	 * Process ajax error, redirects to main page
-	 * if an error/auth error status was returned.
-	 */
-	_processAjaxError: function(xhr) {
-		var self = this;
-		// purposefully aborted request ?
-		// this._userIsNavigatingAway needed to distinguish ajax calls cancelled by navigating away
-		// from calls cancelled by failed cross-domain ajax due to SSO redirect
-		if (xhr.status === 0 && (xhr.statusText === 'abort' || xhr.statusText === 'timeout' || self._reloadCalled)) {
-			return;
-		}
-
-		if (_.contains([302, 303, 307, 401], xhr.status) && OC.currentUser) {
-			// sometimes "beforeunload" happens later, so need to defer the reload a bit
-			setTimeout(function() {
-				if (!self._userIsNavigatingAway && !self._reloadCalled) {
-					var timer = 0;
-					var seconds = 5;
-					var interval = setInterval( function() {
-						OC.Notification.showUpdate(n('core', 'Problem loading page, reloading in %n second', 'Problem loading page, reloading in %n seconds', seconds - timer));
-						if (timer >= seconds) {
-							clearInterval(interval);
-							OC.reload();
-						}
-						timer++;
-						}, 1000 // 1 second interval
-					);
-
-					// only call reload once
-					self._reloadCalled = true;
-				}
-			}, 100);
-		} else if(xhr.status === 0) {
-			// Connection lost (e.g. WiFi disconnected or server is down)
-			setTimeout(function() {
-				if (!self._userIsNavigatingAway && !self._reloadCalled) {
-					self._ajaxConnectionLostHandler();
-				}
-			}, 100);
-		}
-	},
-
-	/**
-	 * Registers XmlHttpRequest object for global error processing.
-	 *
-	 * This means that if this XHR object returns 401 or session timeout errors,
-	 * the current page will automatically be reloaded.
-	 *
-	 * @param {XMLHttpRequest} xhr
-	 */
-	registerXHRForErrorProcessing: function(xhr) {
-		var loadCallback = function() {
-			if (xhr.readyState !== 4) {
-				return;
-			}
-
-			if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
-				return;
-			}
-
-			// fire jquery global ajax error handler
-			$(document).trigger(new $.Event('ajaxError'), xhr);
-		};
-
-		var errorCallback = function() {
-			// fire jquery global ajax error handler
-			$(document).trigger(new $.Event('ajaxError'), xhr);
-		};
-
-		if (xhr.addEventListener) {
-			xhr.addEventListener('load', loadCallback);
-			xhr.addEventListener('error', errorCallback);
-		}
-
-	}
-});
-
diff --git a/core/js/merged-template-prepend.json b/core/js/merged-template-prepend.json
index c7b3501d6c9bc77cfb26f6d1a593116580574b37..01ffe223d7a5eeb12d69f9e9b28db1eb17676c49 100644
--- a/core/js/merged-template-prepend.json
+++ b/core/js/merged-template-prepend.json
@@ -1,5 +1,4 @@
 [
-  "js.js",
   "mimetype.js",
   "mimetypelist.js",
   "select2-toggleselect.js"
diff --git a/core/src/OC/index.js b/core/src/OC/index.js
index 7fd718e17c4b5bd590f310a578a6a0ff5067308c..461e0160526752f3a6fac63a6c570c4c457cd363 100644
--- a/core/src/OC/index.js
+++ b/core/src/OC/index.js
@@ -20,6 +20,11 @@
  */
 
 import {addScript, addStyle} from './legacy-loader'
+import {
+	ajaxConnectionLostHandler,
+	processAjaxError,
+	registerXHRForErrorProcessing,
+} from './xhr-error'
 import Apps from './apps'
 import {AppConfig, appConfig} from './appconfig'
 import {appSettings} from './appsettings'
@@ -154,6 +159,14 @@ export default {
 	isUserAdmin,
 	L10N,
 
+	/**
+	 * Ajax error handlers
+	 * @todo remove from here and keep internally -> requires new tests
+	 */
+	_ajaxConnectionLostHandler: ajaxConnectionLostHandler,
+	_processAjaxError: processAjaxError,
+	registerXHRForErrorProcessing,
+
 	/**
 	 * Capabilities
 	 *
diff --git a/core/src/OC/xhr-error.js b/core/src/OC/xhr-error.js
new file mode 100644
index 0000000000000000000000000000000000000000..43b2eba7229e8c9d48c208cde84cb661c5e890be
--- /dev/null
+++ b/core/src/OC/xhr-error.js
@@ -0,0 +1,114 @@
+/*
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import _ from 'underscore'
+import $ from 'jquery'
+
+import OC from './index'
+import Notification from './notification'
+
+/**
+ * Warn users that the connection to the server was lost temporarily
+ *
+ * This function is throttled to prevent stacked notfications.
+ * After 7sec the first notification is gone, then we can show another one
+ * if necessary.
+ */
+export const ajaxConnectionLostHandler = _.throttle(() => {
+	Notification.showTemporary(t('core', 'Connection to server lost'))
+}, 7 * 1000, {trailing: false})
+
+/**
+ * Process ajax error, redirects to main page
+ * if an error/auth error status was returned.
+ */
+export const processAjaxError = xhr => {
+	// purposefully aborted request ?
+	// OC._userIsNavigatingAway needed to distinguish ajax calls cancelled by navigating away
+	// from calls cancelled by failed cross-domain ajax due to SSO redirect
+	if (xhr.status === 0 && (xhr.statusText === 'abort' || xhr.statusText === 'timeout' || OC._reloadCalled)) {
+		return
+	}
+
+	if (_.contains([302, 303, 307, 401], xhr.status) && OC.currentUser) {
+		// sometimes "beforeunload" happens later, so need to defer the reload a bit
+		setTimeout(function () {
+			if (!OC._userIsNavigatingAway && !OC._reloadCalled) {
+				let timer = 0
+				const seconds = 5
+				const interval = setInterval(function () {
+						Notification.showUpdate(n('core', 'Problem loading page, reloading in %n second', 'Problem loading page, reloading in %n seconds', seconds - timer))
+						if (timer >= seconds) {
+							clearInterval(interval)
+							OC.reload()
+						}
+						timer++
+					}, 1000 // 1 second interval
+				)
+
+				// only call reload once
+				OC._reloadCalled = true
+			}
+		}, 100)
+	} else if (xhr.status === 0) {
+		// Connection lost (e.g. WiFi disconnected or server is down)
+		setTimeout(function () {
+			if (!OC._userIsNavigatingAway && !OC._reloadCalled) {
+				// TODO: call method above directly
+				OC._ajaxConnectionLostHandler()
+			}
+		}, 100)
+	}
+}
+
+/**
+ * Registers XmlHttpRequest object for global error processing.
+ *
+ * This means that if this XHR object returns 401 or session timeout errors,
+ * the current page will automatically be reloaded.
+ *
+ * @param {XMLHttpRequest} xhr
+ */
+export const registerXHRForErrorProcessing = xhr => {
+	const loadCallback = () => {
+		if (xhr.readyState !== 4) {
+			return
+		}
+
+		if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
+			return
+		}
+
+		// fire jquery global ajax error handler
+		$(document).trigger(new $.Event('ajaxError'), xhr)
+	}
+
+	const errorCallback = () => {
+		// fire jquery global ajax error handler
+		$(document).trigger(new $.Event('ajaxError'), xhr)
+	}
+
+	if (xhr.addEventListener) {
+		xhr.addEventListener('load', loadCallback)
+		xhr.addEventListener('error', errorCallback)
+	}
+
+}