diff --git a/core/js/js.js b/core/js/js.js
index 096cc3ad7c137fe8ad1e4bc9ce525803975500e2..968bf650ad52b6f51f6df32fdb8136298cb70a6c 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -668,6 +668,7 @@ OC.Notification={
 				callback.call();
 			}
 			$('#notification').empty();
+			console.log('OCNO EMPTY');
 			if(OC.Notification.queuedNotifications.length > 0){
 				OC.Notification.showHtml(OC.Notification.queuedNotifications[0]);
 				OC.Notification.queuedNotifications.shift();
diff --git a/settings/ajax/creategroup.php b/settings/ajax/creategroup.php
index 0a79527c219f70131e97dfaa8654165338c322a0..f78d123270efd3c02f78df4c101ca35108e5cf89 100644
--- a/settings/ajax/creategroup.php
+++ b/settings/ajax/creategroup.php
@@ -4,6 +4,7 @@ OCP\JSON::callCheck();
 OC_JSON::checkAdminUser();
 
 $groupname = $_POST["groupname"];
+$l = OC_L10N::get('core');
 
 // Does the group exist?
 if( in_array( $groupname, OC_Group::getGroups())) {
diff --git a/settings/js/users/deleteHandler.js b/settings/js/users/deleteHandler.js
new file mode 100644
index 0000000000000000000000000000000000000000..83d1cafc30dcceaf4428ba8d8e6a71271de5663b
--- /dev/null
+++ b/settings/js/users/deleteHandler.js
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+
+/**
+ * @brief takes care of deleting things represented by an ID
+ * @param String endpoint: the corresponding ajax PHP script. Currently limited
+ * to settings - ajax path.
+ * @param String paramID: the by the script expected parameter name holding the
+ * ID of the object to delete
+ * @param Function markCallback: the function to be called after successfully
+ * marking the object for deletion.
+ * @param Function removeCallback: the function to be called after successful
+ * delete. The id of the object will be passed as argument. Insuccessful
+ * operations will display an error using OC.dialogs, no callback is fired.
+ */
+function DeleteHandler(endpoint, paramID, markCallback, removeCallback) {
+	this.oidToDelete = false;
+	this.canceled = false;
+
+	this.ajaxEndpoint = endpoint;
+	this.ajaxParamID = paramID;
+
+	this.markCallback = markCallback;
+	this.removeCallback = removeCallback;
+	this.undoCallback = false;
+
+	this.notifier = false;
+	this.notificationDataID = false;
+	this.notificationMessage = false;
+	this.notificationPlaceholder = '%oid';
+}
+
+/**
+ * @brief enabled the notification system. Required for undo UI.
+ * @param Object notifier: Usually OC.Notification
+ * @param String dataID: an identifier for the notificatior, e.g. 'deleteuser'
+ * @param String message: the message that should be shown upon delete. %oid
+ * will be replaced with the affected id of the item to be deleted
+ * @param Function undoCb: called after "undo" was clicked so consument can
+ * update the web interface
+ */
+DeleteHandler.prototype.setNotification = function(notifier, dataID, message, undoCb) {
+	this.notifier = notifier;
+	this.notificationDataID = dataID;
+	this.notificationMessage = message;
+	this.undoCallback = undoCb;
+
+	dh = this;
+
+	$('#notification').on('click', '.undo', function () {
+		if ($('#notification').data(dh.notificationDataID)) {
+			oid = dh.oidToDelete;
+			UserDeleteHandler.cancel();
+			if(typeof dh.undoCallback !== 'undefined') {
+				dh.undoCallback(oid);
+			}
+		}
+		dh.notifier.hide();
+	});
+}
+
+/**
+ * @brief shows the Undo Notification (if configured)
+ */
+DeleteHandler.prototype.showNotification = function() {
+	if(this.notifier !== false) {
+		if(!this.notifier.isHidden()) {
+			this.hideNotification();
+		}
+		$('#notification').data(this.notificationDataID, true);
+		msg = this.notificationMessage.replace(this.notificationPlaceholder,
+											this.oidToDelete);
+		console.log('NOTISHOW ' + msg);
+		this.notifier.showHtml(msg);
+	}
+}
+
+/**
+ * @brief hides the Undo Notification
+ */
+DeleteHandler.prototype.hideNotification = function() {
+	if(this.notifier !== false) {
+		$('#notification').removeData(this.notificationDataID);
+		this.notifier.hide();
+	}
+}
+
+/**
+ * @brief initilizes the delete operation for a given object id
+ * @param String oid: the object id
+ */
+DeleteHandler.prototype.mark = function(oid) {
+	if(this.oidToDelete !== false) {
+		this.delete();
+	}
+	this.oidToDelete = oid;
+	this.canceled = false;
+	this.markCallback(oid);
+	this.showNotification();
+}
+
+/**
+ * @brief cancels a delete operation
+ */
+DeleteHandler.prototype.cancel = function(oid) {
+	this.canceled = true;
+	this.oidToDelete = false;
+}
+
+/**
+ * @brief executes a delete operation. Requires that the operation has been
+ * initilized by mark(). On error, it will show a message via
+ * OC.dialogs.alert. On success, a callback is fired so that the client can
+ * update the web interface accordingly.
+ */
+DeleteHandler.prototype.delete = function() {
+	if(this.canceled || this.oidToDelete === false) {
+		return false;
+	}
+
+	dh = this;
+	console.log($('#notification').data(this.notificationDataID));
+	if($('#notification').data(this.notificationDataID) === true) {
+		dh.hideNotification();
+		console.log('HIDDEN NOTI');
+	}
+
+	payload = {};
+	payload[dh['ajaxParamID']] = dh.oidToDelete;
+	$.ajax({
+		type: 'POST',
+		url: OC.filePath('settings', 'ajax', dh.ajaxEndpoint),
+		async: false,
+		data: payload,
+		success: function (result) {
+			if (result.status === 'success') {
+				// Remove undo option, & remove user from table
+
+				//TODO: following line
+				dh.removeCallback(dh.oidToDelete);
+				dh.canceled = true;
+				console.log(dh.ajaxEndpoint);
+			} else {
+				OC.dialogs.alert(result.data.message, t('settings', 'Unable to delete ' + escapeHTML(dh.oidToDelete)));
+				dh.undoCallback(dh.oidToDelete);
+			}
+		}
+	});
+}
\ No newline at end of file
diff --git a/settings/js/users/groups.js b/settings/js/users/groups.js
index fcb173de80ade15e9f72a5a49dd0dbc9fb960b85..f5a2ce755b36ec8766ea9e9cab81faf17a74e10c 100644
--- a/settings/js/users/groups.js
+++ b/settings/js/users/groups.js
@@ -61,19 +61,6 @@
 		)
 	},
 
-	delete_group: function (gid) {
-		if(GroupList.deleteGid !=='undefined') {
-			GroupList.finishDelete(null);
-		}
-
-		//Set the undo flag
-		GroupList.deleteCanceled = false;
-
-		//Provide an option to undo
-		$('#notification').data('deletegroup', true);
-		OC.Notification.showHtml(t('settings', 'deleted') + ' ' + escapeHTML(gid) + '<span class="undo">' + t('settings', 'undo') + '</span>');
-	},
-
 	elementBelongsToAddGroup: function(el) {
 		return !(el !== $('#newgroup-form').get(0)
 				&& $('#newgroup-form').find($(el)).length === 0);
@@ -124,40 +111,44 @@
 		return true;
 	},
 
-	finishDelete: function (ready) {
-		if (!GroupList.deleteCanceled && GroupList.deleteGid) {
-			$.ajax({
-				type: 'POST',
-				url: OC.filePath('settings', 'ajax', 'removegroup.php'),
-				async: false,
-				data: { groupname: GroupList.deleteGid },
-				success: function (result) {
-					if (result.status === 'success') {
-						// Remove undo option, & remove user from table
-						OC.Notification.hide();
-						$('li').filterAttr('data-gid', GroupList.deleteGid).remove();
-						GroupList.deleteCanceled = true;
-						if (ready) {
-							ready();
-						}
-					} else {
-						OC.dialogs.alert(result.data.message, t('settings', 'Unable to remove group'));
-					}
-				}
-			});
-		}
+	hide: function(gid) {
+		$('li[data-gid="' + gid + '"]').hide();
+	},
+	show: function(gid) {
+		$('li[data-gid="' + gid + '"]').show();
+	},
+	remove: function(gid) {
+		$('li').filterAttr('data-gid', gid).remove();
+	},
+	initDeleteHandling: function() {
+		//set up handler
+		GroupDeleteHandler = new DeleteHandler('removegroup.php', 'groupname',
+											  GroupList.hide, GroupList.remove);
+
+		//configure undo
+		OC.Notification.hide();
+		msg = t('settings', 'deleted') + ' %oid <span class="undo">' +
+			  t('settings', 'undo') + '</span>';
+		GroupDeleteHandler.setNotification(OC.Notification, 'deletegroup', msg,
+										  GroupList.show);
+
+		//when to mark user for delete
+		$('ul').on('click', 'span.utils>a', function (event) {
+			// Call function for handling delete/undo
+			gid = $(this).parent().parent().attr('data-gid');
+			GroupDeleteHandler.mark(gid);
+		});
 
+		console.log('init del groups');
+		//delete a marked user when leaving the page
+		$(window).on('beforeunload', function () {
+			GroupDeleteHandler.delete();
+		});
 	},
 }
 
 $(document).ready( function () {
-	$('ul').on('click', 'span.utils>a', function (event) {
-		var li = $(this).parent().parent();
-		var gid = $(li).attr('data-gid');
-		$(li).hide();
-		// Call function for handling delete/undo on Groups
-		GroupList.delete_group(gid);
-	});
+	GroupList.initDeleteHandling();
 
 	// Display or hide of Create Group List Element
 	$('#newgroup-form').hide();
@@ -191,7 +182,6 @@ $(document).ready( function () {
 	$('ul').on('click', 'li[data-gid]', function (event) {
 		var li = $(this);
 		var gid = $(li).attr('data-gid');
-		// Call function for handling delete/undo on Groups
 		GroupList.showGroup(gid);
 	});
 
diff --git a/settings/js/users/users.js b/settings/js/users/users.js
index e939d1d3bfc620d4e9607b5c6f909aa8daf7e24d..708451dbaca8c7ebb7271018883d3263e70355b2 100644
--- a/settings/js/users/users.js
+++ b/settings/js/users/users.js
@@ -5,7 +5,6 @@
  */
 
 var UserList = {
-	useUndo: true,
 	availableGroups: [],
 	offset: 30, //The first 30 users are there. No prob, if less in total.
 				//hardcoded in settings/users.php
@@ -13,65 +12,6 @@ var UserList = {
 	usersToLoad: 10, //So many users will be loaded when user scrolls down
 	currentGid: '',
 
-	/**
-	 * @brief Initiate user deletion process in UI
-	 * @param string uid the user ID to be deleted
-	 *
-	 * Does not actually delete the user; it sets them for
-	 * deletion when the current page is unloaded, at which point
-	 * finishDelete() completes the process. This allows for 'undo'.
-	 */
-	do_delete: function (uid) {
-		if (typeof UserList.deleteUid !== 'undefined') {
-			//Already a user in the undo queue
-			UserList.finishDelete(null);
-		}
-		UserList.deleteUid = uid;
-
-		// Set undo flag
-		UserList.deleteCanceled = false;
-
-		// Provide user with option to undo
-		$('#notification').data('deleteuser', true);
-		OC.Notification.showHtml(t('settings', 'deleted') + ' ' + escapeHTML(uid) + '<span class="undo">' + t('settings', 'undo') + '</span>');
-	},
-
-	/**
-	 * @brief Delete a user via ajax
-	 * @param bool ready whether to use ready() upon completion
-	 *
-	 * Executes deletion via ajax of user identified by property deleteUid
-	 * if 'undo' has not been used.  Completes the user deletion procedure
-	 * and reflects success in UI.
-	 */
-	finishDelete: function (ready) {
-
-		// Check deletion has not been undone
-		if (!UserList.deleteCanceled && UserList.deleteUid) {
-
-			// Delete user via ajax
-			$.ajax({
-				type: 'POST',
-				url: OC.filePath('settings', 'ajax', 'removeuser.php'),
-				async: false,
-				data: { username: UserList.deleteUid },
-				success: function (result) {
-					if (result.status === 'success') {
-						// Remove undo option, & remove user from table
-						OC.Notification.hide();
-						$('tr').filterAttr('data-uid', UserList.deleteUid).remove();
-						UserList.deleteCanceled = true;
-						if (ready) {
-							ready();
-						}
-					} else {
-						OC.dialogs.alert(result.data.message, t('settings', 'Unable to remove user'));
-					}
-				}
-			});
-		}
-	},
-
 	add: function (username, displayname, groups, subadmin, quota, storageLocation, lastLogin, sort) {
 		var tr = $('tbody tr').first().clone();
 		var subadminsEl;
@@ -229,6 +169,40 @@ var UserList = {
 		UserList.isEmpty = true;
 		UserList.offset = 0;
 	},
+	hide: function(uid) {
+		$('tr[data-uid="' + uid + '"]').hide();
+	},
+	show: function(uid) {
+		$('tr[data-uid="' + uid + '"]').show();
+	},
+	remove: function(uid) {
+		$('tr').filterAttr('data-uid', uid).remove();
+	},
+	initDeleteHandling: function() {
+		//set up handler
+		UserDeleteHandler = new DeleteHandler('removeuser.php', 'username',
+											  UserList.hide, UserList.remove);
+
+		//configure undo
+		OC.Notification.hide();
+		msg = t('settings', 'deleted') + ' %oid <span class="undo">' +
+			  t('settings', 'undo') + '</span>';
+		UserDeleteHandler.setNotification(OC.Notification, 'deleteuser', msg,
+										  UserList.show);
+
+		//when to mark user for delete
+		$('table').on('click', 'td.remove>a', function (event) {
+			// Call function for handling delete/undo
+			uid = $(this).parent().parent().attr('data-uid');
+			UserDeleteHandler.mark(uid);
+		});
+
+		//delete a marked user when leaving the page
+		console.log('init del users');
+		$(window).on('beforeunload', function () {
+			UserDeleteHandler.delete();
+		});
+	},
 	update: function (gid) {
 		if (UserList.updating) {
 			return;
@@ -394,6 +368,7 @@ function setQuota (uid, quota, ready) {
 }
 
 $(document).ready(function () {
+	UserList.initDeleteHandling();
 
 	UserList.doSort();
 	UserList.availableGroups = $('#content table').data('groups');
@@ -405,13 +380,7 @@ $(document).ready(function () {
 		UserList.applyMultiplySelect($(element));
 	});
 
-	$('table').on('click', 'td.remove>a', function (event) {
-		var row = $(this).parent().parent();
-		var uid = $(row).attr('data-uid');
-		$(row).hide();
-		// Call function for handling delete/undo
-		UserList.do_delete(uid);
-	});
+
 
 	$('table').on('click', 'td.password>img', function (event) {
 		event.stopPropagation();
@@ -568,17 +537,5 @@ $(document).ready(function () {
 		});
 	});
 
-	// Handle undo notifications
-	OC.Notification.hide();
-	$('#notification').on('click', '.undo', function () {
-		if ($('#notification').data('deleteuser')) {
-			$('tbody tr').filterAttr('data-uid', UserList.deleteUid).show();
-			UserList.deleteCanceled = true;
-		}
-		OC.Notification.hide();
-	});
-	UserList.useUndo = ('onbeforeunload' in window);
-	$(window).bind('beforeunload', function () {
-		UserList.finishDelete(null);
-	});
+
 });
diff --git a/settings/users.php b/settings/users.php
index 7bf240fa16eb004decb56ee2a1b06c97b83b5795..c0c1adc74c7dc069811fa2e49816b15accf9cec8 100644
--- a/settings/users.php
+++ b/settings/users.php
@@ -8,6 +8,7 @@
 OC_Util::checkSubAdminUser();
 
 // We have some javascript foo!
+OC_Util::addScript('settings', 'users/deleteHandler');
 OC_Util::addScript( 'settings', 'users/users' );
 OC_Util::addScript( 'settings', 'users/groups' );
 OC_Util::addScript( 'core', 'multiselect' );