summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bennett <lbennett@gitlab.com>2018-11-14 19:51:39 +0000
committerLuke Bennett <lbennett@gitlab.com>2019-01-14 07:12:30 +0000
commitd5bf6deeb265ddaa88809e65f8ffeb45de5af4b2 (patch)
treebf404d304d34fdc155716f8f3a57fb2b5a47f138
parent94d05e3c5ce59448d63ee96e3474b0cd3ef2c995 (diff)
downloadgitlab-ce-53856-changing-group-visibility-does-not-re-enable-save-button.tar.gz
Fix DirtySubmit handling of checkbox and radio inputs53856-changing-group-visibility-does-not-re-enable-save-button
Most browsers do not fire the "input" event for checkboxes or radios. Adds a "change" listener to properly trigger these DirtySubmit updates.
-rw-r--r--app/assets/javascripts/dirty_submit/dirty_submit_form.js7
-rw-r--r--changelogs/unreleased/53856-changing-group-visibility-does-not-re-enable-save-button.yml6
-rw-r--r--spec/features/groups_spec.rb4
-rw-r--r--spec/javascripts/dirty_submit/dirty_submit_collection_spec.js6
-rw-r--r--spec/javascripts/dirty_submit/dirty_submit_form_spec.js28
-rw-r--r--spec/javascripts/dirty_submit/helper.js29
-rw-r--r--spec/support/shared_examples/dirty_submit_form_shared_examples.rb26
7 files changed, 81 insertions, 25 deletions
diff --git a/app/assets/javascripts/dirty_submit/dirty_submit_form.js b/app/assets/javascripts/dirty_submit/dirty_submit_form.js
index d8d0fa1fac4..00e41dd0301 100644
--- a/app/assets/javascripts/dirty_submit/dirty_submit_form.js
+++ b/app/assets/javascripts/dirty_submit/dirty_submit_form.js
@@ -25,15 +25,16 @@ class DirtySubmitForm {
DirtySubmitForm.THROTTLE_DURATION,
);
this.form.addEventListener('input', throttledUpdateDirtyInput);
+ this.form.addEventListener('change', throttledUpdateDirtyInput);
this.form.addEventListener('submit', event => this.formSubmit(event));
}
updateDirtyInput(event) {
- const input = event.target;
+ const { target } = event;
- if (!input.dataset.isDirtySubmitInput) return;
+ if (!target.dataset.isDirtySubmitInput) return;
- this.updateDirtyInputs(input);
+ this.updateDirtyInputs(target);
this.toggleSubmission();
}
diff --git a/changelogs/unreleased/53856-changing-group-visibility-does-not-re-enable-save-button.yml b/changelogs/unreleased/53856-changing-group-visibility-does-not-re-enable-save-button.yml
new file mode 100644
index 00000000000..1daa72fb9c4
--- /dev/null
+++ b/changelogs/unreleased/53856-changing-group-visibility-does-not-re-enable-save-button.yml
@@ -0,0 +1,6 @@
+---
+title: Fix suboptimal handling of checkbox and radio input events causing
+ group general settings submit button to stay disabled after changing its visibility
+merge_request: 23022
+author:
+type: fixed
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index d01fc04311a..00d81b26ce2 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -154,7 +154,7 @@ describe 'Group' do
end
describe 'group edit', :js do
- let(:group) { create(:group) }
+ let(:group) { create(:group, :public) }
let(:path) { edit_group_path(group) }
let(:new_name) { 'new-name' }
@@ -163,6 +163,8 @@ describe 'Group' do
end
it_behaves_like 'dirty submit form', [{ form: '.js-general-settings-form', input: 'input[name="group[name]"]' },
+ { form: '.js-general-settings-form', input: '#group_visibility_level_0' },
+ { form: '.js-general-permissions-form', input: '#group_request_access_enabled' },
{ form: '.js-general-permissions-form', input: 'input[name="group[two_factor_grace_period]"]' }]
it 'saves new settings' do
diff --git a/spec/javascripts/dirty_submit/dirty_submit_collection_spec.js b/spec/javascripts/dirty_submit/dirty_submit_collection_spec.js
index 08ffc44605f..47be0b3ce9d 100644
--- a/spec/javascripts/dirty_submit/dirty_submit_collection_spec.js
+++ b/spec/javascripts/dirty_submit/dirty_submit_collection_spec.js
@@ -1,5 +1,5 @@
import DirtySubmitCollection from '~/dirty_submit/dirty_submit_collection';
-import { setInput, createForm } from './helper';
+import { setInputValue, createForm } from './helper';
describe('DirtySubmitCollection', () => {
it('disables submits until there are changes', done => {
@@ -14,11 +14,11 @@ describe('DirtySubmitCollection', () => {
expect(submit.disabled).toBe(true);
- return setInput(input, `${originalValue} changes`)
+ return setInputValue(input, `${originalValue} changes`)
.then(() => {
expect(submit.disabled).toBe(false);
})
- .then(() => setInput(input, originalValue))
+ .then(() => setInputValue(input, originalValue))
.then(() => {
expect(submit.disabled).toBe(true);
})
diff --git a/spec/javascripts/dirty_submit/dirty_submit_form_spec.js b/spec/javascripts/dirty_submit/dirty_submit_form_spec.js
index 093fec97951..ae2a785de52 100644
--- a/spec/javascripts/dirty_submit/dirty_submit_form_spec.js
+++ b/spec/javascripts/dirty_submit/dirty_submit_form_spec.js
@@ -1,14 +1,14 @@
import DirtySubmitForm from '~/dirty_submit/dirty_submit_form';
-import { setInput, createForm } from './helper';
+import { getInputValue, setInputValue, createForm } from './helper';
function expectToToggleDisableOnDirtyUpdate(submit, input) {
- const originalValue = input.value;
+ const originalValue = getInputValue(input);
expect(submit.disabled).toBe(true);
- return setInput(input, `${originalValue} changes`)
+ return setInputValue(input, `${originalValue} changes`)
.then(() => expect(submit.disabled).toBe(false))
- .then(() => setInput(input, originalValue))
+ .then(() => setInputValue(input, originalValue))
.then(() => expect(submit.disabled).toBe(true));
}
@@ -33,4 +33,24 @@ describe('DirtySubmitForm', () => {
.then(done)
.catch(done.fail);
});
+
+ it('disables submit until there are changes for radio inputs', done => {
+ const { form, input, submit } = createForm('radio');
+
+ new DirtySubmitForm(form); // eslint-disable-line no-new
+
+ return expectToToggleDisableOnDirtyUpdate(submit, input)
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('disables submit until there are changes for checkbox inputs', done => {
+ const { form, input, submit } = createForm('checkbox');
+
+ new DirtySubmitForm(form); // eslint-disable-line no-new
+
+ return expectToToggleDisableOnDirtyUpdate(submit, input)
+ .then(done)
+ .catch(done.fail);
+ });
});
diff --git a/spec/javascripts/dirty_submit/helper.js b/spec/javascripts/dirty_submit/helper.js
index 6d1e643553c..fc5232c58f3 100644
--- a/spec/javascripts/dirty_submit/helper.js
+++ b/spec/javascripts/dirty_submit/helper.js
@@ -1,25 +1,40 @@
import DirtySubmitForm from '~/dirty_submit/dirty_submit_form';
import setTimeoutPromiseHelper from '../helpers/set_timeout_promise_helper';
-export function setInput(element, value) {
- element.value = value;
+export function setInputValue(target, value) {
+ const { type } = target;
+ let eventType;
- element.dispatchEvent(
- new Event('input', {
+ if (/(radio|checkbox)/.test(type)) {
+ target.checked = !target.checked; // eslint-disable-line no-param-reassign
+ eventType = 'change';
+ } else {
+ target.value = value; // eslint-disable-line no-param-reassign
+ eventType = 'input';
+ }
+
+ target.dispatchEvent(
+ new Event(eventType, {
bubbles: true,
- cancelable: true,
}),
);
return setTimeoutPromiseHelper(DirtySubmitForm.THROTTLE_DURATION);
}
-export function createForm() {
+export function getInputValue(input) {
+ const isCheckable = /^(checkbox|radio)$/.test(input.type);
+
+ return isCheckable ? input.checked : input.value;
+}
+
+export function createForm(type = 'text') {
const form = document.createElement('form');
form.innerHTML = `
- <input type="text" value="original" class="js-input" name="input" />
+ <input type="${type}" name="${type}" class="js-input"/>
<button type="submit" class="js-dirty-submit"></button>
`;
+
const input = form.querySelector('.js-input');
const submit = form.querySelector('.js-dirty-submit');
diff --git a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb b/spec/support/shared_examples/dirty_submit_form_shared_examples.rb
index ba363593120..52a2ee49495 100644
--- a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb
+++ b/spec/support/shared_examples/dirty_submit_form_shared_examples.rb
@@ -1,24 +1,36 @@
shared_examples 'dirty submit form' do |selector_args|
selectors = selector_args.is_a?(Array) ? selector_args : [selector_args]
+ def expect_disabled_state(form, submit, is_disabled = true)
+ disabled_selector = is_disabled == true ? '[disabled]' : ':not([disabled])'
+
+ form.find(".js-dirty-submit#{disabled_selector}", match: :first)
+
+ expect(submit.disabled?).to be is_disabled
+ end
+
selectors.each do |selector|
- it "disables #{selector[:form]} submit until there are changes", :js do
+ it "disables #{selector[:form]} submit until there are changes on #{selector[:input]}", :js do
form = find(selector[:form])
submit = form.first('.js-dirty-submit')
input = form.first(selector[:input])
+ is_radio = input[:type] == 'radio'
+ is_checkbox = input[:type] == 'checkbox'
+ is_checkable = is_radio || is_checkbox
original_value = input.value
+ original_checkable = form.find("input[name='#{input[:name]}'][checked]") if is_radio
+ original_checkable = input if is_checkbox
expect(submit.disabled?).to be true
+ expect(input.checked?).to be false
- input.set("#{original_value} changes")
+ is_checkable ? input.click : input.set("#{original_value} changes")
- form.find('.js-dirty-submit:not([disabled])', match: :first)
- expect(submit.disabled?).to be false
+ expect_disabled_state(form, submit, false)
- input.set(original_value)
+ is_checkable ? original_checkable.click : input.set(original_value)
- form.find('.js-dirty-submit[disabled]', match: :first)
- expect(submit.disabled?).to be true
+ expect_disabled_state(form, submit)
end
end
end