From 41c33bd4b2ec3f4a482e6030b6fda15091d81e4a Mon Sep 17 00:00:00 2001
From: Guillermo Iguaran <guilleiguaran@gmail.com>
Date: Mon, 20 Feb 2017 14:29:26 +0900
Subject: Import rails-ujs v0.1.0 from rails/rails-ujs

---
 actionview/app/assets/javascripts/config.coffee    |  13 +-
 .../app/assets/javascripts/features/remote.coffee  |  12 +-
 actionview/app/assets/javascripts/rails-ujs.coffee |   9 +-
 .../app/assets/javascripts/utils/event.coffee      |   2 +-
 .../app/assets/javascripts/utils/form.coffee       |  27 +--
 .../test/ujs/public/test/call-remote-callbacks.js  | 196 ---------------------
 actionview/test/ujs/public/test/data-remote.js     |  17 +-
 actionview/test/ujs/public/test/override.js        |   2 +-
 actionview/test/ujs/public/test/settings.js        |   8 +-
 .../test/ujs/views/layouts/application.html.erb    |   2 +-
 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' %>
 
-- 
cgit v1.2.3