UNPKG

coffeescript-ui

Version:
278 lines (234 loc) 5.92 kB
### * coffeescript-ui - Coffeescript User Interface System (CUI) * Copyright (c) 2013 - 2016 Programmfabrik GmbH * MIT Licence * https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org ### class CUI.XHR extends CUI.Element getGroup: -> "Core" initOpts: -> super() @addOpts method: mandatory: true default: "GET" check: ["GET", "POST", "PUT", "DELETE", "OPTIONS"] url: mandatory: true check: String check: (v) -> v.trim().length > 0 user: check: String password: check: String responseType: mandatory: true default: "json" check: ["", "text", "json", "blob", "arraybuffer"] timeout: check: (v) -> v >= 0 form: check: "PlainObject" url_data: check: "PlainObject" body: {} json_data: {} # can be anything json_pretty: default: false check: (v) -> v == false or v == true or CUI.util.isString(v) headers: mandatory: true default: {} check: "PlainObject" withCredentials: mandatory: true default: false check: Boolean @ @readyStates: 0: "UNSENT" 1: "OPENED" 2: "HEADERS_RECEIVED" 3: "LOADING" 4: "DONE" @statusText: "-1": "abort" "-2": "timeout" "-3": "network_failure" readOpts: -> super() @__xhr = new XMLHttpRequest() @__xhr.withCredentials = @_withCredentials # console.debug "XHR.readOpts", @ @__readyStatesSeen = [@readyState()] @__registerEvents("download") @__registerEvents("upload") @__headers = {} for k, v of @_headers @__headers[k.toLowerCase()] = v if @_form if not @opts.method @_method = "POST" if @_url_data @__url = CUI.appendToUrl(@_url, @_url_data) else @__url = @_url set = 0 if @_form set = set + 1 if @_json_data set = set + 1 if @__headers['content-type'] == undefined @__headers['content-type'] = 'application/json; charset=utf-8' if @_body set = set + 1 CUI.util.assert(set <= 1, "new CUI.XHR", "opts.form, opts.json_data, opts.body are mutually exclusive.") @ # type: xhr / upload __registerEvents: (type) -> keys = [ "loadStart" "progress" "abort" "error" "load" "loadend" "timeout" ] if type == "upload" xhr = @__xhr.upload else keys.push("readyStateChange") xhr = @__xhr for k in keys fn = "__"+type+"_"+k if not @[fn] continue do (fn, k) => # console.debug "register", type, k, fn xhr.addEventListener k.toLowerCase(), (ev) => # console.debug ev.type, type # , ev @[fn](ev) @ __setStatus: (@__status) -> @__xhr.CUI_status = @__status @__xhr.CUI_statusText = @statusText() __download_abort: -> @__setStatus(-1) # console.warn("Aborted:", @__readyStatesSeen, @) __download_timeout: -> @__setStatus(-2) # console.warn("Timeout:", @__readyStatesSeen, @) __download_loadend: -> # console.info("Loadend:", @__readyStatesSeen, @__status, @status()) if @isSuccess() @__dfr.resolve(@response(), @status(), @statusText()) else if not @status() and not @__status # check ready states if we can determine a pseudo status @__setStatus(-3) console.debug("XHR.__download_loadend", @getXHR()) @__dfr.reject(@response(), @status(), @statusText()) @ __download_readyStateChange: -> CUI.util.pushOntoArray(@readyState(), @__readyStatesSeen) __progress: (ev, type) -> if @readyState() == "DONE" return loaded = ev.loaded total = ev.total if ev.lengthComputable percent = Math.floor(loaded / total * 100) else percent = -1 @__dfr.notify(type, loaded, total, percent) @ __upload_progress: (ev) -> @__progress(ev, "upload") __download_progress: (ev) -> @__progress(ev, "download") abort: -> @__xhr.abort() isSuccess: -> if @__url.startsWith("file:///") and @__readyStatesSeen.join(",") == "UNSENT,OPENED,HEADERS_RECEIVED,LOADING,DONE" true else @__xhr.status >= 200 and @__xhr.status < 300 or @__xhr.status == 304 status: -> if @__status < 0 @__status else @__xhr.status statusText: -> if @__status < 0 CUI.XHR.statusText[@__status+""] else @__xhr.statusText response: -> if @_responseType == "json" and @__xhr.responseType == "" # Internet Explorer needs some help here try res = JSON.parse(@__xhr.response) catch e res = @__xhr.response else res = @__xhr.response if @_responseType == "json" # be more compatible with jQuery @__xhr.responseJSON = res res start: -> @__xhr.open(@_method, @__url, true, @_user, @_password) for k, v of @__headers @__xhr.setRequestHeader(k, v) @__xhr.responseType = @_responseType @__xhr.timeout = @_timeout # console.debug "URL:", @__xhr.responseType, @__url, @_form, @_json_data if @_form data = new FormData() for k, v of @_form data.append(k, v) send_data = data # let the browser set the content-type else if @_json_data if @_json_pretty if @_json_pretty == true send_data = JSON.stringify(@_json_data, null, "\t") else send_data = JSON.stringify(@_json_data, null, @_json_pretty) else send_data = JSON.stringify(@_json_data) else if @_body send_data = @_body else send_data = undefined @__dfr = new CUI.Deferred() @__xhr.send(send_data) # console.debug @__xhr, @getAllResponseHeaders() @__dfr.promise() getXHR: -> @__xhr getAllResponseHeaders: -> headers = [] for header in @__xhr.getAllResponseHeaders().split("\r\n") if header.trim().length == 0 continue headers.push(header) headers getResponseHeaders: -> map = {} for header in @getAllResponseHeaders() match = header.match(/^(.*?): (.*)$/) key = match[1].toLowerCase() if not map[key] map[key] = [] map[key].push(match[2]) map getResponseHeader: (key) -> @getResponseHeaders()[key.toLowerCase()]?[0] readyState: -> CUI.XHR.readyStates[@__xhr.readyState]