diff --git a/core/js/apps.js b/core/js/apps.js
index 5f221bb9826a045b294741ffa057ddc7d1bb15f2..21fae58985eb6c479746a465f2c532d88a48e199 100644
--- a/core/js/apps.js
+++ b/core/js/apps.js
@@ -10,67 +10,78 @@
 
 (function (document, $, exports) {
 
-    'use strict';
-
-    var dynamicSlideToggleEnabled = false;
-
-    exports.Apps = {
-        enableDynamicSlideToggle: function () {
-            dynamicSlideToggleEnabled = true;
-        }
-    };
-
-    /**
-     * Provides a way to slide down a target area through a button and slide it
-     * up if the user clicks somewhere else. Used for the news app settings and
-     * add new field.
-     *
-     * Usage:
-     * <button data-apps-slide-toggle=".slide-area">slide</button>
-     * <div class=".slide-area" class="hidden">I'm sliding up</div>
-     */
-    var registerAppsSlideToggle = function () {
-        var buttons = $('[data-apps-slide-toggle]');
-
-        $(document).click(function (event) {
-
-            if (dynamicSlideToggleEnabled) {
-                buttons = $('[data-apps-slide-toggle]');
-            }
-
-            buttons.each(function (index, button) {
-
-                var areaSelector = $(button).data('apps-slide-toggle');
-                var area = $(areaSelector);
-
-                // do nothing if the area is animated
-                if (!area.is(':animated')) {
-
-                    // button toggles the area
-                    if (button === event.target) {
-                        if (area.is(':visible')) {
-                            area.slideUp();
-                        } else {
-                            area.slideDown();
-                        }
-
-                    // all other areas that have not been clicked but are open
-                    // should be slid up
-                    } else {
-                        var closest = $(event.target).closest(areaSelector);
-                        if (area.is(':visible') && closest[0] !== area[0]) {
-                            area.slideUp();
-                        }
-                    }
-                }
-            });
-
-        });
-    };
-
-
-    $(document).ready(function () {
-        registerAppsSlideToggle();
-    });
-
-}(document, jQuery, OC));
\ No newline at end of file
+	'use strict';
+
+	var dynamicSlideToggleEnabled = false;
+
+	exports.Apps = {
+		enableDynamicSlideToggle: function () {
+			dynamicSlideToggleEnabled = true;
+		}
+	};
+
+	/**
+	 * Provides a way to slide down a target area through a button and slide it
+	 * up if the user clicks somewhere else. Used for the news app settings and
+	 * add new field.
+	 *
+	 * Usage:
+	 * <button data-apps-slide-toggle=".slide-area">slide</button>
+	 * <div class=".slide-area" class="hidden">I'm sliding up</div>
+	 */
+	var registerAppsSlideToggle = function () {
+		var buttons = $('[data-apps-slide-toggle]');
+
+		$(document).click(function (event) {
+
+			if (dynamicSlideToggleEnabled) {
+				buttons = $('[data-apps-slide-toggle]');
+			}
+
+			buttons.each(function (index, button) {
+
+				var areaSelector = $(button).data('apps-slide-toggle');
+				var area = $(areaSelector);
+
+				function hideArea() {
+					area.slideUp(function() {
+						area.trigger(new $.Event('hide'));
+					});
+				}
+				function showArea() {
+					area.slideDown(function() {
+						area.trigger(new $.Event('show'));
+					});
+				}
+
+				// do nothing if the area is animated
+				if (!area.is(':animated')) {
+
+					// button toggles the area
+					if (button === event.target) {
+						if (area.is(':visible')) {
+							hideArea();
+						} else {
+							showArea();
+						}
+
+					// all other areas that have not been clicked but are open
+					// should be slid up
+					} else {
+						var closest = $(event.target).closest(areaSelector);
+						if (area.is(':visible') && closest[0] !== area[0]) {
+							hideArea();
+						}
+					}
+				}
+			});
+
+		});
+	};
+
+
+	$(document).ready(function () {
+		registerAppsSlideToggle();
+	});
+
+}(document, jQuery, OC));
diff --git a/core/js/singleselect.js b/core/js/singleselect.js
index c22b5232207908b1d9d11c074e1589bd0f0a2a4d..1b2016aabb97afb97610e2961822d1e71dd2e7f4 100644
--- a/core/js/singleselect.js
+++ b/core/js/singleselect.js
@@ -2,10 +2,14 @@
 	$.fn.singleSelect = function () {
 		return this.each(function (i, select) {
 			var input = $('<input/>'),
+				gravity = $(select).attr('data-tipsy-gravity'),
 				inputTooltip = $(select).attr('data-inputtitle');
 			if (inputTooltip){
 				input.attr('title', inputTooltip);
 			}
+			if (typeof gravity === 'undefined') {
+				gravity = 'n'
+			}
 			select = $(select);
 			input.css('position', 'absolute');
 			input.css({
@@ -35,7 +39,7 @@
 					input.css(select.offset());
 					input.show();
 					if ($.fn.tipsy){
-						input.tipsy({gravity: 'n', trigger: 'manual'});
+						input.tipsy({gravity: gravity, trigger: 'manual'});
 						input.tipsy('show');
 					}
 					select.css('background-color', 'white');
@@ -83,6 +87,10 @@
 					$(this).tipsy('hide');
 				}
 			});
+			input.click(function(ev) {
+				// prevent clicks to close any container
+				ev.stopPropagation();
+			});
 		});
 	};
 })(jQuery);
diff --git a/settings/js/users/groups.js b/settings/js/users/groups.js
index fe06edff34d7a48c43b542a0dd1428c90baceaf4..258b6aa7efd6f4dc45e8ea43dcee2ac11cfe185d 100644
--- a/settings/js/users/groups.js
+++ b/settings/js/users/groups.js
@@ -289,28 +289,4 @@ $(document).ready( function () {
 	$userGroupList.on('click', '.isgroup', function () {
 		GroupList.showGroup(GroupList.getElementGID(this));
 	});
-
-	// Implements Quota Settings Toggle.
-	var $appSettings = $('#app-settings');
-	$('#app-settings-header').on('click keydown',function(event) {
-		if(wrongKey(event)) {
-			return;
-		}
-		if($appSettings.hasClass('open')) {
-			$appSettings.switchClass('open', '');
-		} else {
-			$appSettings.switchClass('', 'open');
-		}
-	});
-	$('body').on('click', function(event){
-		if($appSettings.find(event.target).length === 0) {
-			$appSettings.switchClass('open', '');
-		}
-	});
-
 });
-
-var wrongKey = function(event) {
-	return ((event.type === 'keydown' || event.type === 'keypress') &&
-		(event.keyCode !== 32 && event.keyCode !== 13));
-};
diff --git a/settings/js/users/users.js b/settings/js/users/users.js
index 883851e2a2f62cc06b7b3696748495bb452c163c..60948bb99f31f14cea4f69e689aec824da72796b 100644
--- a/settings/js/users/users.js
+++ b/settings/js/users/users.js
@@ -18,6 +18,18 @@ var UserList = {
 	usersToLoad: 10, //So many users will be loaded when user scrolls down
 	currentGid: '',
 
+	/**
+	 * Initializes the user list
+	 * @param $el user list table element
+	 */
+	initialize: function($el) {
+		this.$el = $el;
+
+		// initially the list might already contain user entries (not fully ajaxified yet)
+		// initialize these entries
+		this.$el.find('.quota-user').singleSelect().on('change', this.onQuotaSelect);
+	},
+
 	add: function (username, displayname, groups, subadmin, quota, storageLocation, lastLogin, sort) {
 		var $tr = $userListBody.find('tr:first-child').clone();
 		var subAdminsEl;
@@ -109,15 +121,7 @@ var UserList = {
 			UserList.doSort();
 		}
 
-		$quotaSelect.on('change', function () {
-			var uid = UserList.getUID(this);
-			var quota = $(this).val();
-			setQuota(uid, quota, function(returnedQuota){
-				if (quota !== returnedQuota) {
-					$($quotaSelect).find(':selected').text(returnedQuota);
-				}
-			});
-		});
+		$quotaSelect.on('change', UserList.onQuotaSelect);
 
 		// defer init so the user first sees the list appear more quickly
 		window.setTimeout(function(){
@@ -496,20 +500,41 @@ var UserList = {
 		if (UserList.scrollArea.scrollTop() + UserList.scrollArea.height() > UserList.scrollArea.get(0).scrollHeight - 500) {
 			UserList.update(UserList.currentGid, true);
 		}
-	}
-};
+	},
 
-function setQuota (uid, quota, ready) {
-	$.post(
-		OC.filePath('settings', 'ajax', 'setquota.php'),
-		{username: uid, quota: quota},
-		function (result) {
-			if (ready) {
-				ready(result.data.quota);
+	/**
+	 * Event handler for when a quota has been changed through a single select.
+	 * This will save the value.
+	 */
+	onQuotaSelect: function(ev) {
+		var $select = $(ev.target);
+		var uid = UserList.getUID($select);
+		var quota = $select.val();
+		UserList._updateQuota(uid, quota, function(returnedQuota){
+			if (quota !== returnedQuota) {
+				$select.find(':selected').text(returnedQuota);
 			}
-		}
-	);
-}
+		});
+	},
+
+	/**
+	 * Saves the quota for the given user
+	 * @param {String} [uid] optional user id, sets default quota if empty
+	 * @param {String} quota quota value
+	 * @param {Function} ready callback after save
+	 */
+	_updateQuota: function(uid, quota, ready) {
+		$.post(
+			OC.filePath('settings', 'ajax', 'setquota.php'),
+			{username: uid, quota: quota},
+			function (result) {
+				if (ready) {
+					ready(result.data.quota);
+				}
+			}
+		);
+	}
+};
 
 $(document).ready(function () {
 	$userList = $('#userlist');
@@ -528,6 +553,9 @@ $(document).ready(function () {
 
 	$userList.after($('<div class="loading" style="height: 200px; visibility: hidden;"></div>'));
 
+	// TODO: move other init calls inside of initialize
+	UserList.initialize($('#userlist'));
+
 	$('.groupsselect').each(function (index, element) {
 		UserList.applyGroupSelect(element);
 	});
@@ -611,15 +639,9 @@ $(document).ready(function () {
 			});
 	});
 
-	$('#default_quota, .quota-user').singleSelect().on('change', function () {
-		var $select = $(this);
-		var uid = UserList.getUID($select);
-		var quota = $select.val();
-		setQuota(uid, quota, function(returnedQuota){
-			if (quota !== returnedQuota) {
-				$select.find(':selected').text(returnedQuota);
-			}
-		});
+	// init the quota field select box after it is shown the first time
+	$('#app-settings').one('show', function() {
+		$(this).find('#default_quota').singleSelect().on('change', UserList.onQuotaSelect);
 	});
 
 	$('#newuser').submit(function (event) {
diff --git a/settings/templates/users/part.setquota.php b/settings/templates/users/part.setquota.php
index fc5624d069aaee853d6b431c776e60f877200070..afbbee82063ae4c4eec17f0298fd359b128622d1 100644
--- a/settings/templates/users/part.setquota.php
+++ b/settings/templates/users/part.setquota.php
@@ -1,12 +1,12 @@
 <div id="app-settings-header">
-	<button class="settings-button" tabindex="0"></button>
+	<button class="settings-button" tabindex="0" data-apps-slide-toggle="#app-settings-content"></button>
 </div>
 <div id="app-settings-content">
 	<div class="quota">
 		<!-- Default storage -->
 		<span><?php p($l->t('Default Quota'));?></span>
 		<?php if((bool) $_['isAdmin']): ?>
-			<select id='default_quota' data-inputtitle="<?php p($l->t('Please enter storage quota (ex: "512 MB" or "12 GB")')) ?>">
+			<select id='default_quota' data-inputtitle="<?php p($l->t('Please enter storage quota (ex: "512 MB" or "12 GB")')) ?>" data-tipsy-gravity="s">
 				<option <?php if($_['default_quota'] === 'none') print_unescaped('selected="selected"');?> value='none'>
 					<?php p($l->t('Unlimited'));?>
 				</option>
@@ -36,4 +36,4 @@
 			</select>
 		<?php endif; ?>
 	</div>
-</div>
\ No newline at end of file
+</div>