Commit 79c63d76 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '34625-Remove-IIFEs-from-users_select.js' into 'master'

Resolve "Remove IIFEs from users_select.js"

Closes #34625

See merge request gitlab-org/gitlab!19290
parents 58b63a7c 9950dfb0
...@@ -27,633 +27,620 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -27,633 +27,620 @@ function UsersSelect(currentUser, els, options = {}) {
} }
const { handleClick } = options; const { handleClick } = options;
const userSelect = this;
$els.each((i, dropdown) => {
const userSelect = this;
const options = {};
const $dropdown = $(dropdown);
options.projectId = $dropdown.data('projectId');
options.groupId = $dropdown.data('groupId');
options.showCurrentUser = $dropdown.data('currentUser');
options.todoFilter = $dropdown.data('todoFilter');
options.todoStateFilter = $dropdown.data('todoStateFilter');
options.iid = $dropdown.data('iid');
options.issuableType = $dropdown.data('issuableType');
const showNullUser = $dropdown.data('nullUser');
const defaultNullUser = $dropdown.data('nullUserDefault');
const showMenuAbove = $dropdown.data('showMenuAbove');
const showAnyUser = $dropdown.data('anyUser');
const firstUser = $dropdown.data('firstUser');
options.authorId = $dropdown.data('authorId');
const defaultLabel = $dropdown.data('defaultLabel');
const issueURL = $dropdown.data('issueUpdate');
const $selectbox = $dropdown.closest('.selectbox');
let $block = $selectbox.closest('.block');
const abilityName = $dropdown.data('abilityName');
let $value = $block.find('.value');
const $collapsedSidebar = $block.find('.sidebar-collapsed-user');
const $loading = $block.find('.block-loading').fadeOut();
const selectedIdDefault = defaultNullUser && showNullUser ? 0 : null;
let selectedId = $dropdown.data('selected');
let assignTo;
let assigneeTemplate;
let collapsedAssigneeTemplate;
if (selectedId === undefined) {
selectedId = selectedIdDefault;
}
$els.each( const assignYourself = function() {
(function(_this) { const unassignedSelected = $dropdown
return function(i, dropdown) { .closest('.selectbox')
const options = {}; .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
const $dropdown = $(dropdown);
options.projectId = $dropdown.data('projectId'); if (unassignedSelected) {
options.groupId = $dropdown.data('groupId'); unassignedSelected.remove();
options.showCurrentUser = $dropdown.data('currentUser'); }
options.todoFilter = $dropdown.data('todoFilter');
options.todoStateFilter = $dropdown.data('todoStateFilter'); // Save current selected user to the DOM
options.iid = $dropdown.data('iid'); const currentUserInfo = $dropdown.data('currentUserInfo') || {};
options.issuableType = $dropdown.data('issuableType'); const currentUser = userSelect.currentUser || {};
const showNullUser = $dropdown.data('nullUser'); const fieldName = $dropdown.data('fieldName');
const defaultNullUser = $dropdown.data('nullUserDefault'); const userName = currentUserInfo.name;
const showMenuAbove = $dropdown.data('showMenuAbove'); const userId = currentUserInfo.id || currentUser.id;
const showAnyUser = $dropdown.data('anyUser');
const firstUser = $dropdown.data('firstUser'); const inputHtmlString = _.template(`
options.authorId = $dropdown.data('authorId'); <input type="hidden" name="<%- fieldName %>"
const defaultLabel = $dropdown.data('defaultLabel'); data-meta="<%- userName %>"
const issueURL = $dropdown.data('issueUpdate'); value="<%- userId %>" />
const $selectbox = $dropdown.closest('.selectbox'); `)({ fieldName, userName, userId });
let $block = $selectbox.closest('.block');
const abilityName = $dropdown.data('abilityName'); if ($selectbox) {
let $value = $block.find('.value'); $dropdown.parent().before(inputHtmlString);
const $collapsedSidebar = $block.find('.sidebar-collapsed-user'); } else {
const $loading = $block.find('.block-loading').fadeOut(); $dropdown.after(inputHtmlString);
const selectedIdDefault = defaultNullUser && showNullUser ? 0 : null; }
let selectedId = $dropdown.data('selected'); };
let assignTo;
let assigneeTemplate;
let collapsedAssigneeTemplate;
if (selectedId === undefined) {
selectedId = selectedIdDefault;
}
const assignYourself = function() {
const unassignedSelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
if (unassignedSelected) { if ($block[0]) {
unassignedSelected.remove(); $block[0].addEventListener('assignYourself', assignYourself);
} }
// Save current selected user to the DOM const getSelectedUserInputs = function() {
const currentUserInfo = $dropdown.data('currentUserInfo') || {}; return $selectbox.find(`input[name="${$dropdown.data('fieldName')}"]`);
const currentUser = _this.currentUser || {}; };
const fieldName = $dropdown.data('fieldName');
const userName = currentUserInfo.name;
const userId = currentUserInfo.id || currentUser.id;
const inputHtmlString = _.template(`
<input type="hidden" name="<%- fieldName %>"
data-meta="<%- userName %>"
value="<%- userId %>" />
`)({ fieldName, userName, userId });
if ($selectbox) {
$dropdown.parent().before(inputHtmlString);
} else {
$dropdown.after(inputHtmlString);
}
};
if ($block[0]) { const getSelected = function() {
$block[0].addEventListener('assignYourself', assignYourself); return getSelectedUserInputs()
} .map((index, input) => parseInt(input.value, 10))
.get();
};
const getSelectedUserInputs = function() { const checkMaxSelect = function() {
return $selectbox.find(`input[name="${$dropdown.data('fieldName')}"]`); const maxSelect = $dropdown.data('maxSelect');
}; if (maxSelect) {
const selected = getSelected();
const getSelected = function() {
return getSelectedUserInputs()
.map((index, input) => parseInt(input.value, 10))
.get();
};
const checkMaxSelect = function() {
const maxSelect = $dropdown.data('maxSelect');
if (maxSelect) {
const selected = getSelected();
if (selected.length > maxSelect) {
const firstSelectedId = selected[0];
const firstSelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
firstSelected.remove();
emitSidebarEvent('sidebar.removeAssignee', {
id: firstSelectedId,
});
}
}
};
const getMultiSelectDropdownTitle = function(selectedUser, isSelected) {
const selectedUsers = getSelected().filter(u => u !== 0);
const firstUser = getSelectedUserInputs()
.map((index, input) => ({
name: input.dataset.meta,
value: parseInt(input.value, 10),
}))
.filter(u => u.id !== 0)
.get(0);
if (selectedUsers.length === 0) {
return s__('UsersSelect|Unassigned');
} else if (selectedUsers.length === 1) {
return firstUser.name;
} else if (isSelected) {
const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
name: selectedUser.name,
length: otherSelected.length,
});
} else {
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
name: firstUser.name,
length: selectedUsers.length - 1,
});
}
};
$('.assign-to-me-link').on('click', e => { if (selected.length > maxSelect) {
e.preventDefault(); const firstSelectedId = selected[0];
$(e.currentTarget).hide(); const firstSelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
if ($dropdown.data('multiSelect')) { firstSelected.remove();
assignYourself(); emitSidebarEvent('sidebar.removeAssignee', {
checkMaxSelect(); id: firstSelectedId,
});
}
}
};
const currentUserInfo = $dropdown.data('currentUserInfo'); const getMultiSelectDropdownTitle = function(selectedUser, isSelected) {
$dropdown const selectedUsers = getSelected().filter(u => u !== 0);
.find('.dropdown-toggle-text')
.text(getMultiSelectDropdownTitle(currentUserInfo)) const firstUser = getSelectedUserInputs()
.removeClass('is-default'); .map((index, input) => ({
} else { name: input.dataset.meta,
const $input = $(`input[name="${$dropdown.data('fieldName')}"]`); value: parseInt(input.value, 10),
$input.val(gon.current_user_id); }))
selectedId = $input.val(); .filter(u => u.id !== 0)
$dropdown .get(0);
.find('.dropdown-toggle-text')
.text(gon.current_user_fullname) if (selectedUsers.length === 0) {
.removeClass('is-default'); return s__('UsersSelect|Unassigned');
} } else if (selectedUsers.length === 1) {
return firstUser.name;
} else if (isSelected) {
const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
name: selectedUser.name,
length: otherSelected.length,
}); });
} else {
$block.on('click', '.js-assign-yourself', e => { return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
e.preventDefault(); name: firstUser.name,
return assignTo(_this.currentUser.id); length: selectedUsers.length - 1,
}); });
}
};
assignTo = function(selected) { $('.assign-to-me-link').on('click', e => {
const data = {}; e.preventDefault();
data[abilityName] = {}; $(e.currentTarget).hide();
data[abilityName].assignee_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn(); if ($dropdown.data('multiSelect')) {
$dropdown.trigger('loading.gl.dropdown'); assignYourself();
checkMaxSelect();
return axios.put(issueURL, data).then(({ data }) => {
let user = {}; const currentUserInfo = $dropdown.data('currentUserInfo');
let tooltipTitle = user.name; $dropdown
$dropdown.trigger('loaded.gl.dropdown'); .find('.dropdown-toggle-text')
$loading.fadeOut(); .text(getMultiSelectDropdownTitle(currentUserInfo))
if (data.assignee) { .removeClass('is-default');
user = { } else {
name: data.assignee.name, const $input = $(`input[name="${$dropdown.data('fieldName')}"]`);
username: data.assignee.username, $input.val(gon.current_user_id);
avatar: data.assignee.avatar_url, selectedId = $input.val();
}; $dropdown
tooltipTitle = _.escape(user.name); .find('.dropdown-toggle-text')
} else { .text(gon.current_user_fullname)
user = { .removeClass('is-default');
name: s__('UsersSelect|Unassigned'), }
username: '', });
avatar: '',
$block.on('click', '.js-assign-yourself', e => {
e.preventDefault();
return assignTo(userSelect.currentUser.id);
});
assignTo = function(selected) {
const data = {};
data[abilityName] = {};
data[abilityName].assignee_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return axios.put(issueURL, data).then(({ data }) => {
let user = {};
let tooltipTitle = user.name;
$dropdown.trigger('loaded.gl.dropdown');
$loading.fadeOut();
if (data.assignee) {
user = {
name: data.assignee.name,
username: data.assignee.username,
avatar: data.assignee.avatar_url,
};
tooltipTitle = _.escape(user.name);
} else {
user = {
name: s__('UsersSelect|Unassigned'),
username: '',
avatar: '',
};
tooltipTitle = s__('UsersSelect|Assignee');
}
$value.html(assigneeTemplate(user));
$collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle');
return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
});
};
collapsedAssigneeTemplate = _.template(
'<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>',
);
assigneeTemplate = _.template(
`<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
${sprintf(s__('UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}'), {
openingTag: '<a href="#" class="js-assign-yourself">',
closingTag: '</a>',
})}</span> <% } %>`,
);
return $dropdown.glDropdown({
showMenuAbove,
data(term, callback) {
return userSelect.users(term, options, users => {
// GitLabDropdownFilter returns this.instance
// GitLabDropdownRemote returns this.options.instance
const glDropdown = this.instance || this.options.instance;
glDropdown.options.processData(term, users, callback);
});
},
processData(term, data, callback) {
let users = data;
// Only show assigned user list when there is no search term
if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
const selectedInputs = getSelectedUserInputs();
// Potential duplicate entries when dealing with issue board
// because issue board is also managed by vue
const selectedUsers = _.uniq(selectedInputs, false, a => a.value)
.filter(input => {
const userId = parseInt(input.value, 10);
const inUsersArray = users.find(u => u.id === userId);
return !inUsersArray && userId !== 0;
})
.map(input => {
const userId = parseInt(input.value, 10);
const { avatarUrl, avatar_url, name, username, canMerge } = input.dataset;
return {
avatar_url: avatarUrl || avatar_url,
id: userId,
name,
username,
can_merge: parseBoolean(canMerge),
}; };
tooltipTitle = s__('UsersSelect|Assignee');
}
$value.html(assigneeTemplate(user));
$collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle');
return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
});
};
collapsedAssigneeTemplate = _.template(
'<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>',
);
assigneeTemplate = _.template(
`<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
${sprintf(s__('UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}'), {
openingTag: '<a href="#" class="js-assign-yourself">',
closingTag: '</a>',
})}</span> <% } %>`,
);
return $dropdown.glDropdown({
showMenuAbove,
data(term, callback) {
return _this.users(term, options, users => {
// GitLabDropdownFilter returns this.instance
// GitLabDropdownRemote returns this.options.instance
const glDropdown = this.instance || this.options.instance;
glDropdown.options.processData(term, users, callback);
}); });
},
processData(term, data, callback) {
let users = data;
// Only show assigned user list when there is no search term
if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
const selectedInputs = getSelectedUserInputs();
// Potential duplicate entries when dealing with issue board
// because issue board is also managed by vue
const selectedUsers = _.uniq(selectedInputs, false, a => a.value)
.filter(input => {
const userId = parseInt(input.value, 10);
const inUsersArray = users.find(u => u.id === userId);
return !inUsersArray && userId !== 0;
})
.map(input => {
const userId = parseInt(input.value, 10);
const { avatarUrl, avatar_url, name, username, canMerge } = input.dataset;
return {
avatar_url: avatarUrl || avatar_url,
id: userId,
name,
username,
can_merge: parseBoolean(canMerge),
};
});
users = data.concat(selectedUsers); users = data.concat(selectedUsers);
} }
let anyUser; let anyUser;
let index; let index;
let len; let len;
let name; let name;
let obj; let obj;
let showDivider; let showDivider;
if (term.length === 0) { if (term.length === 0) {
showDivider = 0; showDivider = 0;
if (firstUser) { if (firstUser) {
// Move current user to the front of the list // Move current user to the front of the list
for (index = 0, len = users.length; index < len; index += 1) { for (index = 0, len = users.length; index < len; index += 1) {
obj = users[index]; obj = users[index];
if (obj.username === firstUser) { if (obj.username === firstUser) {
users.splice(index, 1); users.splice(index, 1);
users.unshift(obj); users.unshift(obj);
break; break;
}
}
} }
if (showNullUser) { }
}
if (showNullUser) {
showDivider += 1;
users.unshift({
beforeDivider: true,
name: s__('UsersSelect|Unassigned'),
id: 0,
});
}
if (showAnyUser) {
showDivider += 1;
name = showAnyUser;
if (name === true) {
name = s__('UsersSelect|Any User');
}
anyUser = {
beforeDivider: true,
name,
id: null,
};
users.unshift(anyUser);
}
if (showDivider) {
users.splice(showDivider, 0, { type: 'divider' });
}
if ($dropdown.hasClass('js-multiselect')) {
const selected = getSelected().filter(i => i !== 0);
if (selected.length > 0) {
if ($dropdown.data('dropdownHeader')) {
showDivider += 1; showDivider += 1;
users.unshift({ users.splice(showDivider, 0, {
beforeDivider: true, type: 'header',
name: s__('UsersSelect|Unassigned'), content: $dropdown.data('dropdownHeader'),
id: 0,
}); });
} }
if (showAnyUser) {
showDivider += 1;
name = showAnyUser;
if (name === true) {
name = s__('UsersSelect|Any User');
}
anyUser = {
beforeDivider: true,
name,
id: null,
};
users.unshift(anyUser);
}
if (showDivider) { const selectedUsers = users
users.splice(showDivider, 0, { type: 'divider' }); .filter(u => selected.indexOf(u.id) !== -1)
} .sort((a, b) => a.name > b.name);
if ($dropdown.hasClass('js-multiselect')) { users = users.filter(u => selected.indexOf(u.id) === -1);
const selected = getSelected().filter(i => i !== 0);
if (selected.length > 0) { selectedUsers.forEach(selectedUser => {
if ($dropdown.data('dropdownHeader')) { showDivider += 1;
showDivider += 1; users.splice(showDivider, 0, selectedUser);
users.splice(showDivider, 0, { });
type: 'header',
content: $dropdown.data('dropdownHeader'),
});
}
const selectedUsers = users users.splice(showDivider + 1, 0, { type: 'divider' });
.filter(u => selected.indexOf(u.id) !== -1) }
.sort((a, b) => a.name > b.name); }
}
users = users.filter(u => selected.indexOf(u.id) === -1); callback(users);
if (showMenuAbove) {
$dropdown.data('glDropdown').positionMenuAbove();
}
},
filterable: true,
filterRemote: true,
search: {
fields: ['name', 'username'],
},
selectable: true,
fieldName: $dropdown.data('fieldName'),
toggleLabel(selected, el, glDropdown) {
const inputValue = glDropdown.filterInput.val();
if (this.multiSelect && inputValue === '') {
// Remove non-users from the fullData array
const users = glDropdown.filteredFullData();
const callback = glDropdown.parseData.bind(glDropdown);
// Update the data model
this.processData(inputValue, users, callback);
}
selectedUsers.forEach(selectedUser => { if (this.multiSelect) {
showDivider += 1; return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active'));
users.splice(showDivider, 0, selectedUser); }
});
users.splice(showDivider + 1, 0, { type: 'divider' }); if (selected && 'id' in selected && $(el).hasClass('is-active')) {
} $dropdown.find('.dropdown-toggle-text').removeClass('is-default');
} if (selected.text) {
} return selected.text;
} else {
return selected.name;
}
} else {
$dropdown.find('.dropdown-toggle-text').addClass('is-default');
return defaultLabel;
}
},
defaultLabel,
hidden() {
if ($dropdown.hasClass('js-multiselect')) {
emitSidebarEvent('sidebar.saveAssignees');
}
callback(users); if (!$dropdown.data('alwaysShowSelectbox')) {
if (showMenuAbove) { $selectbox.hide();
$dropdown.data('glDropdown').positionMenuAbove();
}
},
filterable: true,
filterRemote: true,
search: {
fields: ['name', 'username'],
},
selectable: true,
fieldName: $dropdown.data('fieldName'),
toggleLabel(selected, el, glDropdown) {
const inputValue = glDropdown.filterInput.val();
if (this.multiSelect && inputValue === '') {
// Remove non-users from the fullData array
const users = glDropdown.filteredFullData();
const callback = glDropdown.parseData.bind(glDropdown);
// Update the data model
this.processData(inputValue, users, callback);
}
if (this.multiSelect) { // Recalculate where .value is because vue might have changed it
return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active')); $block = $selectbox.closest('.block');
} $value = $block.find('.value');
// display:block overrides the hide-collapse rule
$value.css('display', '');
}
},
multiSelect: $dropdown.hasClass('js-multiselect'),
inputMeta: $dropdown.data('inputMeta'),
clicked(options) {
const { $el, e, isMarking } = options;
const user = options.selectedObj;
$el.tooltip('dispose');
if ($dropdown.hasClass('js-multiselect')) {
const isActive = $el.hasClass('is-active');
const previouslySelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value!=0]`);
if (selected && 'id' in selected && $(el).hasClass('is-active')) { // Enables support for limiting the number of users selected
$dropdown.find('.dropdown-toggle-text').removeClass('is-default'); // Automatically removes the first on the list if more users are selected
if (selected.text) { checkMaxSelect();
return selected.text;
} else { if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
return selected.name; // Unassigned selected
} previouslySelected.each((index, element) => {
} else { element.remove();
$dropdown.find('.dropdown-toggle-text').addClass('is-default'); });
return defaultLabel; emitSidebarEvent('sidebar.removeAllAssignees');
} else if (isActive) {
// user selected
emitSidebarEvent('sidebar.addAssignee', user);
// Remove unassigned selection (if it was previously selected)
const unassignedSelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
if (unassignedSelected) {
unassignedSelected.remove();
} }
}, } else {
defaultLabel, if (previouslySelected.length === 0) {
hidden() { // Select unassigned because there is no more selected users
if ($dropdown.hasClass('js-multiselect')) { this.addInput($dropdown.data('fieldName'), 0, {});
emitSidebarEvent('sidebar.saveAssignees');
} }
if (!$dropdown.data('alwaysShowSelectbox')) { // User unselected
$selectbox.hide(); emitSidebarEvent('sidebar.removeAssignee', user);
}
// Recalculate where .value is because vue might have changed it if (getSelected().find(u => u === gon.current_user_id)) {
$block = $selectbox.closest('.block'); $('.assign-to-me-link').hide();
$value = $block.find('.value'); } else {
// display:block overrides the hide-collapse rule $('.assign-to-me-link').show();
$value.css('display', ''); }
} }
},
multiSelect: $dropdown.hasClass('js-multiselect'),
inputMeta: $dropdown.data('inputMeta'),
clicked(options) {
const { $el, e, isMarking } = options;
const user = options.selectedObj;
$el.tooltip('dispose');
if ($dropdown.hasClass('js-multiselect')) {
const isActive = $el.hasClass('is-active');
const previouslySelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value!=0]`);
// Enables support for limiting the number of users selected
// Automatically removes the first on the list if more users are selected
checkMaxSelect();
if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
// Unassigned selected
previouslySelected.each((index, element) => {
element.remove();
});
emitSidebarEvent('sidebar.removeAllAssignees');
} else if (isActive) {
// user selected
emitSidebarEvent('sidebar.addAssignee', user);
// Remove unassigned selection (if it was previously selected)
const unassignedSelected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
if (unassignedSelected) {
unassignedSelected.remove();
}
} else {
if (previouslySelected.length === 0) {
// Select unassigned because there is no more selected users
this.addInput($dropdown.data('fieldName'), 0, {});
}
// User unselected const page = $('body').attr('data-page');
emitSidebarEvent('sidebar.removeAssignee', user); const isIssueIndex = page === 'projects:issues:index';
} const isMRIndex = page === page && page === 'projects:merge_requests:index';
if (
$dropdown.hasClass('js-filter-bulk-update') ||
$dropdown.hasClass('js-issuable-form-dropdown')
) {
e.preventDefault();
if (getSelected().find(u => u === gon.current_user_id)) { const isSelecting = user.id !== selectedId;
$('.assign-to-me-link').hide(); selectedId = isSelecting ? user.id : selectedIdDefault;
} else {
$('.assign-to-me-link').show();
}
}
const page = $('body').attr('data-page'); if (selectedId === gon.current_user_id) {
const isIssueIndex = page === 'projects:issues:index'; $('.assign-to-me-link').hide();
const isMRIndex = page === page && page === 'projects:merge_requests:index'; } else {
if ( $('.assign-to-me-link').show();
$dropdown.hasClass('js-filter-bulk-update') || }
$dropdown.hasClass('js-issuable-form-dropdown') return;
) { }
e.preventDefault(); if ($el.closest('.add-issues-modal').length) {
ModalStore.store.filter[$dropdown.data('fieldName')] = user.id;
const isSelecting = user.id !== selectedId; } else if (handleClick) {
selectedId = isSelecting ? user.id : selectedIdDefault; e.preventDefault();
handleClick(user, isMarking);
if (selectedId === gon.current_user_id) { } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
$('.assign-to-me-link').hide(); return Issuable.filterResults($dropdown.closest('form'));
} else { } else if ($dropdown.hasClass('js-filter-submit')) {
$('.assign-to-me-link').show(); return $dropdown.closest('form').submit();
} } else if (!$dropdown.hasClass('js-multiselect')) {
return; const selected = $dropdown
} .closest('.selectbox')
if ($el.closest('.add-issues-modal').length) { .find(`input[name='${$dropdown.data('fieldName')}']`)
ModalStore.store.filter[$dropdown.data('fieldName')] = user.id; .val();
} else if (handleClick) { return assignTo(selected);
e.preventDefault(); }
handleClick(user, isMarking);
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
return Issuable.filterResults($dropdown.closest('form'));
} else if ($dropdown.hasClass('js-filter-submit')) {
return $dropdown.closest('form').submit();
} else if (!$dropdown.hasClass('js-multiselect')) {
const selected = $dropdown
.closest('.selectbox')
.find(`input[name='${$dropdown.data('fieldName')}']`)
.val();
return assignTo(selected);
}
// Automatically close dropdown after assignee is selected // Automatically close dropdown after assignee is selected
// since CE has no multiple assignees // since CE has no multiple assignees
// EE does not have a max-select // EE does not have a max-select
if ( if ($dropdown.data('maxSelect') && getSelected().length === $dropdown.data('maxSelect')) {
$dropdown.data('maxSelect') && // Close the dropdown
getSelected().length === $dropdown.data('maxSelect') $dropdown.dropdown('toggle');
) { }
// Close the dropdown },
$dropdown.dropdown('toggle'); id(user) {
} return user.id;
}, },
id(user) { opened(e) {
return user.id; const $el = $(e.currentTarget);
}, const selected = getSelected();
opened(e) { if ($dropdown.hasClass('js-issue-board-sidebar') && selected.length === 0) {
const $el = $(e.currentTarget); this.addInput($dropdown.data('fieldName'), 0, {});
const selected = getSelected(); }
if ($dropdown.hasClass('js-issue-board-sidebar') && selected.length === 0) { $el.find('.is-active').removeClass('is-active');
this.addInput($dropdown.data('fieldName'), 0, {});
}
$el.find('.is-active').removeClass('is-active');
function highlightSelected(id) { function highlightSelected(id) {
$el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active'); $el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
} }
if (selected.length > 0) { if (selected.length > 0) {
getSelected().forEach(selectedId => highlightSelected(selectedId)); getSelected().forEach(selectedId => highlightSelected(selectedId));
} else if ($dropdown.hasClass('js-issue-board-sidebar')) { } else if ($dropdown.hasClass('js-issue-board-sidebar')) {
highlightSelected(0); highlightSelected(0);
} else { } else {
highlightSelected(selectedId); highlightSelected(selectedId);
} }
}, },
updateLabel: $dropdown.data('dropdownTitle'), updateLabel: $dropdown.data('dropdownTitle'),
renderRow(user) { renderRow(user) {
const username = user.username ? `@${user.username}` : ''; const username = user.username ? `@${user.username}` : '';
const avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url; const avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
let selected = false; let selected = false;
if (this.multiSelect) { if (this.multiSelect) {
selected = getSelected().find(u => user.id === u); selected = getSelected().find(u => user.id === u);
const { fieldName } = this; const { fieldName } = this;
const field = $dropdown const field = $dropdown
.closest('.selectbox') .closest('.selectbox')
.find(`input[name='${fieldName}'][value='${user.id}']`); .find(`input[name='${fieldName}'][value='${user.id}']`);
if (field.length) { if (field.length) {
selected = true; selected = true;
} }
} else { } else {
selected = user.id === selectedId; selected = user.id === selectedId;
} }
let img = ''; let img = '';
if (user.beforeDivider != null) { if (user.beforeDivider != null) {
`<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape( `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape(
user.name, user.name,
)}</a></li>`; )}</a></li>`;
} else { } else {
// 0 margin, because it's now handled by a wrapper // 0 margin, because it's now handled by a wrapper
img = `<img src='${avatar}' class='avatar avatar-inline m-0' width='32' />`; img = `<img src='${avatar}' class='avatar avatar-inline m-0' width='32' />`;
} }
return _this.renderRow(options.issuableType, user, selected, username, img); return userSelect.renderRow(options.issuableType, user, selected, username, img);
}, },
}); });
}; });
})(this),
);
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => { .then(() => {
$('.ajax-users-select').each( $('.ajax-users-select').each((i, select) => {
(function(_this) { const options = {};
return function(i, select) { options.skipLdap = $(select).hasClass('skip_ldap');
const options = {}; options.projectId = $(select).data('projectId');
options.skipLdap = $(select).hasClass('skip_ldap'); options.groupId = $(select).data('groupId');
options.projectId = $(select).data('projectId'); options.showCurrentUser = $(select).data('currentUser');
options.groupId = $(select).data('groupId'); options.authorId = $(select).data('authorId');
options.showCurrentUser = $(select).data('currentUser'); options.skipUsers = $(select).data('skipUsers');
options.authorId = $(select).data('authorId'); const showNullUser = $(select).data('nullUser');
options.skipUsers = $(select).data('skipUsers'); const showAnyUser = $(select).data('anyUser');
const showNullUser = $(select).data('nullUser'); const showEmailUser = $(select).data('emailUser');
const showAnyUser = $(select).data('anyUser'); const firstUser = $(select).data('firstUser');
const showEmailUser = $(select).data('emailUser'); return $(select).select2({
const firstUser = $(select).data('firstUser'); placeholder: __('Search for a user'),
return $(select).select2({ multiple: $(select).hasClass('multiselect'),
placeholder: __('Search for a user'), minimumInputLength: 0,
multiple: $(select).hasClass('multiselect'), query(query) {
minimumInputLength: 0, return userSelect.users(query.term, options, users => {
query(query) { let name;
return _this.users(query.term, options, users => { const data = {
let name; results: users,
const data = { };
results: users, if (query.term.length === 0) {
}; if (firstUser) {
if (query.term.length === 0) { // Move current user to the front of the list
if (firstUser) { const ref = data.results;
// Move current user to the front of the list
const ref = data.results; for (let index = 0, len = ref.length; index < len; index += 1) {
const obj = ref[index];
for (let index = 0, len = ref.length; index < len; index += 1) { if (obj.username === firstUser) {
const obj = ref[index]; data.results.splice(index, 1);
if (obj.username === firstUser) { data.results.unshift(obj);
data.results.splice(index, 1); break;
data.results.unshift(obj);
break;
}
}
}
if (showNullUser) {
const nullUser = {
name: s__('UsersSelect|Unassigned'),
id: 0,
};
data.results.unshift(nullUser);
}
if (showAnyUser) {
name = showAnyUser;
if (name === true) {
name = s__('UsersSelect|Any User');
}
const anyUser = {
name,
id: null,
};
data.results.unshift(anyUser);
} }
} }
if ( }
showEmailUser && if (showNullUser) {
data.results.length === 0 && const nullUser = {
query.term.match(/^[^@]+@[^@]+$/) name: s__('UsersSelect|Unassigned'),
) { id: 0,
const trimmed = query.term.trim(); };
const emailUser = { data.results.unshift(nullUser);
name: sprintf(__('Invite "%{trimmed}" by email'), { trimmed }), }
username: trimmed, if (showAnyUser) {
id: trimmed, name = showAnyUser;
invite: true, if (name === true) {
}; name = s__('UsersSelect|Any User');
data.results.unshift(emailUser);
} }
return query.callback(data); const anyUser = {
}); name,
}, id: null,
initSelection() { };
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; data.results.unshift(anyUser);
return _this.initSelection.apply(_this, args); }
}, }
formatResult() { if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) {
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; const trimmed = query.term.trim();
return _this.formatResult.apply(_this, args); const emailUser = {
}, name: sprintf(__('Invite "%{trimmed}" by email'), { trimmed }),
formatSelection() { username: trimmed,
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; id: trimmed,
return _this.formatSelection.apply(_this, args); invite: true,
}, };
dropdownCssClass: 'ajax-users-dropdown', data.results.unshift(emailUser);
// we do not want to escape markup since we are displaying html in results }
escapeMarkup(m) { return query.callback(data);
return m;
},
}); });
}; },
})(this), initSelection() {
); const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
return userSelect.initSelection.apply(userSelect, args);
},
formatResult() {
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
return userSelect.formatResult.apply(userSelect, args);
},
formatSelection() {
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
return userSelect.formatSelection.apply(userSelect, args);
},
dropdownCssClass: 'ajax-users-dropdown',
// we do not want to escape markup since we are displaying html in results
escapeMarkup(m) {
return m;
},
});
});
}) })
.catch(() => {}); .catch(() => {});
} }
......
---
title: Remove IIFEs from users_select.js
merge_request: 19290
author: minghuan lei
type: other
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment