Browse files

Add rails-ujs to Action View

  • Loading branch information...
guilleiguaran committed Nov 25, 2016
1 parent 0cafbd4 commit ad3a47759e67a411f3534309cdd704f12f6930a7
@@ -0,0 +1,2 @@
@@ -0,0 +1,37 @@
#= export Rails
@Rails =
# Link elements bound by jquery-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
selector: 'button[data-remote]:not([form]), button[data-confirm]:not([form])'
exclude: 'form button'
# Select elements bound by jquery-ujs
inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]'
# Form elements bound by jquery-ujs
formSubmitSelector: 'form'
# Form input elements bound by jquery-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
formDisableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled'
# 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])'
# Link onClick disable selector with possible reenable after remote submission
linkDisableSelector: 'a[data-disable-with], a[data-disable]'
# Button onClick disable selector with possible reenable after remote submission
buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]'
@@ -0,0 +1,26 @@
#= require_tree ../utils
{ fire, stopEverything } = Rails
Rails.handleConfirm = (e) ->
stopEverything(e) unless allowAction(this)
# For 'data-confirm' attribute:
# - Fires `confirm` event
# - Shows the confirmation dialog
# - Fires the `confirm:complete` event
# Returns `true` if no function stops the chain and user chose yes `false` otherwise.
# Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
# Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
# return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
allowAction = (element) ->
message = element.getAttribute('data-confirm')
return true unless message
answer = false
if fire(element, 'confirm')
try answer = confirm(message)
callback = fire(element, 'confirm:complete', [answer])
answer and callback
@@ -0,0 +1,78 @@
#= require_tree ../utils
{ matches, getData, setData, stopEverything, formElements } = Rails
# Unified function to enable an element (link, button and form)
Rails.enableElement = (e) ->
element = if e instanceof Event then else e
if matches(element, Rails.linkDisableSelector)
else if matches(element, Rails.buttonDisableSelector) or matches(element, Rails.formEnableSelector)
else if matches(element, Rails.formSubmitSelector)
# Unified function to disable an element (link, button and form)
Rails.disableElement = (e) ->
element = if e instanceof Event then else e
if matches(element, Rails.linkDisableSelector)
else if matches(element, Rails.buttonDisableSelector) or matches(element, Rails.formDisableSelector)
else if matches(element, Rails.formSubmitSelector)
# Replace element's html with the 'data-disable-with' after storing original html
# and prevent clicking on it
disableLinkElement = (element) ->
replacement = element.getAttribute('data-disable-with')
if replacement?
setData(element, 'ujs:enable-with', element.innerHTML) # store enabled state
element.innerHTML = replacement
element.addEventListener('click', stopEverything) # prevent further clicking
setData(element, 'ujs:disabled', true)
# Restore element to its original state which was disabled by 'disableLinkElement' above
enableLinkElement = (element) ->
originalText = getData(element, 'ujs:enable-with')
if originalText?
element.innerHTML = originalText # set to old enabled state
setData(element, 'ujs:enable-with', null) # clean up cache
element.removeEventListener('click', stopEverything) # enable element
setData(element, 'ujs:disabled', null)
# Disables form elements:
# - Caches element value in 'ujs:enable-with' data store
# - Replaces element text with value of 'data-disable-with' attribute
# - Sets disabled property to true
disableFormElements = (form) ->
formElements(form, Rails.formDisableSelector).forEach(disableFormElement)
disableFormElement = (element) ->
replacement = element.getAttribute('data-disable-with')
if replacement?
if matches(element, 'button')
setData(element, 'ujs:enable-with', element.innerHTML)
element.innerHTML = replacement
setData(element, 'ujs:enable-with', element.value)
element.value = replacement
element.disabled = true
setData(element, 'ujs:disabled', true)
# Re-enables disabled form elements:
# - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
# - Sets disabled property to false
enableFormElements = (form) ->
formElements(form, Rails.formEnableSelector).forEach(enableFormElement)
enableFormElement = (element) ->
originalText = getData(element, 'ujs:enable-with')
if originalText?
if matches(element, 'button')
element.innerHTML = originalText
element.value = originalText
setData(element, 'ujs:enable-with', null) # clean up cache
element.disabled = false
setData(element, 'ujs:disabled', null)
@@ -0,0 +1,34 @@
#= require_tree ../utils
{ stopEverything } = Rails
# Handles "data-method" on links such as:
# <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
Rails.handleMethod = (e) ->
link = this
method = link.getAttribute('data-method')
return unless method
href = Rails.href(link)
csrfToken = Rails.csrfToken()
csrfParam = Rails.csrfParam()
form = document.createElement('form')
formContent = "<input name='_method' value='#{method}' type='hidden' />"
if csrfParam? and csrfToken? and not Rails.isCrossDomain(href)
formContent += "<input name='#{csrfParam}' value='#{csrfToken}' type='hidden' />"
# Must trigger submit by click on a button, else "submit" event handler won't work!
formContent += '<input type="submit" />'
form.method = 'post'
form.action = href =
form.innerHTML = formContent = 'none'
@@ -0,0 +1,100 @@
#= require_tree ../utils
matches, getData, setData
fire, stopEverything
ajax, isCrossDomain
blankInputs, serializeElement
} = Rails
# Checks "data-remote" if true to handle the request through a XHR request.
isRemote = (element) ->
value = element.getAttribute('data-remote')
value? and value isnt 'false'
# Submits "remote" forms and links with ajax
Rails.handleRemote = (e) ->
element = this
return true unless isRemote(element)
unless fire(element, 'ajax:before')
fire(element, 'ajax:stopped')
return false
withCredentials = element.getAttribute('data-with-credentials')
dataType = element.getAttribute('data-type') or 'script'
if matches(element, Rails.formSubmitSelector)
# memoized value from clicked submit button
button = getData(element, 'ujs:submit-button')
method = getData(element, 'ujs:submit-button-formmethod') or element.method
url = getData(element, 'ujs:submit-button-formaction') or element.getAttribute('action') or location.href
# strip query string if it's a GET request
url = url.replace(/\?.*$/, '') if method.toUpperCase() is 'GET'
if element.enctype is 'multipart/form-data'
data = new FormData(element)
data.append(, button.value) if button?
data = serializeElement(element, button)
setData(element, 'ujs:submit-button', null)
setData(element, 'ujs:submit-button-formmethod', null)
setData(element, 'ujs:submit-button-formaction', null)
else if matches(element, Rails.buttonClickSelector) or matches(element, Rails.inputChangeSelector)
method = element.getAttribute('data-method')
url = element.getAttribute('data-url')
data = serializeElement(element, element.getAttribute('data-params'))
method = element.getAttribute('data-method')
url = Rails.href(element)
data = element.getAttribute('data-params')
type: method or 'GET'
url: url
data: data
dataType: dataType
# stopping the "ajax:beforeSend" event will cancel the ajax request
beforeSend: (xhr, options) ->
if fire(element, 'ajax:beforeSend', [xhr, options])
fire(element, 'ajax:send', [xhr])
fire(element, 'ajax:stopped')
success: (args...) -> fire(element, 'ajax:success', args)
error: (args...) -> fire(element, 'ajax:error', args)
complete: (args...) -> fire(element, 'ajax:complete', args)
crossDomain: isCrossDomain(url)
withCredentials: withCredentials? and withCredentials isnt 'false'
# 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])
Rails.formSubmitButtonClick = (e) ->
button = this
form = button.form
return unless form
# Register the pressed submit button
setData(form, 'ujs:submit-button', name:, value: button.value) if
# Save attributes from button
setData(form, 'ujs:formnovalidate-button', button.formNoValidate)
setData(form, 'ujs:submit-button-formaction', button.getAttribute('formaction'))
setData(form, 'ujs:submit-button-formmethod', button.getAttribute('formmethod'))
Rails.handleMetaClick = (e) ->
link = this
method = (link.getAttribute('data-method') or 'GET').toUpperCase()
data = link.getAttribute('data-params')
metaClick = e.metaKey or e.ctrlKey
e.stopImmediatePropagation() if metaClick and method is 'GET' and not data
@@ -0,0 +1,76 @@
# Unobtrusive JavaScript
# Released under the MIT license
#= require ./config
#= require_tree ./utils
#= require_tree ./features
fire, delegate
getData, $
refreshCSRFTokens, CSRFProtection
enableElement, disableElement
handleRemote, validateForm, formSubmitButtonClick, handleMetaClick
} = Rails
# For backward compatibility
if jQuery? and not jQuery.rails
jQuery.rails = Rails
jQuery.ajaxPrefilter (options, originalOptions, xhr) ->
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
# This event works the same as the load event, except that it fires every
# time the page is loaded.
# See
# See
window.addEventListener 'pageshow', ->
$(Rails.formEnableSelector).forEach (el) ->
enableElement(el) if getData(el, 'ujs:disabled')
$(Rails.linkDisableSelector).forEach (el) ->
enableElement(el) if getData(el, 'ujs:disabled')
delegate document, Rails.linkDisableSelector, 'ajax:complete', enableElement
delegate document, Rails.linkDisableSelector, 'ajax:stopped', enableElement
delegate document, Rails.buttonDisableSelector, 'ajax:complete', enableElement
delegate document, Rails.buttonDisableSelector, 'ajax:stopped', enableElement
delegate document, Rails.linkClickSelector, 'click', handleConfirm
delegate document, Rails.linkClickSelector, 'click', handleMetaClick
delegate document, Rails.linkClickSelector, 'click', disableElement
delegate document, Rails.linkClickSelector, 'click', handleRemote
delegate document, Rails.linkClickSelector, 'click', handleMethod
delegate document, Rails.buttonClickSelector, 'click', handleConfirm
delegate document, Rails.buttonClickSelector, 'click', disableElement
delegate document, Rails.buttonClickSelector, 'click', handleRemote
delegate document, Rails.inputChangeSelector, 'change', handleConfirm
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
delegate document, Rails.formSubmitSelector, 'submit', (e) -> setTimeout((-> disableElement(e)), 13)
delegate document, Rails.formSubmitSelector, 'ajax:send', disableElement
delegate document, Rails.formSubmitSelector, 'ajax:complete', enableElement
delegate document, Rails.formInputClickSelector, 'click', handleConfirm
delegate document, Rails.formInputClickSelector, 'click', formSubmitButtonClick
document.addEventListener('DOMContentLoaded', refreshCSRFTokens)
window._rails_loaded = true
if window.Rails is Rails and fire(document, 'rails:attachBindings')
Oops, something went wrong.

0 comments on commit ad3a477

Please sign in to comment.