ajax.coffee 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. MIME_TYPES =
  2. json: 'application/json'
  3. html: 'text/html'
  4. @ajax = (options) ->
  5. applyDefaults(options)
  6. serializeData(options)
  7. xhr = new XMLHttpRequest()
  8. xhr.open(options.type, options.url, options.async)
  9. applyCallbacks(xhr, options)
  10. applyHeaders(xhr, options)
  11. xhr.send(options.data)
  12. if options.async
  13. abort: abort.bind(undefined, xhr)
  14. else
  15. parseResponse(xhr, options)
  16. ajax.defaults =
  17. async: true
  18. dataType: 'json'
  19. timeout: 30000
  20. type: 'GET'
  21. # contentType
  22. # context
  23. # data
  24. # error
  25. # headers
  26. # success
  27. # url
  28. applyDefaults = (options) ->
  29. for key of ajax.defaults
  30. options[key] ?= ajax.defaults[key]
  31. return
  32. serializeData = (options) ->
  33. return unless options.data
  34. if options.type is 'GET'
  35. options.url += '?' + serializeParams(options.data)
  36. options.data = null
  37. else
  38. options.data = serializeParams(options.data)
  39. return
  40. serializeParams = (params) ->
  41. ("#{encodeURIComponent key}=#{encodeURIComponent value}" for key, value of params).join '&'
  42. applyCallbacks = (xhr, options) ->
  43. return unless options.async
  44. xhr.timer = setTimeout onTimeout.bind(undefined, xhr, options), options.timeout
  45. xhr.onreadystatechange = ->
  46. if xhr.readyState is 4
  47. clearTimeout(xhr.timer)
  48. onComplete(xhr, options)
  49. return
  50. return
  51. applyHeaders = (xhr, options) ->
  52. options.headers or= {}
  53. if options.contentType
  54. options.headers['Content-Type'] = options.contentType
  55. if not options.headers['Content-Type'] and options.data and options.type isnt 'GET'
  56. options.headers['Content-Type'] = 'application/x-www-form-urlencoded'
  57. if options.dataType
  58. options.headers['Accept'] = MIME_TYPES[options.dataType] or options.dataType
  59. if isSameOrigin(options.url)
  60. options.headers['X-Requested-With'] = 'XMLHttpRequest'
  61. for key, value of options.headers
  62. xhr.setRequestHeader(key, value)
  63. return
  64. onComplete = (xhr, options) ->
  65. if 200 <= xhr.status < 300
  66. if (response = parseResponse(xhr, options))?
  67. onSuccess response, xhr, options
  68. else
  69. onError 'invalid', xhr, options
  70. else
  71. onError 'error', xhr, options
  72. return
  73. onSuccess = (response, xhr, options) ->
  74. options.success?.call options.context, response, xhr, options
  75. return
  76. onError = (type, xhr, options) ->
  77. options.error?.call options.context, type, xhr, options
  78. return
  79. onTimeout = (xhr, options) ->
  80. xhr.abort()
  81. onError 'timeout', xhr, options
  82. return
  83. abort = (xhr) ->
  84. clearTimeout(xhr.timer)
  85. xhr.onreadystatechange = null
  86. xhr.abort()
  87. return
  88. isSameOrigin = (url) ->
  89. url.indexOf('http') isnt 0 or url.indexOf(location.origin) is 0
  90. parseResponse = (xhr, options) ->
  91. if options.dataType is 'json'
  92. parseJSON(xhr.responseText)
  93. else
  94. xhr.responseText
  95. parseJSON = (json) ->
  96. try JSON.parse(json) catch