aboutsummaryrefslogtreecommitdiffstats
path: root/actionview/app/assets/javascripts/rails-ujs/utils/ajax.coffee
blob: 019bda635ad87d117d6baa3efa2dec2faf947727 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#= require ./csp
#= require ./csrf
#= require ./event

{ cspNonce, 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.responseText, 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)

  if options.beforeSend? && !options.beforeSend(xhr, options)
    return false

  if xhr.readyState is XMLHttpRequest.OPENED
    xhr.send(options.data)

prepareOptions = (options) ->
  options.url = options.url or location.href
  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(/\b(?:java|ecma)script\b/)
      script = document.createElement('script')
      script.setAttribute('nonce', cspNonce())
      script.text = response
      document.head.appendChild(script).parentNode.removeChild(script)
    else if type.match(/\bxml\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