import "../core/array"; import "../core/document"; import "../core/identity"; import "../core/rebind"; import "../event/dispatch"; d3.xhr = d3_xhrType(d3_identity); function d3_xhrType(response) { return function(url, mimeType, callback) { if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, mimeType = null; return d3_xhr(url, mimeType, response, callback); }; } function d3_xhr(url, mimeType, response, callback) { var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest, responseType = null; // If IE does not support CORS, use XDomainRequest. if (self.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest; "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { request.readyState > 3 && respond(); }; function respond() { var status = request.status, result; if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) { try { result = response.call(xhr, request); } catch (e) { dispatch.error.call(xhr, e); return; } dispatch.load.call(xhr, result); } else { dispatch.error.call(xhr, request); } } request.onprogress = function(event) { var o = d3.event; d3.event = event; try { dispatch.progress.call(xhr, request); } finally { d3.event = o; } }; xhr.header = function(name, value) { name = (name + "").toLowerCase(); if (arguments.length < 2) return headers[name]; if (value == null) delete headers[name]; else headers[name] = value + ""; return xhr; }; // If mimeType is non-null and no Accept header is set, a default is used. xhr.mimeType = function(value) { if (!arguments.length) return mimeType; mimeType = value == null ? null : value + ""; return xhr; }; // Specifies what type the response value should take; // for instance, arraybuffer, blob, document, or text. xhr.responseType = function(value) { if (!arguments.length) return responseType; responseType = value; return xhr; }; // Specify how to convert the response content to a specific type; // changes the callback value on "load" events. xhr.response = function(value) { response = value; return xhr; }; // Convenience methods. ["get", "post"].forEach(function(method) { xhr[method] = function() { return xhr.send.apply(xhr, [method].concat(d3_array(arguments))); }; }); // If callback is non-null, it will be used for error and load events. xhr.send = function(method, data, callback) { if (arguments.length === 2 && typeof data === "function") callback = data, data = null; request.open(method, url, true); if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); if (responseType != null) request.responseType = responseType; if (callback != null) xhr.on("error", callback).on("load", function(request) { callback(null, request); }); dispatch.beforesend.call(xhr, request); request.send(data == null ? null : data); return xhr; }; xhr.abort = function() { request.abort(); return xhr; }; d3.rebind(xhr, dispatch, "on"); return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); }; function d3_xhr_fixCallback(callback) { return callback.length === 1 ? function(error, request) { callback(error == null ? request : null); } : callback; } function d3_xhrHasResponse(request) { var type = request.responseType; return type && type !== "text" ? request.response // null on error : request.responseText; // "" on error }