mirror of https://github.com/rails/rails
Add rails-ujs to Action View
This commit is contained in:
parent
0cafbd4e9e
commit
ad3a47759e
|
@ -0,0 +1,2 @@
|
|||
/lib/assets/compiled
|
||||
/tmp
|
|
@ -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
|
||||
buttonClickSelector:
|
||||
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 e.target else e
|
||||
if matches(element, Rails.linkDisableSelector)
|
||||
enableLinkElement(element)
|
||||
else if matches(element, Rails.buttonDisableSelector) or matches(element, Rails.formEnableSelector)
|
||||
enableFormElement(element)
|
||||
else if matches(element, Rails.formSubmitSelector)
|
||||
enableFormElements(element)
|
||||
|
||||
# Unified function to disable an element (link, button and form)
|
||||
Rails.disableElement = (e) ->
|
||||
element = if e instanceof Event then e.target else e
|
||||
if matches(element, Rails.linkDisableSelector)
|
||||
disableLinkElement(element)
|
||||
else if matches(element, Rails.buttonDisableSelector) or matches(element, Rails.formDisableSelector)
|
||||
disableFormElement(element)
|
||||
else if matches(element, Rails.formSubmitSelector)
|
||||
disableFormElements(element)
|
||||
|
||||
# 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
|
||||
else
|
||||
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
|
||||
else
|
||||
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!
|
||||
# https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
|
||||
formContent += '<input type="submit" />'
|
||||
|
||||
form.method = 'post'
|
||||
form.action = href
|
||||
form.target = link.target
|
||||
form.innerHTML = formContent
|
||||
form.style.display = 'none'
|
||||
|
||||
document.body.appendChild(form)
|
||||
form.querySelector('[type="submit"]').click()
|
||||
|
||||
stopEverything(e)
|
|
@ -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.name, button.value) if button?
|
||||
else
|
||||
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'))
|
||||
else
|
||||
method = element.getAttribute('data-method')
|
||||
url = Rails.href(element)
|
||||
data = element.getAttribute('data-params')
|
||||
|
||||
ajax(
|
||||
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])
|
||||
else
|
||||
fire(element, 'ajax:stopped')
|
||||
xhr.abort()
|
||||
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'
|
||||
)
|
||||
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
|
||||
return unless form
|
||||
# Register the pressed submit button
|
||||
setData(form, 'ujs:submit-button', name: button.name, value: button.value) if button.name
|
||||
# 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
|
||||
# https://github.com/rails/rails-ujs
|
||||
#
|
||||
# Released under the MIT license
|
||||
#
|
||||
#= require ./config
|
||||
#= require_tree ./utils
|
||||
#= require_tree ./features
|
||||
|
||||
{
|
||||
fire, delegate
|
||||
getData, $
|
||||
refreshCSRFTokens, CSRFProtection
|
||||
enableElement, disableElement
|
||||
handleConfirm
|
||||
handleRemote, validateForm, formSubmitButtonClick, handleMetaClick
|
||||
handleMethod
|
||||
} = 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 https://github.com/rails/jquery-ujs/issues/357
|
||||
# See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching
|
||||
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')
|
||||
Rails.start()
|
|
@ -0,0 +1,95 @@
|
|||
#= require ./csrf
|
||||
#= require ./event
|
||||
|
||||
{ CSRFProtection, fire } = Rails
|
||||
|
||||
AcceptHeaders =
|
||||
'*': '*/*'
|
||||
text: 'text/plain'
|
||||
html: 'text/html'
|
||||
xml: 'application/xml, text/xml'
|
||||
json: 'application/json, text/javascript'
|
||||
script: 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript'
|
||||
|
||||
Rails.ajax = (options) ->
|
||||
options = prepareOptions(options)
|
||||
xhr = createXHR options, ->
|
||||
response = processResponse(xhr.response, xhr.getResponseHeader('Content-Type'))
|
||||
if xhr.status // 100 == 2
|
||||
options.success?(response, xhr.statusText, xhr)
|
||||
else
|
||||
options.error?(response, xhr.statusText, xhr)
|
||||
options.complete?(xhr, xhr.statusText)
|
||||
# Call beforeSend hook
|
||||
options.beforeSend?(xhr, options)
|
||||
# Send the request
|
||||
if xhr.readyState is XMLHttpRequest.OPENED
|
||||
xhr.send(options.data)
|
||||
else
|
||||
fire(document, 'ajaxStop') # to be compatible with jQuery.ajax
|
||||
|
||||
prepareOptions = (options) ->
|
||||
options.type = options.type.toUpperCase()
|
||||
# append data to url if it's a GET request
|
||||
if options.type is 'GET' and options.data
|
||||
if options.url.indexOf('?') < 0
|
||||
options.url += '?' + options.data
|
||||
else
|
||||
options.url += '&' + options.data
|
||||
# Use "*" as default dataType
|
||||
options.dataType = '*' unless AcceptHeaders[options.dataType]?
|
||||
options.accept = AcceptHeaders[options.dataType]
|
||||
options.accept += ', */*; q=0.01' if options.dataType isnt '*'
|
||||
options
|
||||
|
||||
createXHR = (options, done) ->
|
||||
xhr = new XMLHttpRequest()
|
||||
# Open and setup xhr
|
||||
xhr.open(options.type, options.url, true)
|
||||
xhr.setRequestHeader('Accept', options.accept)
|
||||
# Set Content-Type only when sending a string
|
||||
# Sending FormData will automatically set Content-Type to multipart/form-data
|
||||
if typeof options.data is 'string'
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
|
||||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest') unless options.crossDomain
|
||||
# Add X-CSRF-Token
|
||||
CSRFProtection(xhr)
|
||||
xhr.withCredentials = !!options.withCredentials
|
||||
xhr.onreadystatechange = ->
|
||||
done(xhr) if xhr.readyState is XMLHttpRequest.DONE
|
||||
xhr
|
||||
|
||||
processResponse = (response, type) ->
|
||||
if typeof response is 'string' and typeof type is 'string'
|
||||
if type.match(/\bjson\b/)
|
||||
try response = JSON.parse(response)
|
||||
else if type.match(/\bjavascript\b/)
|
||||
script = document.createElement('script')
|
||||
script.innerHTML = response
|
||||
document.body.appendChild(script)
|
||||
else if type.match(/\b(xml|html|svg)\b/)
|
||||
parser = new DOMParser()
|
||||
type = type.replace(/;.+/, '') # remove something like ';charset=utf-8'
|
||||
try response = parser.parseFromString(response, type)
|
||||
response
|
||||
|
||||
# Default way to get an element's href. May be overridden at Rails.href.
|
||||
Rails.href = (element) -> element.href
|
||||
|
||||
# Determines if the request is a cross domain request.
|
||||
Rails.isCrossDomain = (url) ->
|
||||
originAnchor = document.createElement('a')
|
||||
originAnchor.href = location.href
|
||||
urlAnchor = document.createElement('a')
|
||||
try
|
||||
urlAnchor.href = url
|
||||
# If URL protocol is false or is a string containing a single colon
|
||||
# *and* host are false, assume it is not a cross-domain request
|
||||
# (should only be the case for IE7 and IE compatibility mode).
|
||||
# Otherwise, evaluate protocol and host of the URL against the origin
|
||||
# protocol and host.
|
||||
!(((!urlAnchor.protocol || urlAnchor.protocol == ':') && !urlAnchor.host) ||
|
||||
(originAnchor.protocol + '//' + originAnchor.host == urlAnchor.protocol + '//' + urlAnchor.host))
|
||||
catch e
|
||||
# If there is an error parsing the URL, assume it is crossDomain.
|
||||
true
|
|
@ -0,0 +1,25 @@
|
|||
#= require ./dom
|
||||
|
||||
{ $ } = Rails
|
||||
|
||||
# Up-to-date Cross-Site Request Forgery token
|
||||
csrfToken = Rails.csrfToken = ->
|
||||
meta = document.querySelector('meta[name=csrf-token]')
|
||||
meta and meta.content
|
||||
|
||||
# URL param that must contain the CSRF token
|
||||
csrfParam = Rails.csrfParam = ->
|
||||
meta = document.querySelector('meta[name=csrf-param]')
|
||||
meta and meta.content
|
||||
|
||||
# Make sure that every Ajax request sends the CSRF token
|
||||
Rails.CSRFProtection = (xhr) ->
|
||||
token = csrfToken()
|
||||
xhr.setRequestHeader('X-CSRF-Token', token) if token?
|
||||
|
||||
# Make sure that all forms have actual up-to-date tokens (cached forms contain old ones)
|
||||
Rails.refreshCSRFTokens = ->
|
||||
token = csrfToken()
|
||||
param = csrfParam()
|
||||
if token? and param?
|
||||
$('form input[name="' + param + '"]').forEach (input) -> input.value = token
|
|
@ -0,0 +1,28 @@
|
|||
m = Element.prototype.matches or
|
||||
Element.prototype.matchesSelector or
|
||||
Element.prototype.mozMatchesSelector or
|
||||
Element.prototype.msMatchesSelector or
|
||||
Element.prototype.oMatchesSelector or
|
||||
Element.prototype.webkitMatchesSelector
|
||||
|
||||
Rails.matches = (element, selector) ->
|
||||
if selector.exclude?
|
||||
m.call(element, selector.selector) and not m.call(element, selector.exclude)
|
||||
else
|
||||
m.call(element, selector)
|
||||
|
||||
# get and set data on a given element using "expando properties"
|
||||
# See: https://developer.mozilla.org/en-US/docs/Glossary/Expando
|
||||
expando = '_ujsData'
|
||||
|
||||
Rails.getData = (element, key) ->
|
||||
element[expando]?[key]
|
||||
|
||||
Rails.setData = (element, key, value) ->
|
||||
element[expando] ?= {}
|
||||
element[expando][key] = value
|
||||
|
||||
# a wrapper for document.querySelectorAll
|
||||
# returns an Array
|
||||
Rails.$ = (selector) ->
|
||||
Array.prototype.slice.call(document.querySelectorAll(selector))
|
|
@ -0,0 +1,40 @@
|
|||
#= require ./dom
|
||||
|
||||
{ matches } = Rails
|
||||
|
||||
# Polyfill for CustomEvent in IE9+
|
||||
# https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
|
||||
CustomEvent = window.CustomEvent
|
||||
|
||||
if typeof CustomEvent is 'function'
|
||||
CustomEvent = (event, params) ->
|
||||
evt = document.createEvent('CustomEvent')
|
||||
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail)
|
||||
evt
|
||||
CustomEvent.prototype = window.Event.prototype
|
||||
|
||||
# Triggers an custom event on an element and returns false if the event result is false
|
||||
fire = Rails.fire = (obj, name, data) ->
|
||||
event = new CustomEvent(
|
||||
name,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
detail: data,
|
||||
)
|
||||
obj.dispatchEvent(event)
|
||||
!event.defaultPrevented
|
||||
|
||||
# Helper function, needed to provide consistent behavior in IE
|
||||
Rails.stopEverything = (e) ->
|
||||
fire(e.target, 'ujs:everythingStopped')
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
e.stopImmediatePropagation()
|
||||
|
||||
Rails.delegate = (element, selector, eventType, handler) ->
|
||||
element.addEventListener eventType, (e) ->
|
||||
target = e.target
|
||||
target = target.parentNode until not (target instanceof Element) or matches(target, selector)
|
||||
if target instanceof Element and handler.call(target, e) == false
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
|
@ -0,0 +1,61 @@
|
|||
#= require ./dom
|
||||
|
||||
{ matches } = Rails
|
||||
|
||||
toArray = (e) -> Array.prototype.slice.call(e)
|
||||
|
||||
Rails.serializeElement = (element, additionalParam) ->
|
||||
inputs = [element]
|
||||
inputs = toArray(element.elements) if matches(element, 'form')
|
||||
params = []
|
||||
|
||||
inputs.forEach (input) ->
|
||||
return unless input.name
|
||||
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
|
||||
params.push(name: input.name, value: input.value)
|
||||
|
||||
params.push(additionalParam) if additionalParam
|
||||
|
||||
params.map (param) ->
|
||||
if param.name?
|
||||
"#{encodeURIComponent(param.name)}=#{encodeURIComponent(param.value)}"
|
||||
else
|
||||
param
|
||||
.join('&')
|
||||
|
||||
# Helper function that returns form elements that match the specified CSS selector
|
||||
# If form is actually a "form" element this will return associated elements outside the from that have
|
||||
# the html form attribute set
|
||||
Rails.formElements = (form, selector) ->
|
||||
if matches(form, 'form')
|
||||
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
|
|
@ -0,0 +1,11 @@
|
|||
load_paths:
|
||||
- app/assets/javascripts
|
||||
|
||||
logical_paths:
|
||||
- rails-ujs.js
|
||||
|
||||
build:
|
||||
logical_paths:
|
||||
- rails-ujs.js
|
||||
path: lib/assets/compiled
|
||||
clean: true
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "rails-ujs",
|
||||
"version": "0.0.1",
|
||||
"description": "Ruby on Rails unobtrusive scripting adapter",
|
||||
"main": "lib/assets/compiled/rails-ujs.js",
|
||||
"files": [
|
||||
"lib/assets/compiled/*.js"
|
||||
],
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bundle exec blade build",
|
||||
"test": "echo \"See the README: https://github.com/rails/rails-ujs#how-to-run-tests\" && exit 1",
|
||||
"lint": "coffeelint src && eslint test/public/test",
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "rails/rails"
|
||||
},
|
||||
"contributors": [
|
||||
"Stephen St. Martin",
|
||||
"Steve Schwartz",
|
||||
"Dangyi Liu",
|
||||
"All contributors"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/rails/rails/issues"
|
||||
},
|
||||
"homepage": "http://rubyonrails.org/",
|
||||
"devDependencies": {
|
||||
"coffeelint": "^1.15.7",
|
||||
"eslint": "^2.13.1"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue