diff options
author | Guillermo Iguaran <guilleiguaran@gmail.com> | 2017-02-20 14:29:26 +0900 |
---|---|---|
committer | Guillermo Iguaran <guilleiguaran@gmail.com> | 2017-02-20 14:29:55 +0900 |
commit | 41c33bd4b2ec3f4a482e6030b6fda15091d81e4a (patch) | |
tree | 12a2884bf4e822b80484b4f3b5b2f2f44e840347 /actionview | |
parent | a2234c5f68edebe7f842873f0c0d7c53b439861c (diff) | |
download | rails-41c33bd4b2ec3f4a482e6030b6fda15091d81e4a.tar.gz rails-41c33bd4b2ec3f4a482e6030b6fda15091d81e4a.tar.bz2 rails-41c33bd4b2ec3f4a482e6030b6fda15091d81e4a.zip |
Import rails-ujs v0.1.0 from rails/rails-ujs
Diffstat (limited to 'actionview')
-rw-r--r-- | actionview/app/assets/javascripts/config.coffee | 13 | ||||
-rw-r--r-- | actionview/app/assets/javascripts/features/remote.coffee | 12 | ||||
-rw-r--r-- | actionview/app/assets/javascripts/rails-ujs.coffee | 9 | ||||
-rw-r--r-- | actionview/app/assets/javascripts/utils/event.coffee | 2 | ||||
-rw-r--r-- | actionview/app/assets/javascripts/utils/form.coffee | 27 | ||||
-rw-r--r-- | actionview/test/ujs/public/test/call-remote-callbacks.js | 196 | ||||
-rw-r--r-- | actionview/test/ujs/public/test/data-remote.js | 17 | ||||
-rw-r--r-- | actionview/test/ujs/public/test/override.js | 2 | ||||
-rw-r--r-- | actionview/test/ujs/public/test/settings.js | 8 | ||||
-rw-r--r-- | actionview/test/ujs/views/layouts/application.html.erb | 2 | ||||
-rw-r--r-- | actionview/test/ujs/views/tests/index.html.erb | 2 |
11 files changed, 35 insertions, 255 deletions
diff --git a/actionview/app/assets/javascripts/config.coffee b/actionview/app/assets/javascripts/config.coffee index 3d4706b0e1..a93325e903 100644 --- a/actionview/app/assets/javascripts/config.coffee +++ b/actionview/app/assets/javascripts/config.coffee @@ -1,21 +1,21 @@ #= export Rails @Rails = - # Link elements bound by jquery-ujs + # Link elements bound by rails-ujs linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]' - # Button elements bound by jquery-ujs + # Button elements bound by rails-ujs buttonClickSelector: selector: 'button[data-remote]:not([form]), button[data-confirm]:not([form])' exclude: 'form button' - # Select elements bound by jquery-ujs + # Select elements bound by rails-ujs inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]' - # Form elements bound by jquery-ujs + # Form elements bound by rails-ujs formSubmitSelector: 'form' - # Form input elements bound by jquery-ujs + # Form input elements bound by rails-ujs formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])' # Form input elements disabled during form submission @@ -24,9 +24,6 @@ # Form input elements re-enabled after form submission formEnableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled' - # Form required input elements - requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])' - # Form file input elements fileInputSelector: 'input[name][type=file]:not([disabled])' diff --git a/actionview/app/assets/javascripts/features/remote.coffee b/actionview/app/assets/javascripts/features/remote.coffee index 30a5dc21fa..852587042c 100644 --- a/actionview/app/assets/javascripts/features/remote.coffee +++ b/actionview/app/assets/javascripts/features/remote.coffee @@ -4,7 +4,7 @@ matches, getData, setData fire, stopEverything ajax, isCrossDomain - blankInputs, serializeElement + serializeElement } = Rails # Checks "data-remote" if true to handle the request through a XHR request. @@ -71,16 +71,6 @@ Rails.handleRemote = (e) -> ) stopEverything(e) -# Check whether any required fields are empty -# In both ajax mode and normal mode -Rails.validateForm = (e) -> - form = this - return if form.noValidate or getData(form, 'ujs:formnovalidate-button') - # Skip other logic when required values are missing or file upload is present - blankRequiredInputs = blankInputs(form, Rails.requiredInputSelector, false) - if blankRequiredInputs.length > 0 and fire(form, 'ajax:aborted:required', [blankRequiredInputs]) - stopEverything(e) - Rails.formSubmitButtonClick = (e) -> button = this form = button.form diff --git a/actionview/app/assets/javascripts/rails-ujs.coffee b/actionview/app/assets/javascripts/rails-ujs.coffee index f96d2eb6fd..df889ce067 100644 --- a/actionview/app/assets/javascripts/rails-ujs.coffee +++ b/actionview/app/assets/javascripts/rails-ujs.coffee @@ -14,7 +14,7 @@ refreshCSRFTokens, CSRFProtection enableElement, disableElement handleConfirm - handleRemote, validateForm, formSubmitButtonClick, handleMetaClick + handleRemote, formSubmitButtonClick, handleMetaClick handleMethod } = Rails @@ -25,9 +25,9 @@ if jQuery? and not jQuery.rails CSRFProtection(xhr) unless options.crossDomain Rails.start = -> - # Cut down on the number of issues from people inadvertently including jquery_ujs twice - # by detecting and raising an error when it happens. - throw new Error('jquery-ujs has already been loaded!') if window._rails_loaded + # Cut down on the number of issues from people inadvertently including + # rails-ujs twice by detecting and raising an error when it happens. + throw new Error('rails-ujs has already been loaded!') if window._rails_loaded # This event works the same as the load event, except that it fires every # time the page is loaded. @@ -58,7 +58,6 @@ Rails.start = -> delegate document, Rails.inputChangeSelector, 'change', handleRemote delegate document, Rails.formSubmitSelector, 'submit', handleConfirm - delegate document, Rails.formSubmitSelector, 'submit', validateForm delegate document, Rails.formSubmitSelector, 'submit', handleRemote # Normal mode submit # Slight timeout so that the submit button gets properly serialized diff --git a/actionview/app/assets/javascripts/utils/event.coffee b/actionview/app/assets/javascripts/utils/event.coffee index d25fe8e546..8d3ff007ea 100644 --- a/actionview/app/assets/javascripts/utils/event.coffee +++ b/actionview/app/assets/javascripts/utils/event.coffee @@ -6,7 +6,7 @@ # https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill CustomEvent = window.CustomEvent -if typeof CustomEvent is 'function' +if typeof CustomEvent isnt 'function' CustomEvent = (event, params) -> evt = document.createEvent('CustomEvent') evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail) diff --git a/actionview/app/assets/javascripts/utils/form.coffee b/actionview/app/assets/javascripts/utils/form.coffee index 251113deda..5fa337b518 100644 --- a/actionview/app/assets/javascripts/utils/form.coffee +++ b/actionview/app/assets/javascripts/utils/form.coffee @@ -14,7 +14,7 @@ Rails.serializeElement = (element, additionalParam) -> if matches(input, 'select') toArray(input.options).forEach (option) -> params.push(name: input.name, value: option.value) if option.selected - else if input.type isnt 'radio' and input.type isnt 'checkbox' or input.checked + else if input.checked or ['radio', 'checkbox', 'submit'].indexOf(input.type) == -1 params.push(name: input.name, value: input.value) params.push(additionalParam) if additionalParam @@ -34,28 +34,3 @@ Rails.formElements = (form, selector) -> toArray(form.elements).filter (el) -> matches(el, selector) else toArray(form.querySelectorAll(selector)) - -# Helper function which checks for blank inputs in a form that match the specified CSS selector -Rails.blankInputs = (form, selector, nonBlank) -> - foundInputs = [] - requiredInputs = toArray(form.querySelectorAll(selector or 'input, textarea')) - checkedRadioButtonNames = {} - - requiredInputs.forEach (input) -> - if input.type is 'radio' - # Don't count unchecked required radio as blank if other radio with same name is checked, - # regardless of whether same-name radio input has required attribute or not. The spec - # states https://www.w3.org/TR/html5/forms.html#the-required-attribute - radioName = input.name - # Skip if we've already seen the radio with this name. - unless checkedRadioButtonNames[radioName] - # If none checked - if form.querySelectorAll("input[type=radio][name='#{radioName}']:checked").length == 0 - radios = form.querySelectorAll("input[type=radio][name='#{radioName}']") - foundInputs = foundInputs.concat(toArray(radios)) - # We only need to check each name once. - checkedRadioButtonNames[radioName] = radioName - else - valueToCheck = if input.type is 'checkbox' then input.checked else !!input.value - foundInputs.push(input) if valueToCheck is nonBlank - foundInputs diff --git a/actionview/test/ujs/public/test/call-remote-callbacks.js b/actionview/test/ujs/public/test/call-remote-callbacks.js index 082d10bfbd..707e21541d 100644 --- a/actionview/test/ujs/public/test/call-remote-callbacks.js +++ b/actionview/test/ujs/public/test/call-remote-callbacks.js @@ -108,202 +108,6 @@ asyncTest('stopping the "ajax:beforeSend" event aborts the request', 1, function }) }) -asyncTest('blank required form input field should abort request and trigger "ajax:aborted:required" event', 5, function() { - $(document).bind('iframe:loading', function() { - ok(false, 'form should not get submitted') - }) - - var form = $('form[data-remote]') - .append($('<input type="text" name="user_name" required="required">')) - .append($('<textarea name="user_bio" required="required"></textarea>')) - .bindNative('ajax:beforeSend', function() { - ok(false, 'ajax:beforeSend should not run') - }) - .bindNative('ajax:aborted:required', function(e, data) { - data = $(data) - ok(data.length == 2, 'ajax:aborted:required event is passed all blank required inputs (jQuery objects)') - ok(data.first().is('input[name="user_name"]'), 'ajax:aborted:required adds blank required input to data') - ok(data.last().is('textarea[name="user_bio"]'), 'ajax:aborted:required adds blank required textarea to data') - ok(true, 'ajax:aborted:required should run') - }) - .triggerNative('submit') - - setTimeout(function() { - form.find('input[required],textarea[required]').val('Tyler') - form.unbind('ajax:beforeSend') - submit() - }, 13) -}) - -asyncTest('blank required form input for non-remote form should abort normal submission', 1, function() { - var form = $('form[data-remote]') - .append($('<input type="text" name="user_name" required="required">')) - .removeAttr('data-remote') - .bindNative('ujs:everythingStopped', function() { - ok(true, 'ujs:everythingStopped should run') - }) - .triggerNative('submit') - - setTimeout(function() { - start() - }, 13) -}) - -asyncTest('form should be submitted with blank required fields if handler is bound to "ajax:aborted:required" event that returns false', 1, function() { - var form = $('form[data-remote]') - .append($('<input type="text" name="user_name" required="required">')) - .bindNative('ajax:beforeSend', function() { - ok(true, 'ajax:beforeSend should run') - }) - .bindNative('ajax:aborted:required', function() { - return false - }) - .triggerNative('submit') - - setTimeout(function() { - start() - }, 13) -}) - -asyncTest('disabled fields should not be included in blank required check', 2, function() { - var form = $('form[data-remote]') - .append($('<input type="text" name="user_name" required="required" disabled="disabled">')) - .append($('<textarea name="user_bio" required="required" disabled="disabled"></textarea>')) - .bindNative('ajax:beforeSend', function() { - ok(true, 'ajax:beforeSend should run') - }) - .bindNative('ajax:aborted:required', function() { - ok(false, 'ajax:aborted:required should not run') - }) - - submit() -}) - -asyncTest('form should be submitted with blank required fields if it has the "novalidate" attribute', 2, function() { - var form = $('form[data-remote]') - .append($('<input type="text" name="user_name" required="required">')) - .attr('novalidate', 'novalidate') - .bindNative('ajax:beforeSend', function() { - ok(true, 'ajax:beforeSend should run') - }) - .bindNative('ajax:aborted:required', function() { - ok(false, 'ajax:aborted:required should not run') - }) - - submit() -}) - -asyncTest('form should be submitted with blank required fields if the button has the "formnovalidate" attribute', 2, function() { - var submit_button = $('<input type="submit" formnovalidate>') - var form = $('form[data-remote]') - .append($('<input type="text" name="user_name" required="required">')) - .append(submit_button) - .bindNative('ajax:beforeSend', function() { - ok(true, 'ajax:beforeSend should run') - }) - .bindNative('ajax:aborted:required', function() { - ok(false, 'ajax:aborted:required should not run') - }) - - submit_with_button(submit_button) -}) - -asyncTest('blank required form input for non-remote form with "novalidate" attribute should not abort normal submission', 1, function() { - $(document).bind('iframe:loading', function() { - ok(true, 'form should get submitted') - }) - - var form = $('form[data-remote]') - .append($('<input type="text" name="user_name" required="required">')) - .removeAttr('data-remote') - .attr('novalidate', 'novalidate') - .triggerNative('submit') - - setTimeout(function() { - start() - }, 13) -}) - -asyncTest('unchecked required checkbox should abort form submission', 1, function() { - var form = $('form[data-remote]') - .append($('<input type="checkbox" name="agree" required="required">')) - .removeAttr('data-remote') - .bindNative('ujs:everythingStopped', function() { - ok(true, 'ujs:everythingStopped should run') - }) - .triggerNative('submit') - - setTimeout(function() { - start() - }, 13) -}) - -asyncTest('unchecked required radio should abort form submission', 3, function() { - var form = $('form[data-remote]') - .append($('<input type="radio" name="yes_no_none" required="required" value=1>')) - .append($('<input type="radio" name="yes_no_none" required="required" value=2>')) - .removeAttr('data-remote') - .bindNative('ujs:everythingStopped', function() { - ok(true, 'ujs:everythingStopped should run') - }) - .bindNative('ajax:aborted:required', function(e, data) { - data = $(data) - equal(data.length, 2, 'blankRequiredInputs should include both radios') - ok(data.first().is('input[type=radio][value=1]'), 'blankRequiredInputs[0] should be the first radio') - }) - .triggerNative('submit') - - setTimeout(function() { - start() - }, 13) -}) - -asyncTest('required radio should only require one to be checked', 1, function() { - $(document).bind('iframe:loading', function() { - ok(true, 'form should get submitted') - }) - - var form = $('form[data-remote]') - .append($('<input type="radio" name="yes_no" required="required" value=1 id="checkme">')) - .append($('<input type="radio" name="yes_no" required="required" value=2>')) - .removeAttr('data-remote') - .bindNative('ujs:everythingStopped', function() { - ok(false, 'ujs:everythingStopped should not run') - }) - .find('#checkme').prop('checked', true) - .end() - .triggerNative('submit') - - setTimeout(function() { - start() - }, 13) -}) - -asyncTest('required radio should only require one to be checked if not all radios are required', 1, function() { - $(document).bind('iframe:loading', function() { - ok(true, 'form should get submitted') - }) - - var form = $('form[data-remote]') - // Check the radio that is not required - .append($('<input type="radio" name="yes_no_maybe" value=1 >')) - // Check the radio that is not required - .append($('<input type="radio" name="yes_no_maybe" value=2 id="checkme">')) - // Only one needs to be required - .append($('<input type="radio" name="yes_no_maybe" required="required" value=3>')) - .removeAttr('data-remote') - .bindNative('ujs:everythingStopped', function() { - ok(false, 'ujs:everythingStopped should not run') - }) - .find('#checkme').prop('checked', true) - .end() - .triggerNative('submit') - - setTimeout(function() { - start() - }, 13) -}) - function skipIt() { // This test cannot work due to the security feature in browsers which makes the value // attribute of file input fields readonly, so it cannot be set with default value. diff --git a/actionview/test/ujs/public/test/data-remote.js b/actionview/test/ujs/public/test/data-remote.js index a51aa10417..b756add24e 100644 --- a/actionview/test/ujs/public/test/data-remote.js +++ b/actionview/test/ujs/public/test/data-remote.js @@ -73,7 +73,6 @@ asyncTest('clicking on a link with data-remote attribute', 5, function() { .bindNative('ajax:success', function(e, data, status, xhr) { App.assertCallbackInvoked('ajax:success') App.assertRequestPath(data, '/echo') - console.log(data.params) equal(data.params.data1, 'value1', 'ajax arguments should have key data1 with right value') equal(data.params.data2, 'value2', 'ajax arguments should have key data2 with right value') App.assertGetRequest(data) @@ -398,3 +397,19 @@ asyncTest('form should be serialized correctly', 6, function() { }) .triggerNative('submit') }) + +asyncTest('form buttons should only be serialized when clicked', 4, function() { + $('form') + .append('<input type="submit" name="submit1" value="submit1" />') + .append('<button name="submit2" value="submit2" />') + .append('<button name="submit3" value="submit3" />') + .bindNative('ajax:success', function(e, data, status, xhr) { + equal(data.params.submit1, undefined) + equal(data.params.submit2, 'submit2') + equal(data.params.submit3, undefined) + equal(data['rack.request.form_vars'], 'user_name=john&submit2=submit2') + + start() + }) + .find('[name=submit2]').triggerNative('click') +}) diff --git a/actionview/test/ujs/public/test/override.js b/actionview/test/ujs/public/test/override.js index be6ec7749b..299c7018cc 100644 --- a/actionview/test/ujs/public/test/override.js +++ b/actionview/test/ujs/public/test/override.js @@ -46,7 +46,7 @@ asyncTest('the event selector strings are overridable', 1, function() { start() }) -asyncTest('including jquery-ujs multiple times throws error', 1, function() { +asyncTest('including rails-ujs multiple times throws error', 1, function() { throws(function() { Rails.start() }, 'appending rails.js again throws error') diff --git a/actionview/test/ujs/public/test/settings.js b/actionview/test/ujs/public/test/settings.js index c68ca24d6a..299c71bb00 100644 --- a/actionview/test/ujs/public/test/settings.js +++ b/actionview/test/ujs/public/test/settings.js @@ -63,12 +63,12 @@ $(document).bind('submit', function(e) { } }) -var MouseEvent = window.MouseEvent +var _MouseEvent = window.MouseEvent try { - new MouseEvent() + new _MouseEvent() } catch (e) { - MouseEvent = function(type, options) { + _MouseEvent = function(type, options) { var evt = document.createEvent('MouseEvents') evt.initMouseEvent(type, options.bubbles, options.cancelable, window, options.detail, 0, 0, 80, 20, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, null) return evt @@ -81,7 +81,7 @@ $.fn.extend({ var el = this[0], event, Evt = { - 'click': MouseEvent, + 'click': _MouseEvent, 'change': Event, 'pageshow': PageTransitionEvent, 'submit': Event diff --git a/actionview/test/ujs/views/layouts/application.html.erb b/actionview/test/ujs/views/layouts/application.html.erb index 74fa3bd06d..e09b213b72 100644 --- a/actionview/test/ujs/views/layouts/application.html.erb +++ b/actionview/test/ujs/views/layouts/application.html.erb @@ -21,7 +21,7 @@ <%= script_tag jquery_src %> <script> // This is for test in override.js. - // Must go after jQuery is loaded, but before jquery-ujs. + // Must go before rails-ujs. $(document).bind('rails:attachBindings', function() { $.rails.linkClickSelector += ', a[data-custom-remote-link]'; // Hijacks link click before ujs binds any handlers diff --git a/actionview/test/ujs/views/tests/index.html.erb b/actionview/test/ujs/views/tests/index.html.erb index 393a5ee235..2ac44eeb81 100644 --- a/actionview/test/ujs/views/tests/index.html.erb +++ b/actionview/test/ujs/views/tests/index.html.erb @@ -1,4 +1,4 @@ -<% @title = "jquery-ujs test" %> +<% @title = "rails-ujs test" %> <%= test_to 'data-confirm', 'data-remote', 'data-disable', 'data-disable-with', 'call-remote', 'call-remote-callbacks', 'data-method', 'override', 'csrf-refresh', 'csrf-token' %> |