ajax.coffee 2.8 KB

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