MIME_TYPES = json: 'application/json' html: 'text/html' @ajax = (options) -> applyDefaults(options) serializeData(options) xhr = new XMLHttpRequest() xhr.open(options.type, options.url, options.async) applyCallbacks(xhr, options) applyHeaders(xhr, options) xhr.send(options.data) if options.async abort: abort.bind(undefined, xhr) else parseResponse(xhr, options) ajax.defaults = async: true dataType: 'json' timeout: 30 type: 'GET' # contentType # context # data # error # headers # progress # success # url applyDefaults = (options) -> for key of ajax.defaults options[key] ?= ajax.defaults[key] return serializeData = (options) -> return unless options.data if options.type is 'GET' options.url += '?' + serializeParams(options.data) options.data = null else options.data = serializeParams(options.data) return serializeParams = (params) -> ("#{encodeURIComponent key}=#{encodeURIComponent value}" for key, value of params).join '&' applyCallbacks = (xhr, options) -> return unless options.async xhr.timer = setTimeout onTimeout.bind(undefined, xhr, options), options.timeout * 1000 xhr.onprogress = options.progress if options.progress xhr.onreadystatechange = -> if xhr.readyState is 4 clearTimeout(xhr.timer) onComplete(xhr, options) return return applyHeaders = (xhr, options) -> options.headers or= {} if options.contentType options.headers['Content-Type'] = options.contentType if not options.headers['Content-Type'] and options.data and options.type isnt 'GET' options.headers['Content-Type'] = 'application/x-www-form-urlencoded' if options.dataType options.headers['Accept'] = MIME_TYPES[options.dataType] or options.dataType if isSameOrigin(options.url) options.headers['X-Requested-With'] = 'XMLHttpRequest' for key, value of options.headers xhr.setRequestHeader(key, value) return onComplete = (xhr, options) -> if 200 <= xhr.status < 300 if (response = parseResponse(xhr, options))? onSuccess response, xhr, options else onError 'invalid', xhr, options else onError 'error', xhr, options return onSuccess = (response, xhr, options) -> options.success?.call options.context, response, xhr, options return onError = (type, xhr, options) -> options.error?.call options.context, type, xhr, options return onTimeout = (xhr, options) -> xhr.abort() onError 'timeout', xhr, options return abort = (xhr) -> clearTimeout(xhr.timer) xhr.onreadystatechange = null xhr.abort() return isSameOrigin = (url) -> url.indexOf('http') isnt 0 or url.indexOf(location.origin) is 0 parseResponse = (xhr, options) -> if options.dataType is 'json' parseJSON(xhr.responseText) else xhr.responseText parseJSON = (json) -> try JSON.parse(json) catch