Feature #43825 ยป preserve_checkbox_state.patch
| app/assets/javascripts/application-legacy.js | ||
|---|---|---|
| 796 | 796 |
}); |
| 797 | 797 |
} |
| 798 | 798 | |
| 799 |
function observeSearchfield(fieldId, targetId, url) {
|
|
| 799 |
function observeSearchfield(fieldId, targetId, url, options) {
|
|
| 800 | 800 |
$('#'+fieldId).each(function() {
|
| 801 | 801 |
var $this = $(this); |
| 802 | 802 |
$this.addClass('autocomplete');
|
| 803 | 803 |
$this.attr('data-value-was', $this.val());
|
| 804 |
var checkedValues = {};
|
|
| 804 | 805 |
var check = function() {
|
| 805 | 806 |
var val = $this.val(); |
| 806 | 807 |
if ($this.attr('data-value-was') != val){
|
| 807 | 808 |
$this.attr('data-value-was', val);
|
| 809 |
if (options && options.checkboxSelector) {
|
|
| 810 |
$(options.checkboxSelector).each(function() {
|
|
| 811 |
if ($(this).prop('checked')) {
|
|
| 812 |
checkedValues[$(this).val()] = true; |
|
| 813 |
} |
|
| 814 |
}); |
|
| 815 |
} |
|
| 808 | 816 |
$.ajax({
|
| 809 | 817 |
url: url, |
| 810 | 818 |
type: 'get', |
| 811 | 819 |
data: {q: $this.val()},
|
| 812 |
success: function(data){ if(targetId) $('#'+targetId).html(data); },
|
|
| 813 |
beforeSend: function(){ $this.addClass('ajax-loading'); },
|
|
| 814 |
complete: function(){ $this.removeClass('ajax-loading'); }
|
|
| 820 |
success: function(data){
|
|
| 821 |
if(targetId) $('#'+targetId).html(data);
|
|
| 822 |
}, |
|
| 823 |
complete: function(){
|
|
| 824 |
$this.removeClass('ajax-loading');
|
|
| 825 |
if (options && options.checkboxSelector) {
|
|
| 826 |
$(options.checkboxSelector).each(function() {
|
|
| 827 |
if (checkedValues[$(this).val()]) {
|
|
| 828 |
$(this).prop('checked', true);
|
|
| 829 |
} |
|
| 830 |
}); |
|
| 831 |
} |
|
| 832 |
}, |
|
| 833 |
beforeSend: function(){ $this.addClass('ajax-loading'); }
|
|
| 815 | 834 |
}); |
| 816 | 835 |
} |
| 817 | 836 |
}; |
| app/views/groups/_new_users_form.html.erb | ||
|---|---|---|
| 1 | 1 |
<fieldset class="box"> |
| 2 | 2 |
<legend><%= label_tag "user_search", l(:label_user_search) %></legend> |
| 3 | 3 |
<p><%= text_field_tag 'user_search', nil %></p> |
| 4 |
<%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %>
|
|
| 4 |
<%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }', {checkboxSelector: 'input[name=\"user_ids[]\"]'})" %>
|
|
| 5 | 5 | |
| 6 | 6 |
<div id="users"> |
| 7 | 7 |
<%= render_principals_for_new_group_users(@group) %> |
| app/views/members/_new_form.html.erb | ||
|---|---|---|
| 1 | 1 |
<fieldset class="box"> |
| 2 | 2 |
<legend><%= label_tag("principal_search", l(:label_principal_search)) %></legend>
|
| 3 | 3 |
<p><%= text_field_tag('principal_search', nil) %></p>
|
| 4 |
<%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }')" %>
|
|
| 4 |
<%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }', {checkboxSelector: 'input[name=\"membership[user_ids][]\"]'})" %>
|
|
| 5 | 5 |
<div id="principals_for_new_member"> |
| 6 | 6 |
<%= render_principals_for_new_members(@project) %> |
| 7 | 7 |
</div> |
| app/views/watchers/_new.html.erb | ||
|---|---|---|
| 34 | 34 |
:object_id => (watchables.present? ? watchables.map(&:id) : nil), |
| 35 | 35 |
:project_id => @project |
| 36 | 36 |
) |
| 37 |
)}' |
|
| 37 |
)}', |
|
| 38 |
{checkboxSelector: 'input[name=\"watcher[user_ids][]\"]'}
|
|
| 38 | 39 |
)" |
| 39 | 40 |
) %> |
| 40 | 41 |
<div id="users_for_watcher"> |
| test/system/groups_test.rb | ||
|---|---|---|
| 1 |
# frozen_string_literal: true |
|
| 2 | ||
| 3 |
# Redmine - project management software |
|
| 4 |
# Copyright (C) 2006- Jean-Philippe Lang |
|
| 5 |
# |
|
| 6 |
# This program is free software; you can redistribute it and/or |
|
| 7 |
# modify it under the terms of the GNU General Public License |
|
| 8 |
# as published by the Free Software Foundation; either version 2 |
|
| 9 |
# of the License, or (at your option) any later version. |
|
| 10 |
# |
|
| 11 |
# This program is distributed in the hope that it will be useful, |
|
| 12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 14 |
# GNU General Public License for more details. |
|
| 15 |
# |
|
| 16 |
# You should have received a copy of the GNU General Public License |
|
| 17 |
# along with this program; if not, write to the Free Software |
|
| 18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 19 | ||
| 20 |
require_relative '../application_system_test_case' |
|
| 21 | ||
| 22 |
class GroupsSystemTest < ApplicationSystemTestCase |
|
| 23 |
fixtures :users, :email_addresses, :groups_users |
|
| 24 | ||
| 25 |
def test_add_user_to_group_after_search_preserves_selection |
|
| 26 |
group = Group.find(10) # A Team |
|
| 27 |
rhill = User.find_by_login('rhill')
|
|
| 28 |
someone = User.find_by_login('someone')
|
|
| 29 | ||
| 30 |
assert_not group.users.include?(rhill) |
|
| 31 |
assert_not group.users.include?(someone) |
|
| 32 | ||
| 33 |
log_user('admin', 'admin')
|
|
| 34 |
visit "/groups/#{group.id}/edit?tab=users"
|
|
| 35 | ||
| 36 |
click_on 'New user' |
|
| 37 | ||
| 38 |
within '#ajax-modal' do |
|
| 39 |
# Check Robert Hill |
|
| 40 |
find('label', text: 'Robert Hill').click
|
|
| 41 | ||
| 42 |
# Search for 'some' - Robert Hill disappears |
|
| 43 |
fill_in 'user_search', with: 'some' |
|
| 44 |
assert page.has_no_css?('label', text: 'Robert Hill')
|
|
| 45 | ||
| 46 |
# Check Some One while Robert Hill is hidden |
|
| 47 |
find('label', text: 'Some One').click
|
|
| 48 | ||
| 49 |
# Clear search - both should be visible and checked |
|
| 50 |
fill_in 'user_search', with: '' |
|
| 51 |
assert page.has_css?('label', text: 'Robert Hill')
|
|
| 52 |
assert page.has_css?('label', text: 'Some One')
|
|
| 53 | ||
| 54 |
# Submit |
|
| 55 |
click_on 'Add' |
|
| 56 |
end |
|
| 57 | ||
| 58 |
# Wait for modal to close |
|
| 59 |
assert page.has_no_css?('#ajax-modal')
|
|
| 60 | ||
| 61 |
# Verify both users were added to the group |
|
| 62 |
group.reload |
|
| 63 |
assert group.users.include?(rhill), |
|
| 64 |
"Expected Robert Hill to be added to group" |
|
| 65 |
assert group.users.include?(someone), |
|
| 66 |
"Expected Some One to be added to group" |
|
| 67 |
end |
|
| 68 |
end |
|
| test/system/members_test.rb | ||
|---|---|---|
| 1 |
# frozen_string_literal: true |
|
| 2 | ||
| 3 |
# Redmine - project management software |
|
| 4 |
# Copyright (C) 2006- Jean-Philippe Lang |
|
| 5 |
# |
|
| 6 |
# This program is free software; you can redistribute it and/or |
|
| 7 |
# modify it under the terms of the GNU General Public License |
|
| 8 |
# as published by the Free Software Foundation; either version 2 |
|
| 9 |
# of the License, or (at your option) any later version. |
|
| 10 |
# |
|
| 11 |
# This program is distributed in the hope that it will be useful, |
|
| 12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 14 |
# GNU General Public License for more details. |
|
| 15 |
# |
|
| 16 |
# You should have received a copy of the GNU General Public License |
|
| 17 |
# along with this program; if not, write to the Free Software |
|
| 18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 19 | ||
| 20 |
require_relative '../application_system_test_case' |
|
| 21 | ||
| 22 |
class MembersSystemTest < ApplicationSystemTestCase |
|
| 23 |
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, |
|
| 24 |
:trackers, :projects_trackers, :enabled_modules |
|
| 25 | ||
| 26 |
def test_add_member_after_search_preserves_selection |
|
| 27 |
project = Project.find('ecookbook')
|
|
| 28 |
rhill = User.find_by_login('rhill')
|
|
| 29 |
admin_user = User.find_by_login('admin')
|
|
| 30 | ||
| 31 |
assert_not project.members.map(&:user).include?(rhill) |
|
| 32 |
assert_not project.members.map(&:user).include?(admin_user) |
|
| 33 | ||
| 34 |
log_user('admin', 'admin')
|
|
| 35 |
visit '/projects/ecookbook/settings/members' |
|
| 36 | ||
| 37 |
click_on 'New member' |
|
| 38 | ||
| 39 |
within '#ajax-modal' do |
|
| 40 |
# Check Robert Hill |
|
| 41 |
find('label', text: 'Robert Hill').click
|
|
| 42 | ||
| 43 |
# Search for 'redmine' - Robert Hill disappears |
|
| 44 |
fill_in 'principal_search', with: 'redmine' |
|
| 45 |
assert page.has_no_css?('label', text: 'Robert Hill')
|
|
| 46 | ||
| 47 |
# Check Redmine Admin while Robert Hill is hidden |
|
| 48 |
find('label', text: 'Redmine Admin').click
|
|
| 49 | ||
| 50 |
# Clear search - both should be visible and checked |
|
| 51 |
fill_in 'principal_search', with: '' |
|
| 52 |
assert page.has_css?('label', text: 'Robert Hill')
|
|
| 53 |
assert page.has_css?('label', text: 'Redmine Admin')
|
|
| 54 | ||
| 55 |
# Select a role |
|
| 56 |
check 'Manager' |
|
| 57 | ||
| 58 |
# Submit |
|
| 59 |
click_on 'Add' |
|
| 60 |
end |
|
| 61 | ||
| 62 |
# Wait for modal to close and page to update |
|
| 63 |
assert page.has_no_css?('#ajax-modal')
|
|
| 64 | ||
| 65 |
# Verify both users were added as members |
|
| 66 |
project.reload |
|
| 67 |
assert project.members.map(&:user).include?(rhill), |
|
| 68 |
"Expected Robert Hill to be added as member" |
|
| 69 |
assert project.members.map(&:user).include?(admin_user), |
|
| 70 |
"Expected Redmine Admin to be added as member" |
|
| 71 | ||
| 72 |
# Verify on the page |
|
| 73 |
assert page.has_css?('#tab-content-members', text: 'Robert Hill')
|
|
| 74 |
assert page.has_css?('#tab-content-members', text: 'Redmine Admin')
|
|
| 75 |
end |
|
| 76 |
end |
|
| test/system/watchers_test.rb | ||
|---|---|---|
| 1 |
# frozen_string_literal: true |
|
| 2 | ||
| 3 |
# Redmine - project management software |
|
| 4 |
# Copyright (C) 2006- Jean-Philippe Lang |
|
| 5 |
# |
|
| 6 |
# This program is free software; you can redistribute it and/or |
|
| 7 |
# modify it under the terms of the GNU General Public License |
|
| 8 |
# as published by the Free Software Foundation; either version 2 |
|
| 9 |
# of the License, or (at your option) any later version. |
|
| 10 |
# |
|
| 11 |
# This program is distributed in the hope that it will be useful, |
|
| 12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 14 |
# GNU General Public License for more details. |
|
| 15 |
# |
|
| 16 |
# You should have received a copy of the GNU General Public License |
|
| 17 |
# along with this program; if not, write to the Free Software |
|
| 18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 19 | ||
| 20 |
require_relative '../application_system_test_case' |
|
| 21 | ||
| 22 |
class WatchersSystemTest < ApplicationSystemTestCase |
|
| 23 |
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, |
|
| 24 |
:trackers, :projects_trackers, :enabled_modules, :issues, :issue_statuses, |
|
| 25 |
:watchers |
|
| 26 | ||
| 27 |
def test_add_watcher_after_search_preserves_selection |
|
| 28 |
issue = Issue.find(1) |
|
| 29 |
jsmith = User.find_by_login('jsmith')
|
|
| 30 |
dlopper = User.find_by_login('dlopper')
|
|
| 31 | ||
| 32 |
# Clear existing watchers |
|
| 33 |
issue.watcher_users = [] |
|
| 34 | ||
| 35 |
assert_not issue.watched_by?(jsmith) |
|
| 36 |
assert_not issue.watched_by?(dlopper) |
|
| 37 | ||
| 38 |
log_user('admin', 'admin')
|
|
| 39 |
visit "/issues/#{issue.id}"
|
|
| 40 | ||
| 41 |
# Open watcher modal |
|
| 42 |
within '#sidebar' do |
|
| 43 |
click_on 'Add' |
|
| 44 |
end |
|
| 45 | ||
| 46 |
within '#ajax-modal' do |
|
| 47 |
# Check John Smith |
|
| 48 |
find('label', text: 'John Smith').click
|
|
| 49 | ||
| 50 |
# Search for 'lopper' - John Smith disappears |
|
| 51 |
fill_in 'user_search', with: 'lopper' |
|
| 52 |
assert page.has_no_css?('label', text: 'John Smith')
|
|
| 53 | ||
| 54 |
# Check Dave Lopper while John Smith is hidden |
|
| 55 |
find('label', text: 'Dave Lopper').click
|
|
| 56 | ||
| 57 |
# Clear search - both should be visible and checked |
|
| 58 |
fill_in 'user_search', with: '' |
|
| 59 |
assert page.has_css?('label', text: 'John Smith')
|
|
| 60 |
assert page.has_css?('label', text: 'Dave Lopper')
|
|
| 61 | ||
| 62 |
# Submit |
|
| 63 |
click_on 'Add' |
|
| 64 |
end |
|
| 65 | ||
| 66 |
# Wait for modal to close |
|
| 67 |
assert page.has_no_css?('#ajax-modal')
|
|
| 68 | ||
| 69 |
# Verify both users were added as watchers |
|
| 70 |
issue.reload |
|
| 71 |
assert issue.watched_by?(jsmith), |
|
| 72 |
"Expected John Smith to be added as watcher" |
|
| 73 |
assert issue.watched_by?(dlopper), |
|
| 74 |
"Expected Dave Lopper to be added as watcher" |
|
| 75 |
end |
|
| 76 |
end |
|