Skip to content

Commit

Permalink
Backport of Users page lazy multiselect group dropdowns #1128 to stab…
Browse files Browse the repository at this point in the history
…le10

Users page lazy multiselect group dropdowns

Instead of pre-rendering all multiselects with lots of group entries,
the current groups are now displayed as simple labels.
Behind the labels there is a pencil icon like for other fields.
When clicking the pencil icon, the dropdown will be spawned and will
open itself.
Upon closing of the dropdown, the label comes back with the updated
selection and the dropdown is destroyed.

Extra non-available groups also in list

Fix group sorting in user list group selection
  • Loading branch information
Vincent Petry authored and blizzz committed Aug 29, 2016
1 parent dbc860e commit 3a0a84e
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 119 deletions.
52 changes: 29 additions & 23 deletions core/js/multiselect.js
Expand Up @@ -32,7 +32,7 @@
'onuncheck':false,
'minWidth': 'default;'
};
var slideDuration = 200;
var slideDuration = 0;
$(this).attr('data-msid', multiSelectId);
$.extend(settings,options);
$.each(this.children(),function(i,option) {
Expand Down Expand Up @@ -75,6 +75,26 @@

var self = this;
self.menuDirection = 'down';

function closeDropDown() {
if(!button.parent().data('preventHide')) {
// How can I save the effect in a var?
if(self.menuDirection === 'down') {
button.parent().children('ul').slideUp(slideDuration,function() {
button.parent().children('ul').remove();
button.removeClass('active down');
$(self).trigger($.Event('dropdownclosed', settings));
});
} else {
button.parent().children('ul').fadeOut(slideDuration,function() {
button.parent().children('ul').remove();
button.removeClass('active up');
$(self).trigger($.Event('dropdownclosed', settings));
});
}
}
}

button.click(function(event){

var button=$(this);
Expand All @@ -83,21 +103,20 @@
button.parent().children('ul').slideUp(slideDuration,function() {
button.parent().children('ul').remove();
button.removeClass('active down');
$(self).trigger($.Event('dropdownclosed', settings));
});
} else {
button.parent().children('ul').fadeOut(slideDuration,function() {
button.parent().children('ul').remove();
button.removeClass('active up');
$(self).trigger($.Event('dropdownclosed', settings));
});
}
return;
}
// tell other lists to shut themselves
var lists=$('ul.multiselectoptions');
lists.slideUp(slideDuration,function(){
lists.remove();
$('div.multiselect').removeClass('active');
button.addClass('active');
});
lists.trigger($.Event('shut'));
button.addClass('active');
event.stopPropagation();
var options=$(this).parent().next().children();
Expand Down Expand Up @@ -309,29 +328,16 @@
list.detach().insertBefore($(this));
list.addClass('up');
button.addClass('up');
list.fadeIn();
list.show();
self.menuDirection = 'up';
}
list.click(function(event) {
event.stopPropagation();
});
list.one('shut', closeDropDown);
});
$(window).click(function() {
if(!button.parent().data('preventHide')) {
// How can I save the effect in a var?
if(self.menuDirection === 'down') {
button.parent().children('ul').slideUp(slideDuration,function() {
button.parent().children('ul').remove();
button.removeClass('active down');
});
} else {
button.parent().children('ul').fadeOut(slideDuration,function() {
button.parent().children('ul').remove();
button.removeClass('active up');
});
}
}
});

$(window).click(closeDropDown);

return span;
};
Expand Down
9 changes: 9 additions & 0 deletions settings/css/settings.css
Expand Up @@ -258,6 +258,15 @@ span.usersLastLoginTooltip { white-space: nowrap; }
top: 3px;
}

#newuser .groups {
display: inline;
}

#newuser .groupsListContainer.hidden,
#userlist .groupsListContainer.hidden {
display: none;
}

tr:hover>td.password>span, tr:hover>td.displayName>span { margin:0; cursor:pointer; }
tr:hover>td.remove>a, tr:hover>td.password>img,tr:hover>td.displayName>img, tr:hover>td.quota>img { visibility:visible; cursor:pointer; }
td.remove {
Expand Down
4 changes: 0 additions & 4 deletions settings/js/users/groups.js
Expand Up @@ -136,10 +136,6 @@ GroupList = {
var addedGroup = result.groupname;
UserList.availableGroups = $.unique($.merge(UserList.availableGroups, [addedGroup]));
GroupList.addGroup(result.groupname);

$('.groupsselect, .subadminsselect')
.append($('<option>', { value: result.groupname })
.text(result.groupname));
}
GroupList.toggleAddGroup();
}).fail(function(result) {
Expand Down
174 changes: 96 additions & 78 deletions settings/js/users/users.js
Expand Up @@ -57,9 +57,6 @@ var UserList = {
var $tr = $userListBody.find('tr:first-child').clone();
// this removes just the `display:none` of the template row
$tr.removeAttr('style');
var subAdminsEl;
var subAdminSelect;
var groupsSelect;

/**
* Avatar or placeholder
Expand All @@ -86,32 +83,17 @@ var UserList = {
$tr.find('td.mailAddress > .action').tooltip({placement: 'top'});
$tr.find('td.password > .action').tooltip({placement: 'top'});


/**
* groups and subadmins
*/
// make them look like the multiselect buttons
// until they get time to really get initialized
groupsSelect = $('<select multiple="multiple" class="groupsselect multiselect button" data-placehoder="Groups" title="' + t('settings', 'no group') + '"></select>')
.data('username', user.name)
.data('user-groups', user.groups);
if ($tr.find('td.subadmins').length > 0) {
subAdminSelect = $('<select multiple="multiple" class="subadminsselect multiselect button" data-placehoder="subadmins" title="' + t('settings', 'no group') + '">')
.data('username', user.name)
.data('user-groups', user.groups)
.data('subadmin', user.subadmin);
$tr.find('td.subadmins').empty();
}
$.each(this.availableGroups, function (i, group) {
groupsSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
if (typeof subAdminSelect !== 'undefined' && group !== 'admin') {
subAdminSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
}
});
$tr.find('td.groups').empty().append(groupsSelect);
subAdminsEl = $tr.find('td.subadmins');
if (subAdminsEl.length > 0) {
subAdminsEl.append(subAdminSelect);
}
var $tdGroups = $tr.find('td.groups');
this._updateGroupListLabel($tdGroups, user.groups);
$tdGroups.find('.action').tooltip({placement: 'top'});

var $tdSubadmins = $tr.find('td.subadmins');
this._updateGroupListLabel($tdSubadmins, user.subadmin);
$tdSubadmins.find('.action').tooltip({placement: 'top'});

/**
* remove action
Expand Down Expand Up @@ -198,10 +180,6 @@ var UserList = {
// defer init so the user first sees the list appear more quickly
window.setTimeout(function(){
$quotaSelect.singleSelect();
UserList.applyGroupSelect(groupsSelect);
if (subAdminSelect) {
UserList.applySubadminSelect(subAdminSelect);
}
}, 0);
return $tr;
},
Expand Down Expand Up @@ -322,7 +300,7 @@ var UserList = {
},
markRemove: function(uid) {
var $tr = UserList.getRow(uid);
var groups = $tr.find('.groups .groupsselect').val();
var groups = $tr.find('.groups').data('groups');
for(var i in groups) {
var gid = groups[i];
var $li = GroupList.getGroupLI(gid);
Expand All @@ -337,7 +315,7 @@ var UserList = {
},
undoRemove: function(uid) {
var $tr = UserList.getRow(uid);
var groups = $tr.find('.groups .groupsselect').val();
var groups = $tr.find('.groups').data('groups');
for(var i in groups) {
var gid = groups[i];
var $li = GroupList.getGroupLI(gid);
Expand Down Expand Up @@ -438,19 +416,9 @@ var UserList = {
});
},

applyGroupSelect: function (element) {
var checked = [];
applyGroupSelect: function (element, user, checked) {
var $element = $(element);
var user = UserList.getUID($element);

if ($element.data('user-groups')) {
if (typeof $element.data('user-groups') === 'string') {
checked = $element.data('user-groups').split(", ");
}
else {
checked = $element.data('user-groups');
}
}
var checkHandler = null;
if(user) { // Only if in a user row, and not the #newusergroups select
checkHandler = function (group) {
Expand Down Expand Up @@ -490,13 +458,6 @@ var UserList = {
};
}
var addGroup = function (select, group) {
$('select[multiple]').each(function (index, element) {
$element = $(element);
if ($element.find('option').filterAttr('value', group).length === 0 &&
select.data('msid') !== $element.data('msid')) {
$element.append('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>');
}
});
GroupList.addGroup(escapeHTML(group));
};
var label;
Expand All @@ -517,19 +478,8 @@ var UserList = {
});
},

applySubadminSelect: function (element) {
var checked = [];
applySubadminSelect: function (element, user, checked) {
var $element = $(element);
var user = UserList.getUID($element);

if ($element.data('subadmin')) {
if (typeof $element.data('subadmin') === 'string') {
checked = $element.data('subadmin').split(", ");
}
else {
checked = $element.data('subadmin');
}
}
var checkHandler = function (group) {
if (group === 'admin') {
return false;
Expand All @@ -545,15 +495,7 @@ var UserList = {
);
};

var addSubAdmin = function (group) {
$('select[multiple]').each(function (index, element) {
if ($(element).find('option').filterAttr('value', group).length === 0) {
$(element).append('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>');
}
});
};
$element.multiSelect({
createCallback: addSubAdmin,
createText: null,
checked: checked,
oncheck: checkHandler,
Expand Down Expand Up @@ -611,6 +553,76 @@ var UserList = {
}
}
);
},

/**
* Creates a temporary jquery.multiselect selector on the given group field
*/
_triggerGroupEdit: function($td, isSubadminSelect) {
var $groupsListContainer = $td.find('.groupsListContainer');
var placeholder = $groupsListContainer.attr('data-placeholder') || t('settings', 'no group');
var user = UserList.getUID($td);
var checked = $td.data('groups') || [];
var extraGroups = [].concat(checked);

$td.find('.multiselectoptions').remove();

// jquery.multiselect can only work with select+options in DOM ? We'll give jquery.multiselect what it wants...
var $groupsSelect;
if (isSubadminSelect) {
$groupsSelect = $('<select multiple="multiple" class="groupsselect multiselect button" title="' + placeholder + '"></select>');
} else {
$groupsSelect = $('<select multiple="multiple" class="subadminsselect multiselect button" title="' + placeholder + '"></select>')
}

function createItem(group) {
if (isSubadminSelect && group === 'admin') {
// can't become subadmin of "admin" group
return;
}
$groupsSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
}

$.each(this.availableGroups, function (i, group) {
// some new groups might be selected but not in the available groups list yet
var extraIndex = extraGroups.indexOf(group);
if (extraIndex >= 0) {
// remove extra group as it was found
extraGroups.splice(extraIndex, 1);
}
createItem(group);
});
$.each(extraGroups, function (i, group) {
createItem(group);
});

$td.append($groupsSelect);

if (isSubadminSelect) {
UserList.applySubadminSelect($groupsSelect, user, checked);
} else {
UserList.applyGroupSelect($groupsSelect, user, checked);
}

$groupsListContainer.addClass('hidden');
$td.find('.multiselect:not(.groupsListContainer):first').click();
$groupsSelect.on('dropdownclosed', function(e) {
$groupsSelect.remove();
$td.find('.multiselect:not(.groupsListContainer)').parent().remove();
$td.find('.multiselectoptions').remove();
$groupsListContainer.removeClass('hidden');
UserList._updateGroupListLabel($td, e.checked);
});
},

/**
* Updates the groups list td with the given groups selection
*/
_updateGroupListLabel: function($td, groups) {
var placeholder = $td.find('.groupsListContainer').attr('data-placeholder');
var $groupsEl = $td.find('.groupsList');
$groupsEl.text(groups.join(', ') || placeholder || t('settings', 'no group'));
$td.data('groups', groups);
}
};

Expand All @@ -635,13 +647,6 @@ $(document).ready(function () {
// TODO: move other init calls inside of initialize
UserList.initialize($('#userlist'));

$('.groupsselect').each(function (index, element) {
UserList.applyGroupSelect(element);
});
$('.subadminsselect').each(function (index, element) {
UserList.applySubadminSelect(element);
});

$userListBody.on('click', '.password', function (event) {
event.stopPropagation();

Expand Down Expand Up @@ -785,11 +790,24 @@ $(document).ready(function () {
});
});

$('#newuser .groupsListContainer').on('click', function (event) {
event.stopPropagation();
var $div = $(this).closest('.groups');
UserList._triggerGroupEdit($div);
});
$userListBody.on('click', '.groups .groupsListContainer, .subadmins .groupsListContainer', function (event) {
event.stopPropagation();
var $td = $(this).closest('td');
var isSubadminSelect = $td.hasClass('subadmins');
UserList._triggerGroupEdit($td, isSubadminSelect);
});

// 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);
});

UserList._updateGroupListLabel($('#newuser .groups'), []);
$('#newuser').submit(function (event) {
event.preventDefault();
var username = $('#newusername').val();
Expand Down Expand Up @@ -825,7 +843,7 @@ $(document).ready(function () {
}

promise.then(function() {
var groups = $('#newusergroups').val() || [];
var groups = $('#newuser .groups').data('groups') || [];
$.post(
OC.generateUrl('/settings/users/users'),
{
Expand Down

0 comments on commit 3a0a84e

Please sign in to comment.