summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/behaviors/requires_input.js.coffee39
-rw-r--r--spec/javascripts/behaviors/requires_input_spec.js.coffee49
-rw-r--r--spec/javascripts/fixtures/behaviors/requires_input.html.haml18
3 files changed, 106 insertions, 0 deletions
diff --git a/app/assets/javascripts/behaviors/requires_input.js.coffee b/app/assets/javascripts/behaviors/requires_input.js.coffee
new file mode 100644
index 00000000000..8318fe435b3
--- /dev/null
+++ b/app/assets/javascripts/behaviors/requires_input.js.coffee
@@ -0,0 +1,39 @@
+# Requires Input behavior
+#
+# When called on a form with input fields with the `required` attribute, the
+# form's submit button will be disabled until all required fields have values.
+#
+#= require extensions/jquery
+#
+# ### Example Markup
+#
+# <form class="js-requires-input">
+# <input type="text" required="required">
+# <input type="submit" value="Submit">
+# </form>
+#
+$.fn.requiresInput = ->
+ $form = $(this)
+ $button = $('button[type=submit], input[type=submit]', $form)
+
+ required = '[required=required]'
+ fieldSelector = "input#{required}, select#{required}, textarea#{required}"
+
+ requireInput = ->
+ # Collect the input values of *all* required fields
+ values = _.map $(fieldSelector, $form), (field) -> field.value
+
+ # Disable the button if any required fields are empty
+ if values.length && _.any(values, _.isEmpty)
+ $button.disable()
+ else
+ $button.enable()
+
+ # Set initial button state
+ requireInput()
+
+ $form.on 'change input', fieldSelector, requireInput
+
+# Triggered on standard document `ready` and on Turbolinks `page:load` events
+$(document).on 'ready page:load', ->
+ $('form.js-requires-input').requiresInput()
diff --git a/spec/javascripts/behaviors/requires_input_spec.js.coffee b/spec/javascripts/behaviors/requires_input_spec.js.coffee
new file mode 100644
index 00000000000..61a17632173
--- /dev/null
+++ b/spec/javascripts/behaviors/requires_input_spec.js.coffee
@@ -0,0 +1,49 @@
+#= require behaviors/requires_input
+
+describe 'requiresInput', ->
+ fixture.preload('behaviors/requires_input.html')
+
+ beforeEach ->
+ fixture.load('behaviors/requires_input.html')
+
+ it 'disables submit when any field is required', ->
+ $('.js-requires-input').requiresInput()
+
+ expect($('.submit')).toBeDisabled()
+
+ it 'enables submit when no field is required', ->
+ $('*[required=required]').removeAttr('required')
+
+ $('.js-requires-input').requiresInput()
+
+ expect($('.submit')).not.toBeDisabled()
+
+ it 'enables submit when all required fields are pre-filled', ->
+ $('*[required=required]').remove()
+
+ $('.js-requires-input').requiresInput()
+
+ expect($('.submit')).not.toBeDisabled()
+
+ it 'enables submit when all required fields receive input', ->
+ $('.js-requires-input').requiresInput()
+
+ $('#required1').val('input1').change()
+ expect($('.submit')).toBeDisabled()
+
+ $('#optional1').val('input1').change()
+ expect($('.submit')).toBeDisabled()
+
+ $('#required2').val('input2').change()
+ $('#required3').val('input3').change()
+ $('#required4').val('input4').change()
+ $('#required5').val('1').change()
+
+ expect($('.submit')).not.toBeDisabled()
+
+ it 'is called on page:load event', ->
+ spy = spyOn($.fn, 'requiresInput')
+
+ $(document).trigger('page:load')
+
+ expect(spy).toHaveBeenCalled()
diff --git a/spec/javascripts/fixtures/behaviors/requires_input.html.haml b/spec/javascripts/fixtures/behaviors/requires_input.html.haml
new file mode 100644
index 00000000000..c3f905e912e
--- /dev/null
+++ b/spec/javascripts/fixtures/behaviors/requires_input.html.haml
@@ -0,0 +1,18 @@
+%form.js-requires-input
+ %input{type: 'text', id: 'required1', required: 'required'}
+ %input{type: 'text', id: 'required2', required: 'required'}
+ %input{type: 'text', id: 'required3', required: 'required', value: 'Pre-filled'}
+ %input{type: 'text', id: 'optional1'}
+
+ %textarea{id: 'required4', required: 'required'}
+ %textarea{id: 'optional2'}
+
+ %select{id: 'required5', required: 'required'}
+ %option Zero
+ %option{value: '1'} One
+ %select{id: 'optional3', required: 'required'}
+ %option Zero
+ %option{value: '1'} One
+
+ %button.submit{type: 'submit', value: 'Submit'}
+ %input.submit{type: 'submit', value: 'Submit'}